xref: /illumos-gate/usr/src/lib/libkmf/libkmf/common/policy.c (revision 5ad42b1b1469908fabc0099764182e9ecbc04dda)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 
35 #include <kmfapiP.h>
36 #include <libxml/tree.h>
37 #include <libxml/parser.h>
38 
39 typedef struct {
40 	char	*ekuname;
41 	KMF_OID	*oid;
42 } EKUName2OID;
43 
44 static EKUName2OID EKUList[] = {
45 	{"serverAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ServerAuth},
46 	{"clientAuth",		(KMF_OID *)&KMFOID_PKIX_KP_ClientAuth},
47 	{"codeSigning",		(KMF_OID *)&KMFOID_PKIX_KP_CodeSigning},
48 	{"emailProtection",	(KMF_OID *)&KMFOID_PKIX_KP_EmailProtection},
49 	{"ipsecEndSystem",	(KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem},
50 	{"ipsecTunnel",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel},
51 	{"ipsecUser",		(KMF_OID *)&KMFOID_PKIX_KP_IPSecUser},
52 	{"timeStamping",	(KMF_OID *)&KMFOID_PKIX_KP_TimeStamping},
53 	{"OCSPSigning", 	(KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning},
54 	{"KPClientAuth", 	(KMF_OID *)&KMFOID_PKINIT_ClientAuth},
55 	{"KPKdc", 		(KMF_OID *)&KMFOID_PKINIT_Kdc},
56 	{"scLogon", 		(KMF_OID *)&KMFOID_MS_KP_SCLogon}
57 };
58 
59 static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID);
60 
61 static void
62 addFormatting(xmlNodePtr parent, char *text)
63 {
64 	xmlNodePtr snode;
65 
66 	if (parent == NULL || text == NULL)
67 		return;
68 
69 	snode = xmlNewText((const xmlChar *)text);
70 	if (snode != NULL) {
71 		(void) xmlAddChild(parent, snode);
72 	}
73 }
74 
75 static void
76 parseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo)
77 {
78 	xmlNodePtr n;
79 	char *c;
80 	n = node->children;
81 	while (n != NULL) {
82 		if (!xmlStrcmp((const xmlChar *)n->name,
83 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) {
84 
85 			vinfo->ocsp_info.basic.responderURI =
86 			    (char *)xmlGetProp(n,
87 			    (const xmlChar *)KMF_OCSP_RESPONDER_ATTR);
88 
89 			vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n,
90 			    (const xmlChar *)KMF_OCSP_PROXY_ATTR);
91 
92 			c = (char *)xmlGetProp(n,
93 			    (const xmlChar *)KMF_OCSP_URI_ATTR);
94 			if (c != NULL && !strcasecmp(c, "true")) {
95 				vinfo->ocsp_info.basic.uri_from_cert = 1;
96 				xmlFree(c);
97 			}
98 
99 			vinfo->ocsp_info.basic.response_lifetime =
100 			    (char *)xmlGetProp(n,
101 			    (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR);
102 
103 			c = (char *)xmlGetProp(n,
104 			    (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR);
105 			if (c != NULL && !strcasecmp(c, "true")) {
106 				vinfo->ocsp_info.basic.ignore_response_sign = 1;
107 				xmlFree(c);
108 			}
109 
110 		} else if (!xmlStrcmp((const xmlChar *)n->name,
111 		    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) {
112 
113 			vinfo->ocsp_info.resp_cert.name =
114 			    (char *)xmlGetProp(n,
115 			    (const xmlChar *)KMF_CERT_NAME_ATTR);
116 			vinfo->ocsp_info.resp_cert.serial =
117 			    (char *)xmlGetProp(n,
118 			    (const xmlChar *)KMF_CERT_SERIAL_ATTR);
119 			vinfo->ocsp_info.has_resp_cert = 1;
120 		}
121 
122 		n = n->next;
123 	}
124 
125 }
126 
127 /*
128  * Parse the "validation-methods" section of the policy.
129  */
130 static void
131 parseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo,
132 	KMF_POLICY_RECORD *policy)
133 {
134 	xmlNodePtr n;
135 	char *c;
136 	n = node->children;
137 	while (n != NULL) {
138 		if (!xmlStrcmp((const xmlChar *)n->name,
139 		    (const xmlChar *)KMF_OCSP_ELEMENT)) {
140 
141 			parseOCSPValidation(n, &policy->validation_info);
142 			policy->revocation |= KMF_REVOCATION_METHOD_OCSP;
143 
144 
145 		} else if (!xmlStrcmp((const xmlChar *)n->name,
146 		    (const xmlChar *)KMF_CRL_ELEMENT)) {
147 
148 			vinfo->crl_info.basefilename = (char *)xmlGetProp(n,
149 			    (const xmlChar *)KMF_CRL_BASENAME_ATTR);
150 
151 			vinfo->crl_info.directory = (char *)xmlGetProp(n,
152 			    (const xmlChar *)KMF_CRL_DIRECTORY_ATTR);
153 
154 			c = (char *)xmlGetProp(n,
155 			    (const xmlChar *)KMF_CRL_GET_URI_ATTR);
156 			if (c != NULL && !strcasecmp(c, "true")) {
157 				vinfo->crl_info.get_crl_uri = 1;
158 			} else {
159 				vinfo->crl_info.get_crl_uri = 0;
160 			}
161 			xmlFree(c);
162 
163 			vinfo->crl_info.proxy = (char *)xmlGetProp(n,
164 			    (const xmlChar *)KMF_CRL_PROXY_ATTR);
165 
166 			c = (char *)xmlGetProp(n,
167 			    (const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR);
168 			if (c != NULL && !strcasecmp(c, "true")) {
169 				vinfo->crl_info.ignore_crl_sign = 1;
170 			} else {
171 				vinfo->crl_info.ignore_crl_sign = 0;
172 			}
173 			xmlFree(c);
174 
175 			c = (char *)xmlGetProp(n,
176 			    (const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR);
177 			if (c != NULL && !strcasecmp(c, "true")) {
178 				vinfo->crl_info.ignore_crl_date = 1;
179 			} else {
180 				vinfo->crl_info.ignore_crl_date = 0;
181 			}
182 			xmlFree(c);
183 
184 			policy->revocation |= KMF_REVOCATION_METHOD_CRL;
185 		}
186 
187 		n = n->next;
188 	}
189 }
190 
191 char *
192 kmf_ku_to_string(uint32_t bitfield)
193 {
194 	if (bitfield & KMF_digitalSignature)
195 		return ("digitalSignature");
196 
197 	if (bitfield & KMF_nonRepudiation)
198 		return ("nonRepudiation");
199 
200 	if (bitfield & KMF_keyEncipherment)
201 		return ("keyEncipherment");
202 
203 	if (bitfield & KMF_dataEncipherment)
204 		return ("dataEncipherment");
205 
206 	if (bitfield & KMF_keyAgreement)
207 		return ("keyAgreement");
208 
209 	if (bitfield & KMF_keyCertSign)
210 		return ("keyCertSign");
211 
212 	if (bitfield & KMF_cRLSign)
213 		return ("cRLSign");
214 
215 	if (bitfield & KMF_encipherOnly)
216 		return ("encipherOnly");
217 
218 	if (bitfield & KMF_decipherOnly)
219 		return ("decipherOnly");
220 
221 	return (NULL);
222 }
223 
224 uint32_t
225 kmf_string_to_ku(char *kustring)
226 {
227 	if (kustring == NULL || !strlen(kustring))
228 		return (0);
229 	if (strcasecmp(kustring, "digitalSignature") == 0)
230 		return (KMF_digitalSignature);
231 	if (strcasecmp(kustring, "nonRepudiation") == 0)
232 		return (KMF_nonRepudiation);
233 	if (strcasecmp(kustring, "keyEncipherment") == 0)
234 		return (KMF_keyEncipherment);
235 	if (strcasecmp(kustring, "dataEncipherment") == 0)
236 		return (KMF_dataEncipherment);
237 	if (strcasecmp(kustring, "keyAgreement") == 0)
238 		return (KMF_keyAgreement);
239 	if (strcasecmp(kustring, "keyCertSign") == 0)
240 		return (KMF_keyCertSign);
241 	if (strcasecmp(kustring, "cRLSign") == 0)
242 		return (KMF_cRLSign);
243 	if (strcasecmp(kustring, "encipherOnly") == 0)
244 		return (KMF_encipherOnly);
245 	if (strcasecmp(kustring, "decipherOnly") == 0)
246 		return (KMF_decipherOnly);
247 
248 	return (0);
249 }
250 
251 static void
252 parseKeyUsageSet(xmlNodePtr node, uint32_t *kubits)
253 {
254 	xmlNodePtr n;
255 	char *c;
256 
257 	n = node->children;
258 	while (n != NULL) {
259 		if (!xmlStrcmp((const xmlChar *)n->name,
260 		    (const xmlChar *)KMF_KEY_USAGE_ELEMENT)) {
261 			c = (char *)xmlGetProp(n,
262 			    (const xmlChar *)KMF_KEY_USAGE_USE_ATTR);
263 			if (c) {
264 				*kubits |= kmf_string_to_ku(c);
265 				xmlFree(c);
266 			}
267 		}
268 
269 		n = n->next;
270 	}
271 }
272 
273 static KMF_OID *
274 dup_oid(KMF_OID *oldoid)
275 {
276 	KMF_OID *oid;
277 
278 	oid = malloc(sizeof (KMF_OID));
279 	if (oid == NULL)
280 		return (NULL);
281 
282 	oid->Length = oldoid->Length;
283 	oid->Data = malloc(oid->Length);
284 	if (oid->Data == NULL) {
285 		free(oid);
286 		return (NULL);
287 	}
288 	(void) memcpy(oid->Data, oldoid->Data, oid->Length);
289 
290 	return (oid);
291 }
292 
293 KMF_OID *
294 kmf_ekuname_to_oid(char *ekuname)
295 {
296 	KMF_OID *oid;
297 	int i;
298 
299 	if (ekuname == NULL)
300 		return (NULL);
301 
302 	for (i = 0; i < num_ekus; i++) {
303 		if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) {
304 			oid = dup_oid(EKUList[i].oid);
305 			return (oid);
306 		}
307 	}
308 
309 	return (NULL);
310 }
311 
312 char *
313 kmf_oid_to_ekuname(KMF_OID *oid)
314 {
315 	int i;
316 	for (i = 0; i < num_ekus; i++) {
317 		if (oid->Length == EKUList[i].oid->Length &&
318 		    !memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) {
319 			return (EKUList[i].ekuname);
320 		}
321 	}
322 	return (NULL);
323 }
324 
325 static KMF_RETURN
326 parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus)
327 {
328 	xmlNodePtr n;
329 	char *c;
330 	KMF_RETURN ret = KMF_OK;
331 	boolean_t found = FALSE;
332 
333 	n = node->children;
334 	while (n != NULL && ret == KMF_OK) {
335 		KMF_OID newoid, *oidptr;
336 
337 		oidptr = NULL;
338 		newoid.Data = NULL;
339 		newoid.Length = 0;
340 
341 		if (!xmlStrcmp((const xmlChar *)n->name,
342 		    (const xmlChar *)KMF_EKU_NAME_ELEMENT)) {
343 			c = (char *)xmlGetProp(n,
344 			    (const xmlChar *)KMF_EKU_NAME_ATTR);
345 			if (c != NULL) {
346 				oidptr = kmf_ekuname_to_oid(c);
347 				xmlFree(c);
348 				found = TRUE;
349 				if (oidptr != NULL)
350 					newoid = *oidptr;
351 			}
352 		} else if (!xmlStrcmp((const xmlChar *)n->name,
353 		    (const xmlChar *)KMF_EKU_OID_ELEMENT)) {
354 			c = (char *)xmlGetProp(n,
355 			    (const xmlChar *)KMF_EKU_OID_ATTR);
356 			if (c != NULL) {
357 				(void) kmf_string_to_oid(c, &newoid);
358 				xmlFree(c);
359 				found = TRUE;
360 			}
361 		} else {
362 			n = n->next;
363 			if ((n == NULL) && (!found))
364 				ret = KMF_ERR_POLICY_DB_FORMAT;
365 			continue;
366 		}
367 
368 		if (newoid.Data != NULL) {
369 			ekus->eku_count++;
370 			ekus->ekulist = realloc(ekus->ekulist,
371 			    ekus->eku_count * sizeof (KMF_OID));
372 			if (ekus->ekulist != NULL) {
373 				ekus->ekulist[ekus->eku_count-1].Length =
374 				    newoid.Length;
375 				ekus->ekulist[ekus->eku_count-1].Data =
376 				    newoid.Data;
377 			} else {
378 				ret = KMF_ERR_MEMORY;
379 			}
380 		} else {
381 			ret = KMF_ERR_POLICY_DB_FORMAT;
382 		}
383 
384 		n = n->next;
385 	}
386 
387 	return (ret);
388 }
389 
390 int
391 parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy)
392 {
393 	int ret = 0;
394 	xmlNodePtr n = node->xmlChildrenNode;
395 	char *c;
396 
397 	if (node->type == XML_ELEMENT_NODE) {
398 		if (node->properties != NULL) {
399 			policy->name = (char *)xmlGetProp(node,
400 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
401 
402 			c = (char *)xmlGetProp(node,
403 			    (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR);
404 			if (c && !strcasecmp(c, "true")) {
405 				policy->ignore_date = 1;
406 				xmlFree((xmlChar *)c);
407 			}
408 
409 			c = (char *)xmlGetProp(node,
410 			    (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS);
411 			if (c && !strcasecmp(c, "true")) {
412 				policy->ignore_unknown_ekus = 1;
413 				xmlFree(c);
414 			}
415 
416 			c = (char *)xmlGetProp(node,
417 			    (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR);
418 			if (c && !strcasecmp(c, "true")) {
419 				policy->ignore_trust_anchor = 1;
420 				xmlFree(c);
421 			}
422 
423 			c = (char *)xmlGetProp(node,
424 			    (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME);
425 			if (c) {
426 				policy->validity_adjusttime = c;
427 			} else {
428 				policy->validity_adjusttime = NULL;
429 			}
430 
431 			policy->ta_name = (char *)xmlGetProp(node,
432 			    (const xmlChar *)KMF_POLICY_TA_NAME_ATTR);
433 
434 			policy->ta_serial = (char *)xmlGetProp(node,
435 			    (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR);
436 		}
437 
438 		n = node->children;
439 		while (n != NULL) {
440 			if (!xmlStrcmp((const xmlChar *)n->name,
441 			    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT))
442 				parseValidation(n, &policy->validation_info,
443 				    policy);
444 			else if (!xmlStrcmp((const xmlChar *)n->name,
445 			    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT))
446 				parseKeyUsageSet(n, &policy->ku_bits);
447 			else if (!xmlStrcmp((const xmlChar *)n->name,
448 			    (const xmlChar *)KMF_EKU_ELEMENT)) {
449 				ret = parseExtKeyUsage(n, &policy->eku_set);
450 				if (ret != KMF_OK)
451 					return (ret);
452 			}
453 
454 			n = n->next;
455 		}
456 	}
457 
458 	return (ret);
459 }
460 
461 static int
462 newprop(xmlNodePtr node, char *attrname, char *src)
463 {
464 	xmlAttrPtr newattr;
465 
466 	if (src != NULL && strlen(src)) {
467 		newattr = xmlNewProp(node, (const xmlChar *)attrname,
468 		    (xmlChar *)src);
469 		if (newattr == NULL) {
470 			xmlUnlinkNode(node);
471 			xmlFreeNode(node);
472 			return (-1);
473 		}
474 	}
475 	return (0);
476 }
477 
478 /*
479  * Add CRL policy information to the XML tree.
480  * Return non-zero on any failure, else 0 for success.
481  *
482  * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on.
483  */
484 static int
485 AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo)
486 {
487 	xmlNodePtr n;
488 
489 	addFormatting(node, "\t\t");
490 	n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL);
491 	if (n == NULL)
492 		return (-1);
493 
494 	if (crlinfo->basefilename &&
495 	    newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename))
496 		return (-1);
497 
498 	if (crlinfo->directory &&
499 	    newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory))
500 		return (-1);
501 
502 	if (crlinfo->get_crl_uri &&
503 	    newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) {
504 		return (-1);
505 	}
506 
507 	if (crlinfo->proxy &&
508 	    newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy))
509 		return (-1);
510 
511 	if (crlinfo->ignore_crl_sign &&
512 	    newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) {
513 		return (-1);
514 	}
515 
516 	if (crlinfo->ignore_crl_date &&
517 	    newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) {
518 		return (-1);
519 	}
520 
521 	addFormatting(node, "\n");
522 	return (0);
523 }
524 
525 /*
526  * Add OCSP information to the policy tree.
527  * Return non-zero on any failure, else 0 for success.
528  *
529  * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on.
530  */
531 static int
532 AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp)
533 {
534 	int ret = 0;
535 	xmlNodePtr n_ocsp, n_basic, n_resp;
536 	KMF_OCSP_BASIC_POLICY *basic;
537 	KMF_RESP_CERT_POLICY *resp_cert;
538 
539 	basic = &(ocsp->basic);
540 	resp_cert = &(ocsp->resp_cert);
541 
542 	if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) {
543 
544 		addFormatting(parent, "\t\t");
545 
546 		/* basic node */
547 		n_ocsp = xmlNewChild(parent, NULL,
548 		    (const xmlChar *)KMF_OCSP_ELEMENT, NULL);
549 		if (n_ocsp == NULL)
550 			return (-1);
551 		addFormatting(n_ocsp, "\n\t\t\t");
552 
553 		n_basic = xmlNewChild(n_ocsp, NULL,
554 		    (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL);
555 		if (n_basic == NULL)
556 			return (-1);
557 		if (basic->responderURI && newprop(n_basic,
558 		    KMF_OCSP_RESPONDER_ATTR, basic->responderURI))
559 			return (-1);
560 		if (basic->proxy &&
561 		    newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy))
562 			return (-1);
563 		if (basic->uri_from_cert &&
564 		    newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE"))
565 			return (-1);
566 		if (basic->response_lifetime &&
567 		    newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR,
568 		    basic->response_lifetime))
569 			return (-1);
570 		if (basic->ignore_response_sign &&
571 		    newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE"))
572 			return (-1);
573 
574 		addFormatting(n_ocsp, "\n\t\t\t");
575 
576 		/* responder cert node */
577 		if (ocsp->has_resp_cert) {
578 			n_resp = xmlNewChild(n_ocsp, NULL,
579 			    (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT,
580 			    NULL);
581 			if (n_resp == NULL)
582 				return (-1);
583 			if (newprop(n_resp, KMF_CERT_NAME_ATTR,
584 			    resp_cert->name))
585 				return (-1);
586 			if (newprop(n_resp, KMF_CERT_SERIAL_ATTR,
587 			    resp_cert->serial))
588 				return (-1);
589 		}
590 		addFormatting(n_ocsp, "\n\t\t");
591 	}
592 
593 	addFormatting(parent, "\n");
594 	return (ret);
595 }
596 
597 /*
598  * Add validation method information to the policy tree.
599  * Return non-zero on any failure, else 0 for success.
600  */
601 static int
602 AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy)
603 {
604 	xmlNodePtr mnode;
605 	int ret = 0;
606 
607 	addFormatting(parent, "\t");
608 	mnode = xmlNewChild(parent, NULL,
609 	    (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL);
610 	if (mnode == NULL)
611 		return (-1);
612 
613 	addFormatting(mnode, "\n");
614 
615 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
616 		ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info));
617 		if (ret != KMF_OK)
618 			goto end;
619 	}
620 
621 	if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
622 		ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info));
623 		if (ret != KMF_OK)
624 			goto end;
625 	}
626 
627 	addFormatting(mnode, "\t");
628 	addFormatting(parent, "\n");
629 
630 end:
631 	if (ret != 0) {
632 		xmlUnlinkNode(mnode);
633 		xmlFreeNode(mnode);
634 	}
635 	return (ret);
636 
637 }
638 
639 /*
640  * Add Key Usage information to the policy tree.
641  * Return non-zero on any failure, else 0 for success.
642  */
643 static KMF_RETURN
644 AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits)
645 {
646 	int ret = KMF_OK;
647 	int i;
648 
649 	xmlNodePtr kuset, kunode;
650 
651 	if (kubits == 0)
652 		return (0);
653 
654 	addFormatting(parent, "\n\t");
655 	kuset = xmlNewChild(parent, NULL,
656 	    (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL);
657 	if (kuset == NULL)
658 		return (KMF_ERR_POLICY_ENGINE);
659 
660 	for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) {
661 		char *s = kmf_ku_to_string((kubits & (1<<i)));
662 		if (s != NULL) {
663 			addFormatting(kuset, "\n\t\t");
664 
665 			kunode = xmlNewChild(kuset, NULL,
666 			    (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL);
667 			if (kunode == NULL)
668 				ret = KMF_ERR_POLICY_ENGINE;
669 
670 			else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s))
671 				ret = KMF_ERR_POLICY_ENGINE;
672 		}
673 	}
674 	addFormatting(kuset, "\n\t");
675 	addFormatting(parent, "\n");
676 
677 	if (ret != KMF_OK) {
678 		xmlUnlinkNode(kuset);
679 		xmlFreeNode(kuset);
680 	}
681 
682 	return (ret);
683 }
684 
685 /*
686  * Add Extended-Key-Usage information to the policy tree.
687  * Return non-zero on any failure, else 0 for success.
688  */
689 static KMF_RETURN
690 AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus)
691 {
692 	KMF_RETURN ret = KMF_OK;
693 	xmlNodePtr n, kunode;
694 	int i;
695 
696 	if (ekus != NULL && ekus->eku_count > 0) {
697 		addFormatting(parent, "\n\t");
698 		n = xmlNewChild(parent, NULL,
699 		    (const xmlChar *)KMF_EKU_ELEMENT, NULL);
700 		if (n == NULL)
701 			return (KMF_ERR_POLICY_ENGINE);
702 
703 		for (i = 0; i < ekus->eku_count; i++) {
704 			char *s = kmf_oid_to_string(&ekus->ekulist[i]);
705 			if (s != NULL) {
706 				addFormatting(n, "\n\t\t");
707 				kunode = xmlNewChild(n, NULL,
708 				    (const xmlChar *)KMF_EKU_OID_ELEMENT,
709 				    NULL);
710 				if (kunode == NULL)
711 					ret = KMF_ERR_POLICY_ENGINE;
712 
713 				else if (newprop(kunode, KMF_EKU_OID_ATTR, s))
714 					ret = KMF_ERR_POLICY_ENGINE;
715 				free(s);
716 			} else {
717 				ret = KMF_ERR_POLICY_ENGINE;
718 			}
719 		}
720 		addFormatting(n, "\n\t");
721 		addFormatting(parent, "\n");
722 	}
723 
724 	if (ret != KMF_OK) {
725 		xmlUnlinkNode(n);
726 		xmlFreeNode(n);
727 	}
728 	return (ret);
729 }
730 
731 void
732 kmf_free_eku_policy(KMF_EKU_POLICY *ekus)
733 {
734 	if (ekus->eku_count > 0) {
735 		int i;
736 		for (i = 0; i < ekus->eku_count; i++) {
737 			kmf_free_data(&ekus->ekulist[i]);
738 		}
739 		free(ekus->ekulist);
740 	}
741 }
742 
743 #define	FREE_POLICY_STR(s) if (s != NULL) free(s);
744 
745 void
746 kmf_free_policy_record(KMF_POLICY_RECORD *policy)
747 {
748 	if (policy == NULL)
749 		return;
750 
751 	FREE_POLICY_STR(policy->name)
752 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI)
753 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy)
754 	FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime)
755 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name)
756 	FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial)
757 	FREE_POLICY_STR(policy->validation_info.crl_info.basefilename)
758 	FREE_POLICY_STR(policy->validation_info.crl_info.directory)
759 	FREE_POLICY_STR(policy->validation_info.crl_info.proxy)
760 	FREE_POLICY_STR(policy->validity_adjusttime)
761 	FREE_POLICY_STR(policy->ta_name)
762 	FREE_POLICY_STR(policy->ta_serial)
763 
764 	kmf_free_eku_policy(&policy->eku_set);
765 
766 	(void) memset(policy, 0, sizeof (KMF_POLICY_RECORD));
767 }
768 
769 /*
770  * kmf_get_policy
771  *
772  * Find a policy record in the database.
773  */
774 KMF_RETURN
775 kmf_get_policy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc)
776 {
777 	KMF_RETURN ret = KMF_OK;
778 	xmlParserCtxtPtr ctxt;
779 	xmlDocPtr doc = NULL;
780 	xmlNodePtr cur, node;
781 	int found = 0;
782 
783 	if (filename == NULL || policy_name == NULL || plc == NULL)
784 		return (KMF_ERR_BAD_PARAMETER);
785 
786 	(void) memset(plc, 0, sizeof (KMF_POLICY_RECORD));
787 
788 	/* Create a parser context */
789 	ctxt = xmlNewParserCtxt();
790 	if (ctxt == NULL)
791 		return (KMF_ERR_POLICY_DB_FORMAT);
792 
793 	/* Read the policy DB and verify it against the schema. */
794 	doc = xmlCtxtReadFile(ctxt, filename, NULL,
795 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
796 	if (doc == NULL || ctxt->valid == 0) {
797 		ret = KMF_ERR_POLICY_DB_FORMAT;
798 		goto out;
799 	}
800 
801 	cur = xmlDocGetRootElement(doc);
802 	if (cur == NULL) {
803 		ret = KMF_ERR_POLICY_DB_FORMAT;
804 		goto out;
805 	}
806 
807 	node = cur->xmlChildrenNode;
808 	while (node != NULL && !found) {
809 		char *c;
810 		/*
811 		 * Search for the policy that matches the given name.
812 		 */
813 		if (!xmlStrcmp((const xmlChar *)node->name,
814 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
815 			/* Check the name attribute */
816 			c = (char *)xmlGetProp(node,
817 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
818 
819 			/* If a match, parse the rest of the data */
820 			if (c != NULL) {
821 				if (strcmp(c, policy_name) == 0) {
822 					ret = parsePolicyElement(node, plc);
823 					found = (ret == KMF_OK);
824 				}
825 				xmlFree(c);
826 			}
827 		}
828 		node = node->next;
829 	}
830 
831 	if (!found) {
832 		ret = KMF_ERR_POLICY_NOT_FOUND;
833 		goto out;
834 	}
835 
836 out:
837 	if (ctxt != NULL)
838 		xmlFreeParserCtxt(ctxt);
839 
840 	if (doc != NULL)
841 		xmlFreeDoc(doc);
842 
843 	return (ret);
844 }
845 
846 /*
847  * kmf_set_policy
848  *
849  * Set the policy record in the handle.  This searches
850  * the policy DB for the named policy.  If it is not found
851  * or an error occurred in processing, the existing policy
852  * is kept and an error code is returned.
853  */
854 KMF_RETURN
855 kmf_set_policy(KMF_HANDLE_T handle, char *policyfile, char *policyname)
856 {
857 	KMF_RETURN ret = KMF_OK;
858 	KMF_POLICY_RECORD *newpolicy = NULL;
859 
860 	CLEAR_ERROR(handle, ret);
861 	if (ret != KMF_OK)
862 		return (ret);
863 
864 	newpolicy = malloc(sizeof (KMF_POLICY_RECORD));
865 	if (newpolicy == NULL)
866 		return (KMF_ERR_MEMORY);
867 	(void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD));
868 
869 	ret = kmf_get_policy(
870 	    policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile,
871 	    policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname,
872 	    newpolicy);
873 	if (ret != KMF_OK)
874 		goto out;
875 
876 	ret = kmf_verify_policy(newpolicy);
877 	if (ret != KMF_OK)
878 		goto out;
879 
880 	/* release the existing policy data (if any). */
881 	if (handle->policy != NULL) {
882 		kmf_free_policy_record(handle->policy);
883 		free(handle->policy);
884 	}
885 
886 	handle->policy = newpolicy;
887 
888 out:
889 	/* Cleanup any data allocated before the error occurred */
890 	if (ret != KMF_OK) {
891 		kmf_free_policy_record(newpolicy);
892 		free(newpolicy);
893 	}
894 
895 	return (ret);
896 }
897 
898 
899 static KMF_RETURN
900 deletePolicyNode(xmlNodePtr node, char *policy_name)
901 {
902 	KMF_RETURN ret = KMF_OK;
903 	int found = 0;
904 	xmlNodePtr dnode = NULL;
905 
906 	while (node != NULL && !found) {
907 		char *c;
908 		/*
909 		 * Search for the policy that matches the given name.
910 		 */
911 		if (!xmlStrcmp((const xmlChar *)node->name,
912 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
913 			/* Check the name attribute */
914 			c = (char *)xmlGetProp(node,
915 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
916 
917 			/* If a match, parse the rest of the data */
918 			if (c != NULL) {
919 				if (strcmp(c, policy_name) == 0) {
920 					found = 1;
921 					dnode = node;
922 				}
923 				xmlFree(c);
924 			}
925 		}
926 		if (!found)
927 			node = node->next;
928 	}
929 
930 	if (found && dnode != NULL) {
931 		/* Unlink the node */
932 		xmlUnlinkNode(dnode);
933 
934 		/* Delete it from the document tree */
935 		xmlFreeNode(dnode);
936 	} else {
937 		ret = KMF_ERR_POLICY_NOT_FOUND;
938 	}
939 
940 	return (ret);
941 }
942 
943 /*
944  * update_policyfile
945  *
946  * Attempt to do a "safe" file update as follows:
947  *  1. Lock the original file.
948  *  2. Create and write to a temporary file
949  *  3. Replace the original file with the temporary file.
950  */
951 static KMF_RETURN
952 update_policyfile(xmlDocPtr doc, char *filename)
953 {
954 	KMF_RETURN ret = KMF_OK;
955 	FILE *pfile, *tmpfile;
956 	char tmpfilename[MAXPATHLEN];
957 	char *p;
958 	int prefix_len, tmpfd;
959 	mode_t old_mode;
960 
961 	/*
962 	 * Open and lock the DB file. First try to open an existing file,
963 	 * if that fails, open it as if it were new.
964 	 */
965 	if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT)
966 		pfile = fopen(filename, "w+");
967 
968 	if (pfile == NULL)
969 		return (KMF_ERR_POLICY_DB_FILE);
970 
971 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
972 		(void) fclose(pfile);
973 		return (KMF_ERR_POLICY_DB_FILE);
974 	}
975 
976 	/*
977 	 * Create a temporary file to hold the new data.
978 	 */
979 	(void) memset(tmpfilename, 0, sizeof (tmpfilename));
980 	p = (char *)strrchr(filename, '/');
981 	if (p == NULL) {
982 		/*
983 		 * filename contains basename only so we
984 		 * create a temp file in current directory.
985 		 */
986 		if (strlcpy(tmpfilename, TMPFILE_TEMPLATE,
987 		    sizeof (tmpfilename)) >= sizeof (tmpfilename))
988 			return (KMF_ERR_INTERNAL);
989 	} else {
990 		/*
991 		 * create a temp file in the same directory
992 		 * as the policy file.
993 		 */
994 		prefix_len = p - filename;
995 		(void) strncpy(tmpfilename, filename, prefix_len);
996 		(void) strncat(tmpfilename, "/", 1);
997 		(void) strncat(tmpfilename, TMPFILE_TEMPLATE,
998 		    sizeof (TMPFILE_TEMPLATE));
999 	}
1000 
1001 	old_mode = umask(077);
1002 	tmpfd = mkstemp(tmpfilename);
1003 	(void) umask(old_mode);
1004 	if (tmpfd == -1) {
1005 		return (KMF_ERR_POLICY_DB_FILE);
1006 	}
1007 
1008 	if ((tmpfile = fdopen(tmpfd, "w")) == NULL) {
1009 		(void) close(tmpfd);
1010 		(void) unlink(tmpfilename);
1011 		(void) fclose(pfile);
1012 		return (KMF_ERR_POLICY_DB_FILE);
1013 	}
1014 
1015 	/*
1016 	 * Write the new info to the temporary file.
1017 	 */
1018 	if (xmlDocFormatDump(tmpfile, doc, 1) == -1) {
1019 		(void) fclose(pfile);
1020 		(void) fclose(tmpfile);
1021 		(void) unlink(tmpfilename);
1022 		return (KMF_ERR_POLICY_ENGINE);
1023 	}
1024 
1025 	(void) fclose(pfile);
1026 
1027 	if (fchmod(tmpfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1028 		(void) close(tmpfd);
1029 		(void) unlink(tmpfilename);
1030 		return (KMF_ERR_POLICY_DB_FILE);
1031 	}
1032 	if (fclose(tmpfile) != 0)
1033 		return (KMF_ERR_POLICY_DB_FILE);
1034 
1035 	/*
1036 	 * Replace the original file with the updated tempfile.
1037 	 */
1038 	if (rename(tmpfilename, filename) == -1) {
1039 		ret = KMF_ERR_POLICY_DB_FILE;
1040 	}
1041 
1042 	if (ret != KMF_OK) {
1043 		/* try to remove the tmp file */
1044 		(void) unlink(tmpfilename);
1045 	}
1046 
1047 	return (ret);
1048 }
1049 
1050 /*
1051  * kmf_delete_policy_from_db
1052  *
1053  * Find a policy by name and remove it from the policy DB file.
1054  * If the policy is not found, return an error.
1055  */
1056 KMF_RETURN
1057 kmf_delete_policy_from_db(char *policy_name, char *dbfilename)
1058 {
1059 	KMF_RETURN ret;
1060 	xmlParserCtxtPtr ctxt = NULL;
1061 	xmlDocPtr doc = NULL;
1062 	xmlNodePtr cur, node;
1063 
1064 	if (policy_name == NULL || dbfilename == NULL)
1065 		return (KMF_ERR_BAD_PARAMETER);
1066 
1067 	/*
1068 	 * Cannot delete the default policy record from the system
1069 	 * default policy database (/etc/security/kmfpolicy.xml).
1070 	 */
1071 	if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 &&
1072 	    strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0)
1073 		return (KMF_ERR_BAD_PARAMETER);
1074 
1075 	/* Make sure the policy file exists */
1076 	if (access(dbfilename, R_OK | W_OK))
1077 		return (KMF_ERR_BAD_PARAMETER);
1078 
1079 	/* Read the policy DB and verify it against the schema. */
1080 	ctxt = xmlNewParserCtxt();
1081 	if (ctxt == NULL)
1082 		return (KMF_ERR_POLICY_DB_FORMAT);
1083 
1084 	doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1085 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1086 	if (doc == NULL || ctxt->valid == 0) {
1087 		ret = KMF_ERR_POLICY_DB_FORMAT;
1088 		goto end;
1089 	}
1090 
1091 	cur = xmlDocGetRootElement(doc);
1092 	if (cur == NULL) {
1093 		xmlFreeDoc(doc);
1094 		return (KMF_ERR_POLICY_DB_FORMAT);
1095 	}
1096 	node = cur->xmlChildrenNode;
1097 
1098 	ret = deletePolicyNode(node, policy_name);
1099 
1100 	if (ret == KMF_OK)
1101 		ret = update_policyfile(doc, dbfilename);
1102 
1103 end:
1104 	if (ctxt != NULL)
1105 		xmlFreeParserCtxt(ctxt);
1106 
1107 	if (doc != NULL)
1108 		xmlFreeDoc(doc);
1109 
1110 	return (ret);
1111 }
1112 
1113 /*
1114  * Add a new policy node to the Policy DB XML tree.
1115  */
1116 static KMF_RETURN
1117 addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy)
1118 {
1119 	KMF_RETURN ret = KMF_OK;
1120 
1121 	if (pnode != NULL && policy != NULL) {
1122 		if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) {
1123 			ret = KMF_ERR_POLICY_ENGINE;
1124 			goto out;
1125 		}
1126 		if (policy->ignore_date) {
1127 			if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR,
1128 			    "TRUE")) {
1129 				ret = KMF_ERR_POLICY_ENGINE;
1130 				goto out;
1131 			}
1132 		}
1133 
1134 		if (policy->ignore_unknown_ekus) {
1135 			if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS,
1136 			    "TRUE")) {
1137 				ret = KMF_ERR_POLICY_ENGINE;
1138 				goto out;
1139 			}
1140 		}
1141 
1142 		if (policy->ignore_trust_anchor) {
1143 			if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR,
1144 			    "TRUE")) {
1145 				ret = KMF_ERR_POLICY_ENGINE;
1146 				goto out;
1147 			}
1148 		}
1149 
1150 		if (policy->validity_adjusttime) {
1151 			if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME,
1152 			    policy->validity_adjusttime)) {
1153 				ret = KMF_ERR_POLICY_ENGINE;
1154 				goto out;
1155 			}
1156 		}
1157 
1158 		if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR,
1159 		    policy->ta_name) != 0) {
1160 			ret = KMF_ERR_POLICY_ENGINE;
1161 			goto out;
1162 		}
1163 
1164 		if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR,
1165 		    policy->ta_serial) != 0) {
1166 			ret = KMF_ERR_POLICY_ENGINE;
1167 			goto out;
1168 		}
1169 
1170 		/* Add a text node for readability */
1171 		addFormatting(pnode, "\n");
1172 
1173 		if (ret = AddValidationNodes(pnode, policy)) {
1174 			goto out;
1175 		}
1176 
1177 		if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) {
1178 			goto out;
1179 		}
1180 
1181 		if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) {
1182 			goto out;
1183 		}
1184 	} else {
1185 		ret = KMF_ERR_BAD_PARAMETER;
1186 	}
1187 out:
1188 	if (ret != KMF_OK && pnode != NULL) {
1189 		xmlUnlinkNode(pnode);
1190 		xmlFreeNode(pnode);
1191 	}
1192 
1193 	return (ret);
1194 }
1195 
1196 
1197 KMF_RETURN
1198 kmf_verify_policy(KMF_POLICY_RECORD *policy)
1199 {
1200 	KMF_RETURN ret = KMF_OK;
1201 	boolean_t has_ta;
1202 
1203 	if (policy->name == NULL || !strlen(policy->name))
1204 		return (KMF_ERR_POLICY_NAME);
1205 
1206 	/* Check the TA related policy */
1207 	if (policy->ta_name != NULL && policy->ta_serial != NULL) {
1208 		has_ta = B_TRUE;
1209 	} else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
1210 		has_ta = B_FALSE;
1211 	} else {
1212 		/*
1213 		 * If the TA cert is set, then both name and serial number
1214 		 * need to be specified.
1215 		 */
1216 		return (KMF_ERR_TA_POLICY);
1217 	}
1218 
1219 	if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE)
1220 		return (KMF_ERR_TA_POLICY);
1221 
1222 	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
1223 		/*
1224 		 * For OCSP, either use a fixed responder or use the
1225 		 * value from the cert, but not both.
1226 		 */
1227 		if ((policy->VAL_OCSP_BASIC.responderURI == NULL &&
1228 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) ||
1229 		    (policy->VAL_OCSP_BASIC.responderURI != NULL &&
1230 		    policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE))
1231 			return (KMF_ERR_OCSP_POLICY);
1232 
1233 		/*
1234 		 * If the OCSP responder cert is set, then both name and serial
1235 		 * number need to be specified.
1236 		 */
1237 		if ((policy->VAL_OCSP_RESP_CERT.name != NULL &&
1238 		    policy->VAL_OCSP_RESP_CERT.serial == NULL) ||
1239 		    (policy->VAL_OCSP_RESP_CERT.name == NULL &&
1240 		    policy->VAL_OCSP_RESP_CERT.serial != NULL))
1241 			return (KMF_ERR_OCSP_POLICY);
1242 	}
1243 
1244 	return (ret);
1245 }
1246 
1247 /*
1248  * Update the KMF policy file by creating a new XML Policy doc tree
1249  * from the data in the KMF_POLICY_RECORD structure. If "check_policy"
1250  * is true, then we check the policy sanity also.
1251  */
1252 KMF_RETURN
1253 kmf_add_policy_to_db(KMF_POLICY_RECORD *policy, char *dbfilename,
1254     boolean_t check_policy)
1255 {
1256 	KMF_RETURN ret = KMF_OK;
1257 	xmlDocPtr doc = NULL;
1258 	xmlNodePtr root, node;
1259 	xmlParserCtxtPtr ctxt = NULL;
1260 
1261 	if (policy == NULL || dbfilename == NULL)
1262 		return (KMF_ERR_BAD_PARAMETER);
1263 
1264 	if (check_policy == B_TRUE) {
1265 		if (ret = kmf_verify_policy(policy))
1266 			return (ret);
1267 	}
1268 
1269 	/* If the policyDB exists, load it into memory */
1270 	if (!access(dbfilename, R_OK)) {
1271 
1272 		/* Create a parser context */
1273 		ctxt = xmlNewParserCtxt();
1274 		if (ctxt == NULL)
1275 			return (KMF_ERR_POLICY_DB_FORMAT);
1276 
1277 		doc = xmlCtxtReadFile(ctxt, dbfilename, NULL,
1278 		    XML_PARSE_DTDVALID | XML_PARSE_NOERROR |
1279 		    XML_PARSE_NOWARNING);
1280 		if (doc == NULL || ctxt->valid == 0) {
1281 			ret = KMF_ERR_POLICY_DB_FORMAT;
1282 			goto out;
1283 		}
1284 
1285 		root = xmlDocGetRootElement(doc);
1286 		if (root == NULL) {
1287 			ret = KMF_ERR_POLICY_DB_FORMAT;
1288 			goto out;
1289 		}
1290 
1291 		node = root->xmlChildrenNode;
1292 		/*
1293 		 * If the DB has an existing policy of the
1294 		 * same name, delete it from the tree.
1295 		 */
1296 		ret = deletePolicyNode(node, policy->name);
1297 		if (ret == KMF_ERR_POLICY_NOT_FOUND)
1298 			ret = KMF_OK;
1299 	} else {
1300 		/* Initialize a new DB tree */
1301 		doc = xmlNewDoc((const xmlChar *)"1.0");
1302 		if (doc == NULL)
1303 			return (KMF_ERR_POLICY_ENGINE);
1304 
1305 		/*
1306 		 * Add the DOCTYPE header to the tree so the
1307 		 * DTD link is embedded
1308 		 */
1309 		doc->intSubset = xmlCreateIntSubset(doc,
1310 		    (const xmlChar *)KMF_POLICY_ROOT,
1311 		    NULL, (const xmlChar *)KMF_POLICY_DTD);
1312 
1313 		root = xmlNewDocNode(doc, NULL,
1314 		    (const xmlChar *)KMF_POLICY_ROOT, NULL);
1315 		if (root != NULL) {
1316 			(void) xmlDocSetRootElement(doc, root);
1317 		}
1318 	}
1319 
1320 	/* Append the new policy info to the root node. */
1321 	if (root != NULL) {
1322 		xmlNodePtr pnode;
1323 
1324 		pnode = xmlNewChild(root, NULL,
1325 		    (const xmlChar *)KMF_POLICY_ELEMENT, NULL);
1326 
1327 		ret = addPolicyNode(pnode, policy);
1328 		/* If that worked, update the DB file. */
1329 		if (ret == KMF_OK)
1330 			ret = update_policyfile(doc, dbfilename);
1331 	} else {
1332 		ret = KMF_ERR_POLICY_ENGINE;
1333 	}
1334 
1335 
1336 out:
1337 	if (ctxt != NULL)
1338 		xmlFreeParserCtxt(ctxt);
1339 
1340 	if (doc != NULL)
1341 		xmlFreeDoc(doc);
1342 
1343 	return (ret);
1344 }
1345