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