Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/xml/os_dtd.c
+++ new/usr/src/lib/xml/os_dtd.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2015 Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * Utility functions for working with XML documents that are validated against
18 18 * Document Type Definitions (DTD) shipped in the operating system.
19 19 */
20 20
21 21 #include <stdlib.h>
22 22 #include <stdio.h>
23 23 #include <string.h>
24 24 #include <strings.h>
25 25 #include <errno.h>
26 26 #include <zone.h>
27 27
28 28 #include <libxml/parser.h>
29 29 #include <libxml/xmlmemory.h>
30 30
31 31 #include "os_dtd.h"
32 32
33 33 struct os_dtd_path {
34 34 os_dtd_id_t odp_id;
35 35 const char *odp_name;
36 36 const char *odp_public_ident;
37 37 const char *odp_path;
38 38 };
39 39
40 40 static os_dtd_path_t os_dtd_paths[] = {
41 41 /*
42 42 * DTDs for Zones infrastructure:
43 43 */
44 44 { OS_DTD_ZONES_BRAND, "brand",
45 45 "-//Sun Microsystems Inc//DTD Brands//EN",
46 46 "/usr/share/lib/xml/dtd/brand.dtd.1" },
47 47 { OS_DTD_ZONES_ZONE, "zone",
48 48 "-//Sun Microsystems Inc//DTD Zones//EN",
49 49 "/usr/share/lib/xml/dtd/zonecfg.dtd.1" },
50 50 { OS_DTD_ZONES_PLATFORM, "platform",
51 51 "-//Sun Microsystems Inc//Zones Platform//EN",
52 52 "/usr/share/lib/xml/dtd/zone_platform.dtd.1" },
53 53
54 54 /*
55 55 * DTDs for smf(5):
56 56 */
57 57 { OS_DTD_SMF_SERVICE_BUNDLE, "service_bundle",
58 58 NULL,
59 59 "/usr/share/lib/xml/dtd/service_bundle.dtd.1" },
60 60
61 61 { OS_DTD_UNKNOWN, NULL, NULL, NULL }
62 62 };
63 63
64 64 /*
65 65 * Check this document to see if it references the public identifier of a
66 66 * well-known DTD that we ship with the operating system. If there is no DTD,
67 67 * or the public identifier is unknown to us, return OS_DTD_UNKNOWN.
68 68 */
69 69 os_dtd_id_t
70 70 os_dtd_identify(xmlDocPtr doc)
71 71 {
72 72 xmlDtdPtr dp;
73 73 int i;
74 74
75 75 if ((dp = xmlGetIntSubset(doc)) == NULL) {
76 76 /*
77 77 * This document does not have an internal subset pointing
78 78 * to a DTD.
79 79 */
80 80 errno = EIO;
81 81 return (OS_DTD_UNKNOWN);
82 82 }
83 83
84 84 /*
85 85 * The use of a symbolic name via the public identifier is preferred.
86 86 * Check to see if the document refers to a public identifier for any
87 87 * well-known DTD:
88 88 */
89 89 for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
90 90 os_dtd_path_t *odp = &os_dtd_paths[i];
91 91 const xmlChar *pubid = (const xmlChar *)odp->odp_public_ident;
92 92
93 93 if (dp->ExternalID == NULL || odp->odp_public_ident == NULL) {
94 94 continue;
95 95 }
96 96
97 97 if (xmlStrEqual(pubid, dp->ExternalID)) {
98 98 return (odp->odp_id);
99 99 }
100 100 }
101 101
102 102 /*
103 103 * If a public identifier is not present, or does not match any known
104 104 * DTD, fall back to inspecting the system identifier.
105 105 */
106 106 for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
107 107 os_dtd_path_t *odp = &os_dtd_paths[i];
108 108 char uri[sizeof ("file://") + MAXPATHLEN];
109 109 const xmlChar *path = (const xmlChar *)odp->odp_path;
110 110
111 111 if (dp->SystemID == NULL || odp->odp_path == NULL) {
112 112 continue;
113 113 }
114 114
115 115 /*
116 116 * The system identifier may be a regular path.
117 117 */
118 118 if (xmlStrEqual(path, dp->SystemID)) {
119 119 return (odp->odp_id);
120 120 }
121 121
122 122 /*
123 123 * The system identifier may also be a "file://"
124 124 * URI referring to a path:
125 125 */
126 126 (void) snprintf(uri, sizeof (uri), "file://%s", odp->odp_path);
127 127 if (xmlStrEqual((const xmlChar *)uri, dp->SystemID)) {
128 128 return (odp->odp_id);
129 129 }
130 130 }
131 131
132 132 errno = ENOENT;
133 133 return (OS_DTD_UNKNOWN);
134 134 }
135 135
136 136 static os_dtd_path_t *
137 137 os_dtd_lookup(os_dtd_id_t id)
138 138 {
139 139 int i;
140 140
141 141 for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
142 142 os_dtd_path_t *odp = &os_dtd_paths[i];
143 143
144 144 if (odp->odp_id == id) {
145 145 return (odp);
146 146 }
147 147 }
148 148
149 149 errno = ENOENT;
150 150 return (NULL);
151 151 }
152 152
153 153 /*
154 154 * If this document references a DTD, remove that reference (the "internal
155 155 * subset"). Install a new internal subset reference to the well-known
156 156 * operating system DTD passed by the caller. The URI in this reference will
157 157 * respect the current native system prefix (e.g. "/native") if there is one,
158 158 * such as when running in a branded zone.
159 159 */
160 160 int
161 161 os_dtd_attach(xmlDocPtr doc, os_dtd_id_t id)
162 162 {
163 163 xmlDtdPtr dp;
164 164 os_dtd_path_t *odp;
165 165 const char *zroot = zone_get_nroot();
166 166 char uri[sizeof ("file://") + MAXPATHLEN];
167 167
168 168 if ((odp = os_dtd_lookup(id)) == NULL) {
169 169 return (-1);
170 170 }
171 171
172 172 if ((dp = xmlGetIntSubset(doc)) != NULL) {
173 173 /*
174 174 * This document already has an internal subset. Remove it
175 175 * before attaching the new one.
176 176 */
177 177 xmlUnlinkNode((xmlNodePtr)dp);
178 178 xmlFreeNode((xmlNodePtr)dp);
179 179 }
180 180
181 181 /*
182 182 * The "system identifier" of this internal subset must refer to the
183 183 * path in the filesystem where the DTD file (the external subset) is
184 184 * stored. If we are running in a branded zone, that file may be at a
185 185 * different path (e.g. under "/native").
186 186 */
187 187 (void) snprintf(uri, sizeof (uri), "file://%s%s", zroot != NULL ?
188 188 zroot : "", odp->odp_path);
189 189
190 190 if (xmlCreateIntSubset(doc, (const xmlChar *)odp->odp_name,
191 191 (const xmlChar *)odp->odp_public_ident,
192 192 (const xmlChar *)uri) == NULL) {
193 193 errno = EIO;
194 194 return (-1);
195 195 }
196 196
197 197 return (0);
198 198 }
199 199
200 200 /*ARGSUSED*/
201 201 static void
202 202 os_dtd_print_nothing(void *ctx, const char *msg, ...)
203 203 {
204 204 }
205 205
206 206 int
207 207 os_dtd_validate(xmlDocPtr doc, boolean_t emit_messages, boolean_t *valid)
208 208 {
209 209 int ret;
210 210 xmlValidCtxtPtr cvp;
211 211 os_dtd_id_t dtdid;
212 212
213 213 if ((dtdid = os_dtd_identify(doc)) != OS_DTD_UNKNOWN) {
214 214 /*
215 215 * This document refers to a well-known DTD shipped with
216 216 * the operating system. Ensure that it points to the
217 217 * correct local path for validation in the current context.
218 218 */
219 219 if (os_dtd_attach(doc, dtdid) != 0) {
220 220 return (-1);
221 221 }
222 222 }
223 223
224 224 if ((cvp = xmlNewValidCtxt()) == NULL) {
225 225 return (-1);
226 226 }
227 227
228 228 if (!emit_messages) {
229 229 cvp->error = os_dtd_print_nothing;
230 230 cvp->warning = os_dtd_print_nothing;
231 231 }
232 232
233 233 ret = xmlValidateDocument(cvp, doc);
234 234 xmlFreeValidCtxt(cvp);
235 235
236 236 *valid = (ret == 1 ? B_TRUE : B_FALSE);
237 237 return (0);
238 238 }
|
↓ open down ↓ |
238 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX