diff options
author | Joshua M. Clulow <jmc@joyent.com> | 2015-06-02 22:54:11 +0000 |
---|---|---|
committer | Joshua M. Clulow <jmc@joyent.com> | 2015-06-08 20:46:20 +0000 |
commit | 3780e6e7444648fd996068beb45fc98096c1a525 (patch) | |
tree | f4fab5a33c4261bfb92711f1fd3be6aa55fd9276 /usr/src | |
parent | 747826ee744212d4556f07404b550534e0c023f7 (diff) | |
download | illumos-joyent-3780e6e7444648fd996068beb45fc98096c1a525.tar.gz |
OS-4361 libzonecfg should be aware of branded zone native root
Reviewed by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libzonecfg/Makefile.com | 17 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/getzoneent.c | 59 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/libzonecfg.c | 126 | ||||
-rw-r--r-- | usr/src/lib/xml/os_dtd.c | 238 | ||||
-rw-r--r-- | usr/src/lib/xml/os_dtd.h | 49 |
5 files changed, 405 insertions, 84 deletions
diff --git a/usr/src/lib/libzonecfg/Makefile.com b/usr/src/lib/libzonecfg/Makefile.com index 0bee2fc908..6bec7141cb 100644 --- a/usr/src/lib/libzonecfg/Makefile.com +++ b/usr/src/lib/libzonecfg/Makefile.com @@ -20,11 +20,14 @@ # # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2015 Joyent, Inc. # LIBRARY= libzonecfg.a VERS= .1 -OBJECTS= libzonecfg.o getzoneent.o scratchops.o +LIB_OBJS= libzonecfg.o getzoneent.o scratchops.o +XML_OBJS= os_dtd.o +OBJECTS= $(LIB_OBJS) $(XML_OBJS) include ../../Makefile.lib @@ -35,15 +38,27 @@ LDLIBS += -lc -lsocket -lnsl -luuid -lnvpair -lsysevent -lsec -lbrand \ $(DYNLIB) := LDLIBS += -lxml2 SRCDIR = ../common + +XMLDIR = $(SRC)/lib/xml +SRCS = \ + $(LIB_OBJS:%.o=$(SRCDIR)/%.c) \ + $(XML_OBJS:%.o=$(XMLDIR)/%.c) \ + CPPFLAGS += -I$(ADJUNCT_PROTO)/usr/include/libxml2 -I$(SRCDIR) -D_REENTRANT CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-parentheses $(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC) +CPPFLAGS += -I$(XMLDIR) + .KEEP_STATE: all: $(LIBS) lint: lintcheck +pics/%.o: $(XMLDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + include ../../Makefile.targ diff --git a/usr/src/lib/libzonecfg/common/getzoneent.c b/usr/src/lib/libzonecfg/common/getzoneent.c index 76664fcc92..2113ecd44b 100644 --- a/usr/src/lib/libzonecfg/common/getzoneent.c +++ b/usr/src/lib/libzonecfg/common/getzoneent.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015 Joyent, Inc. */ @@ -170,10 +171,32 @@ getzoneent_private(FILE *cookie) } static boolean_t -get_index_path(char *path) +path_common(char *path, size_t path_size, const char *stem) { - return (snprintf(path, MAXPATHLEN, "%s%s", zonecfg_root, - ZONE_INDEX_FILE) < MAXPATHLEN); + const char *native_root = zone_get_nroot(); + + if (native_root == NULL || zonecfg_in_alt_root()) { + /* + * Do not prepend the native system root (e.g. "/native") if an + * alternative configuration root has been selected. + */ + native_root = ""; + } + + return (snprintf(path, path_size, "%s%s%s", native_root, zonecfg_root, + stem) < path_size); +} + +static boolean_t +get_index_path(char *path, size_t path_size) +{ + return (path_common(path, path_size, ZONE_INDEX_FILE)); +} + +static boolean_t +get_temp_path(char *path, size_t path_size) +{ + return (path_common(path, path_size, _PATH_TMPFILE)); } FILE * @@ -181,7 +204,7 @@ setzoneent(void) { char path[MAXPATHLEN]; - if (!get_index_path(path)) { + if (!get_index_path(path, sizeof (path))) { errno = EINVAL; return (NULL); } @@ -202,8 +225,7 @@ lock_index_file(void) struct flock lock; char path[MAXPATHLEN]; - if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, - ZONE_INDEX_LOCK_DIR) >= sizeof (path)) + if (!path_common(path, sizeof (path), ZONE_INDEX_LOCK_DIR)) return (-1); if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST) return (-1); @@ -269,13 +291,14 @@ int putzoneent(struct zoneent *ze, zoneent_op_t operation) { FILE *index_file, *tmp_file; - char *tmp_file_name, buf[MAX_INDEX_LEN]; + char buf[MAX_INDEX_LEN]; int tmp_file_desc, lock_fd, err; boolean_t exist, need_quotes; char *cp; + char tmp_path[MAXPATHLEN]; char path[MAXPATHLEN]; char uuidstr[UUID_PRINTABLE_STRING_LENGTH]; - size_t tlen, namelen; + size_t namelen; const char *zone_name, *zone_state, *zone_path, *zone_uuid; assert(ze != NULL); @@ -299,20 +322,14 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation) if ((lock_fd = lock_index_file()) == -1) return (Z_LOCKING_FILE); - /* using sizeof gives us room for the terminating NUL byte as well */ - tlen = sizeof (_PATH_TMPFILE) + strlen(zonecfg_root); - tmp_file_name = malloc(tlen); - if (tmp_file_name == NULL) { + if (!get_temp_path(tmp_path, sizeof (tmp_path))) { (void) unlock_index_file(lock_fd); return (Z_NOMEM); } - (void) snprintf(tmp_file_name, tlen, "%s%s", zonecfg_root, - _PATH_TMPFILE); - tmp_file_desc = mkstemp(tmp_file_name); + tmp_file_desc = mkstemp(tmp_path); if (tmp_file_desc == -1) { - (void) unlink(tmp_file_name); - free(tmp_file_name); + (void) unlink(tmp_path); (void) unlock_index_file(lock_fd); return (Z_TEMP_FILE); } @@ -323,7 +340,7 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation) err = Z_MISC_FS; goto error; } - if (!get_index_path(path)) { + if (!get_index_path(path, sizeof (path))) { err = Z_MISC_FS; goto error; } @@ -462,11 +479,10 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation) goto error; } tmp_file = NULL; - if (rename(tmp_file_name, path) == -1) { + if (rename(tmp_path, path) == -1) { err = errno == EACCES ? Z_ACCES : Z_MISC_FS; goto error; } - free(tmp_file_name); if (unlock_index_file(lock_fd) != Z_OK) return (Z_UNLOCKING_FILE); return (Z_OK); @@ -476,8 +492,7 @@ error: (void) fclose(index_file); if (tmp_file != NULL) (void) fclose(tmp_file); - (void) unlink(tmp_file_name); - free(tmp_file_name); + (void) unlink(tmp_path); (void) unlock_index_file(lock_fd); return (err); } diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c index 3162390931..6e368a164f 100644 --- a/usr/src/lib/libzonecfg/common/libzonecfg.c +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c @@ -22,7 +22,7 @@ /* * Copyright 2014 Gary Mills * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015, Joyent Inc. All rights reserved. + * Copyright 2015 Joyent Inc. */ #include <libsysevent.h> @@ -59,6 +59,8 @@ #include <secdb.h> #include <user_attr.h> #include <prof_attr.h> +#include <sys/debug.h> +#include <os_dtd.h> #include <arpa/inet.h> #include <netdb.h> @@ -279,17 +281,35 @@ zonecfg_in_alt_root(void) */ static boolean_t -config_file_path(const char *zonename, char *answer) +file_path_common(const char *zonename, const char *subdir, const char *stem, + char *answer, size_t answer_size) { - return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, - ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); + const char *native_root = zone_get_nroot(); + + if (native_root == NULL || zonecfg_in_alt_root()) { + /* + * Do not prepend the native system root (e.g. "/native") if an + * alternative configuration root has been selected. + */ + native_root = ""; + } + + return (snprintf(answer, answer_size, "%s%s%s/%s.%s", native_root, + zonecfg_root, subdir, zonename, stem) < answer_size); } static boolean_t -snap_file_path(const char *zonename, char *answer) +config_file_path(const char *zonename, char *answer, size_t answer_size) { - return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", - zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); + return (file_path_common(zonename, ZONE_CONFIG_ROOT, "xml", answer, + answer_size)); +} + +static boolean_t +snap_file_path(const char *zonename, char *answer, size_t answer_size) +{ + return (file_path_common(zonename, ZONE_SNAPSHOT_ROOT, "snapshot.xml", + answer, answer_size)); } /*ARGSUSED*/ @@ -360,7 +380,7 @@ zonecfg_destroy(const char *zonename, boolean_t force) int err, state_err; zone_state_t state; - if (!config_file_path(zonename, path)) + if (!config_file_path(zonename, path, sizeof (path))) return (Z_MISC_FS); state_err = zone_get_state((char *)zonename, &state); @@ -417,7 +437,7 @@ zonecfg_destroy_snapshot(const char *zonename) { char path[MAXPATHLEN]; - if (!snap_file_path(zonename, path)) + if (!snap_file_path(zonename, path, sizeof (path))) return (Z_MISC_FS); return (zonecfg_destroy_impl(path)); } @@ -584,9 +604,8 @@ static int zonecfg_get_handle_impl(const char *zonename, const char *filename, zone_dochandle_t handle) { - xmlValidCtxtPtr cvp; struct stat statbuf; - int valid; + boolean_t valid; if (zonename == NULL) return (Z_NO_ZONE); @@ -597,14 +616,13 @@ zonecfg_get_handle_impl(const char *zonename, const char *filename, return (Z_INVALID_DOCUMENT); return (Z_NO_ZONE); } - if ((cvp = xmlNewValidCtxt()) == NULL) + + if (os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid) != 0) { return (Z_NOMEM); - cvp->error = zonecfg_error_func; - cvp->warning = zonecfg_error_func; - valid = xmlValidateDocument(cvp, handle->zone_dh_doc); - xmlFreeValidCtxt(cvp); - if (valid == 0) + } + if (!valid) { return (Z_INVALID_DOCUMENT); + } /* delete any comments such as inherited Sun copyright / ident str */ stripcomments(handle); @@ -616,7 +634,7 @@ zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) { char path[MAXPATHLEN]; - if (!config_file_path(zonename, path)) + if (!config_file_path(zonename, path, sizeof (path))) return (Z_MISC_FS); handle->zone_dh_newzone = B_FALSE; @@ -660,7 +678,7 @@ zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) { char path[MAXPATHLEN]; - if (!snap_file_path(zonename, path)) + if (!snap_file_path(zonename, path, sizeof (path))) return (Z_MISC_FS); handle->zone_dh_newzone = B_FALSE; return (zonecfg_get_handle_impl(zonename, path, handle)); @@ -673,7 +691,7 @@ zonecfg_get_template_handle(const char *template, const char *zonename, char path[MAXPATHLEN]; int err; - if (!config_file_path(template, path)) + if (!config_file_path(template, path, sizeof (path))) return (Z_MISC_FS); if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) @@ -707,21 +725,19 @@ int zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, zone_dochandle_t rem_handle) { - xmlValidCtxtPtr cvp; - int valid; + boolean_t valid; /* load the manifest into the handle for the remote system */ if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { return (Z_INVALID_DOCUMENT); } - if ((cvp = xmlNewValidCtxt()) == NULL) + + if (os_dtd_validate(rem_handle->zone_dh_doc, B_FALSE, &valid) != 0) { return (Z_NOMEM); - cvp->error = zonecfg_error_func; - cvp->warning = zonecfg_error_func; - valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); - xmlFreeValidCtxt(cvp); - if (valid == 0) + } + if (!valid) { return (Z_INVALID_DOCUMENT); + } /* delete any comments such as inherited Sun copyright / ident str */ stripcomments(rem_handle); @@ -742,14 +758,12 @@ zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, * We need to re-run xmlValidateDocument on local_handle to properly * update the in-core representation of the configuration. */ - if ((cvp = xmlNewValidCtxt()) == NULL) + if (os_dtd_validate(local_handle->zone_dh_doc, B_FALSE, &valid) != 0) { return (Z_NOMEM); - cvp->error = zonecfg_error_func; - cvp->warning = zonecfg_error_func; - valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); - xmlFreeValidCtxt(cvp); - if (valid == 0) + } + if (!valid) { return (Z_INVALID_DOCUMENT); + } strip_sw_inv(local_handle); @@ -1203,9 +1217,9 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename) { char tmpfile[MAXPATHLEN]; char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; - int tmpfd, err, valid; - xmlValidCtxt cvp = { NULL }; + int tmpfd, err; boolean_t backup; + boolean_t valid; (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); (void) dirname(tmpfile); @@ -1218,16 +1232,13 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename) } (void) close(tmpfd); - cvp.error = zonecfg_error_func; - cvp.warning = zonecfg_error_func; - /* * We do a final validation of the document. Since the library has * malfunctioned if it fails to validate, we follow-up with an * assert() that the doc is valid. */ - valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); - assert(valid != 0); + VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid)); + VERIFY(valid == B_TRUE); if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) goto err; @@ -1324,7 +1335,7 @@ zonecfg_save(zone_dochandle_t handle) if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) return (err); - if (!config_file_path(zname, path)) + if (!config_file_path(zname, path, sizeof (path))) return (Z_MISC_FS); addcomment(handle, "\n DO NOT EDIT THIS " @@ -1345,8 +1356,10 @@ zonecfg_save(zone_dochandle_t handle) handle->zone_dh_newzone = B_FALSE; if (is_renaming(handle)) { - if (config_file_path(handle->zone_dh_delete_name, delpath)) + if (config_file_path(handle->zone_dh_delete_name, delpath, + sizeof (delpath))) { (void) unlink(delpath); + } handle->zone_dh_delete_name[0] = '\0'; } @@ -1356,23 +1369,18 @@ zonecfg_save(zone_dochandle_t handle) int zonecfg_verify_save(zone_dochandle_t handle, char *filename) { - int valid; - - xmlValidCtxt cvp = { NULL }; + boolean_t valid; if (zonecfg_check_handle(handle) != Z_OK) return (Z_BAD_HANDLE); - cvp.error = zonecfg_error_func; - cvp.warning = zonecfg_error_func; - /* * We do a final validation of the document. Since the library has * malfunctioned if it fails to validate, we follow-up with an * assert() that the doc is valid. */ - valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); - assert(valid != 0); + VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid)); + VERIFY(valid == B_TRUE); if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0) return (Z_SAVING_FILE); @@ -1386,9 +1394,8 @@ zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) char zname[ZONENAME_MAX]; char path[MAXPATHLEN]; char migpath[MAXPATHLEN]; - xmlValidCtxt cvp = { NULL }; int err = Z_SAVING_FILE; - int valid; + boolean_t valid; if (zonecfg_check_handle(handle) != Z_OK) return (Z_BAD_HANDLE); @@ -1415,16 +1422,13 @@ zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) addcomment(handle, "\n DO NOT EDIT THIS FILE. " "Use zonecfg(1M) and zoneadm(1M) attach.\n"); - cvp.error = zonecfg_error_func; - cvp.warning = zonecfg_error_func; - /* * We do a final validation of the document. Since the library has * malfunctioned if it fails to validate, we follow-up with an * assert() that the doc is valid. */ - valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); - assert(valid != 0); + VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid)); + VERIFY(valid == B_TRUE); if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) return (Z_SAVING_FILE); @@ -1497,7 +1501,7 @@ zonecfg_access(const char *zonename, int amode) { char path[MAXPATHLEN]; - if (!config_file_path(zonename, path)) + if (!config_file_path(zonename, path, sizeof (path))) return (Z_INVAL); if (access(path, amode) == 0) return (Z_OK); @@ -1562,7 +1566,7 @@ zonecfg_create_snapshot(const char *zonename) goto out; } - if (!snap_file_path(zonename, path)) { + if (!snap_file_path(zonename, path, sizeof (path))) { error = Z_MISC_FS; goto out; } @@ -8032,7 +8036,7 @@ zonecfg_update_userauths(zone_dochandle_t handle, char *zonename) (void) fclose(uaf); return (Z_MISC_FS); } - if (!config_file_path(zonename, config_file)) { + if (!config_file_path(zonename, config_file, sizeof (config_file))) { (void) fclose(uaf); return (Z_MISC_FS); } diff --git a/usr/src/lib/xml/os_dtd.c b/usr/src/lib/xml/os_dtd.c new file mode 100644 index 0000000000..579e99ba3c --- /dev/null +++ b/usr/src/lib/xml/os_dtd.c @@ -0,0 +1,238 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * Utility functions for working with XML documents that are validated against + * Document Type Definitions (DTD) shipped in the operating system. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <errno.h> +#include <zone.h> + +#include <libxml/parser.h> +#include <libxml/xmlmemory.h> + +#include "os_dtd.h" + +struct os_dtd_path { + os_dtd_id_t odp_id; + const char *odp_name; + const char *odp_public_ident; + const char *odp_path; +}; + +static os_dtd_path_t os_dtd_paths[] = { + /* + * DTDs for Zones infrastructure: + */ + { OS_DTD_ZONES_BRAND, "brand", + "-//Sun Microsystems Inc//DTD Brands//EN", + "/usr/share/lib/xml/dtd/brand.dtd.1" }, + { OS_DTD_ZONES_ZONE, "zone", + "-//Sun Microsystems Inc//DTD Zones//EN", + "/usr/share/lib/xml/dtd/zonecfg.dtd.1" }, + { OS_DTD_ZONES_PLATFORM, "platform", + "-//Sun Microsystems Inc//Zones Platform//EN", + "/usr/share/lib/xml/dtd/zone_platform.dtd.1" }, + + /* + * DTDs for smf(5): + */ + { OS_DTD_SMF_SERVICE_BUNDLE, "service_bundle", + NULL, + "/usr/share/lib/xml/dtd/service_bundle.dtd.1" }, + + { OS_DTD_UNKNOWN, NULL, NULL, NULL } +}; + +/* + * Check this document to see if it references the public identifier of a + * well-known DTD that we ship with the operating system. If there is no DTD, + * or the public identifier is unknown to us, return OS_DTD_UNKNOWN. + */ +os_dtd_id_t +os_dtd_identify(xmlDocPtr doc) +{ + xmlDtdPtr dp; + int i; + + if ((dp = xmlGetIntSubset(doc)) == NULL) { + /* + * This document does not have an internal subset pointing + * to a DTD. + */ + errno = EIO; + return (OS_DTD_UNKNOWN); + } + + /* + * The use of a symbolic name via the public identifier is preferred. + * Check to see if the document refers to a public identifier for any + * well-known DTD: + */ + for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) { + os_dtd_path_t *odp = &os_dtd_paths[i]; + const xmlChar *pubid = (const xmlChar *)odp->odp_public_ident; + + if (dp->ExternalID == NULL || odp->odp_public_ident == NULL) { + continue; + } + + if (xmlStrEqual(pubid, dp->ExternalID)) { + return (odp->odp_id); + } + } + + /* + * If a public identifier is not present, or does not match any known + * DTD, fall back to inspecting the system identifier. + */ + for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) { + os_dtd_path_t *odp = &os_dtd_paths[i]; + char uri[sizeof ("file://") + MAXPATHLEN]; + const xmlChar *path = (const xmlChar *)odp->odp_path; + + if (dp->SystemID == NULL || odp->odp_path == NULL) { + continue; + } + + /* + * The system identifier may be a regular path. + */ + if (xmlStrEqual(path, dp->SystemID)) { + return (odp->odp_id); + } + + /* + * The system identifier may also be a "file://" + * URI referring to a path: + */ + (void) snprintf(uri, sizeof (uri), "file://%s", odp->odp_path); + if (xmlStrEqual((const xmlChar *)uri, dp->SystemID)) { + return (odp->odp_id); + } + } + + errno = ENOENT; + return (OS_DTD_UNKNOWN); +} + +static os_dtd_path_t * +os_dtd_lookup(os_dtd_id_t id) +{ + int i; + + for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) { + os_dtd_path_t *odp = &os_dtd_paths[i]; + + if (odp->odp_id == id) { + return (odp); + } + } + + errno = ENOENT; + return (NULL); +} + +/* + * If this document references a DTD, remove that reference (the "internal + * subset"). Install a new internal subset reference to the well-known + * operating system DTD passed by the caller. The URI in this reference will + * respect the current native system prefix (e.g. "/native") if there is one, + * such as when running in a branded zone. + */ +int +os_dtd_attach(xmlDocPtr doc, os_dtd_id_t id) +{ + xmlDtdPtr dp; + os_dtd_path_t *odp; + const char *zroot = zone_get_nroot(); + char uri[sizeof ("file://") + MAXPATHLEN]; + + if ((odp = os_dtd_lookup(id)) == NULL) { + return (-1); + } + + if ((dp = xmlGetIntSubset(doc)) != NULL) { + /* + * This document already has an internal subset. Remove it + * before attaching the new one. + */ + xmlUnlinkNode((xmlNodePtr)dp); + xmlFreeNode((xmlNodePtr)dp); + } + + /* + * The "system identifier" of this internal subset must refer to the + * path in the filesystem where the DTD file (the external subset) is + * stored. If we are running in a branded zone, that file may be at a + * different path (e.g. under "/native"). + */ + (void) snprintf(uri, sizeof (uri), "file://%s%s", zroot != NULL ? + zroot : "", odp->odp_path); + + if (xmlCreateIntSubset(doc, (const xmlChar *)odp->odp_name, + (const xmlChar *)odp->odp_public_ident, + (const xmlChar *)uri) == NULL) { + errno = EIO; + return (-1); + } + + return (0); +} + +/*ARGSUSED*/ +static void +os_dtd_print_nothing(void *ctx, const char *msg, ...) +{ +} + +int +os_dtd_validate(xmlDocPtr doc, boolean_t emit_messages, boolean_t *valid) +{ + int ret; + xmlValidCtxtPtr cvp; + os_dtd_id_t dtdid; + + if ((dtdid = os_dtd_identify(doc)) != OS_DTD_UNKNOWN) { + /* + * This document refers to a well-known DTD shipped with + * the operating system. Ensure that it points to the + * correct local path for validation in the current context. + */ + if (os_dtd_attach(doc, dtdid) != 0) { + return (-1); + } + } + + if ((cvp = xmlNewValidCtxt()) == NULL) { + return (-1); + } + + if (!emit_messages) { + cvp->error = os_dtd_print_nothing; + cvp->warning = os_dtd_print_nothing; + } + + ret = xmlValidateDocument(cvp, doc); + xmlFreeValidCtxt(cvp); + + *valid = (ret == 1 ? B_TRUE : B_FALSE); + return (0); +} diff --git a/usr/src/lib/xml/os_dtd.h b/usr/src/lib/xml/os_dtd.h new file mode 100644 index 0000000000..c6fe24a293 --- /dev/null +++ b/usr/src/lib/xml/os_dtd.h @@ -0,0 +1,49 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +#ifndef _OS_DTD_H +#define _OS_DTD_H + +/* + * Utility functions for working with XML documents that are validated against + * Document Type Definitions (DTD) shipped in the operating system. + */ + +#include <libxml/parser.h> +#include <libxml/xmlmemory.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum os_dtd_id { + OS_DTD_UNKNOWN = 0, + OS_DTD_ZONES_BRAND, + OS_DTD_ZONES_ZONE, + OS_DTD_ZONES_PLATFORM, + OS_DTD_SMF_SERVICE_BUNDLE +} os_dtd_id_t; + +typedef struct os_dtd_path os_dtd_path_t; + +extern os_dtd_id_t os_dtd_identify(xmlDocPtr); +extern int os_dtd_attach(xmlDocPtr, os_dtd_id_t); +extern int os_dtd_validate(xmlDocPtr, boolean_t, boolean_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_DTD_H */ |