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 37 typedef struct { 38 char *ekuname; 39 KMF_OID *oid; 40 } EKUName2OID; 41 42 static 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 57 static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID); 58 59 static void 60 addFormatting(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 73 static void 74 parseOCSPValidation(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 */ 128 static void 129 parseValidation(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 189 char * 190 kmf_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 222 uint32_t 223 kmf_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 249 static void 250 parseKeyUsageSet(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 271 static KMF_OID * 272 dup_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 291 KMF_OID * 292 kmf_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 310 char * 311 kmf_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 323 static KMF_RETURN 324 parseExtKeyUsage(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 388 static KMF_RETURN 389 parseMapper(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 413 int 414 parsePolicyElement(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 489 static int 490 newprop(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 */ 512 static int 513 AddCRLNodes(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 */ 559 static int 560 AddOCSPNodes(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 */ 629 static int 630 AddValidationNodes(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 658 end: 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 */ 671 static KMF_RETURN 672 AddMapperPolicyNodes(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 710 end: 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 */ 722 static KMF_RETURN 723 AddKeyUsageNodes(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 */ 768 static KMF_RETURN 769 AddExtKeyUsageNodes(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 810 void 811 kmf_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 824 void 825 kmf_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 */ 857 KMF_RETURN 858 kmf_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 919 out: 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 */ 937 KMF_RETURN 938 kmf_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 971 out: 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 982 static KMF_RETURN 983 deletePolicyNode(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 */ 1034 static KMF_RETURN 1035 update_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 */ 1139 KMF_RETURN 1140 kmf_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 1186 end: 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 */ 1199 static KMF_RETURN 1200 addPolicyNode(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 } 1273 out: 1274 if (ret != KMF_OK && pnode != NULL) { 1275 xmlUnlinkNode(pnode); 1276 xmlFreeNode(pnode); 1277 } 1278 1279 return (ret); 1280 } 1281 1282 KMF_RETURN 1283 kmf_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 */ 1340 KMF_RETURN 1341 kmf_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 1424 out: 1425 if (ctxt != NULL) 1426 xmlFreeParserCtxt(ctxt); 1427 1428 if (doc != NULL) 1429 xmlFreeDoc(doc); 1430 1431 return (ret); 1432 } 1433