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