1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <time.h> 32 #include <unistd.h> 33 #include <locale.h> 34 #include <sys/types.h> 35 #include <zone.h> 36 #include <sys/stat.h> 37 #include "cryptoadm.h" 38 #include <cryptoutil.h> 39 40 static int err; /* To store errno which may be overwritten by gettext() */ 41 static int build_entrylist(entry_t *, entrylist_t **); 42 static entry_t *dup_entry(entry_t *); 43 static mechlist_t *dup_mechlist(mechlist_t *); 44 static entry_t *getent(char *, entrylist_t *); 45 static int interpret(char *, entry_t **); 46 static int parse_sup_dis_list(char *, entry_t *); 47 48 49 /* 50 * Duplicate the mechanism list. A null pointer is returned if the storage 51 * space available is insufficient or the input argument is NULL. 52 */ 53 static mechlist_t * 54 dup_mechlist(mechlist_t *plist) 55 { 56 mechlist_t *pres = NULL; 57 mechlist_t *pcur; 58 mechlist_t *ptmp; 59 int rc = SUCCESS; 60 61 while (plist != NULL) { 62 if (!(ptmp = create_mech(plist->name))) { 63 rc = FAILURE; 64 break; 65 } 66 67 if (pres == NULL) { 68 pres = pcur = ptmp; 69 } else { 70 pcur->next = ptmp; 71 pcur = pcur->next; 72 } 73 plist = plist->next; 74 } 75 76 if (rc != SUCCESS) { 77 free_mechlist(pres); 78 return (NULL); 79 } 80 81 return (pres); 82 } 83 84 85 /* 86 * Get the number of mechanisms in the mechanism list. 87 */ 88 int 89 get_mech_count(mechlist_t *plist) 90 { 91 int count = 0; 92 93 while (plist != NULL) { 94 count++; 95 plist = plist->next; 96 } 97 return (count); 98 } 99 100 /* 101 * Create one item of type entry_t with the provider name. 102 * Return NULL if there's not enough memory or provname is NULL. 103 */ 104 entry_t * 105 create_entry(char *provname) 106 { 107 entry_t *pent = NULL; 108 109 if (provname == NULL) { 110 return (NULL); 111 } 112 113 pent = calloc(1, sizeof (entry_t)); 114 if (pent == NULL) { 115 cryptodebug("out of memory."); 116 return (NULL); 117 } 118 119 (void) strlcpy(pent->name, provname, MAXNAMELEN); 120 pent->suplist = NULL; 121 pent->sup_count = 0; 122 pent->dislist = NULL; 123 pent->dis_count = 0; 124 pent->load = B_TRUE; 125 126 return (pent); 127 } 128 129 /* 130 * Duplicate an entry for a provider from kcf.conf. 131 * Return NULL if memory is insufficient or the input argument is NULL. 132 * Called by getent(). 133 */ 134 static entry_t * 135 dup_entry(entry_t *pent1) 136 { 137 entry_t *pent2 = NULL; 138 139 if (pent1 == NULL) { 140 return (NULL); 141 } 142 143 if ((pent2 = create_entry(pent1->name)) == NULL) { 144 cryptodebug("out of memory."); 145 return (NULL); 146 } 147 148 pent2->flag_fips_enabled = pent1->flag_fips_enabled; 149 pent2->sup_count = pent1->sup_count; 150 pent2->dis_count = pent1->dis_count; 151 pent2->load = pent1->load; 152 if (pent1->suplist != NULL) { 153 pent2->suplist = dup_mechlist(pent1->suplist); 154 if (pent2->suplist == NULL) { 155 free_entry(pent2); 156 return (NULL); 157 } 158 } 159 if (pent1->dislist != NULL) { 160 pent2->dislist = dup_mechlist(pent1->dislist); 161 if (pent2->dislist == NULL) { 162 free_entry(pent2); 163 return (NULL); 164 } 165 } 166 167 return (pent2); 168 } 169 170 171 /* 172 * This routine parses the disabledlist or the supportedlist of an entry 173 * in the kcf.conf configuration file. 174 * 175 * Arguments: 176 * buf: an input argument which is a char string with the format of 177 * "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..." 178 * pent: the entry for the disabledlist. This is an IN/OUT argument. 179 * 180 * Return value: SUCCESS or FAILURE. 181 */ 182 static int 183 parse_sup_dis_list(char *buf, entry_t *pent) 184 { 185 mechlist_t *pmech = NULL; 186 mechlist_t *phead = NULL; 187 char *next_token; 188 char *value; 189 int count; 190 int supflag = B_FALSE; 191 int disflag = B_FALSE; 192 int rc = SUCCESS; 193 194 if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) { 195 supflag = B_TRUE; 196 } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) { 197 disflag = B_TRUE; 198 } else { 199 /* should not come here */ 200 return (FAILURE); 201 } 202 203 if (value = strpbrk(buf, SEP_EQUAL)) { 204 value++; /* get rid of = */ 205 } else { 206 cryptodebug("failed to parse the kcf.conf file."); 207 return (FAILURE); 208 } 209 210 if ((next_token = strtok(value, SEP_COMMA)) == NULL) { 211 cryptodebug("failed to parse the kcf.conf file."); 212 return (FAILURE); 213 } 214 215 if ((pmech = create_mech(next_token)) == NULL) { 216 return (FAILURE); 217 } 218 219 if (supflag) { 220 pent->suplist = phead = pmech; 221 } else if (disflag) { 222 pent->dislist = phead = pmech; 223 } 224 225 count = 1; 226 while (next_token) { 227 if (next_token = strtok(NULL, SEP_COMMA)) { 228 if ((pmech = create_mech(next_token)) == NULL) { 229 rc = FAILURE; 230 break; 231 } 232 count++; 233 phead->next = pmech; 234 phead = phead->next; 235 } 236 } 237 238 if (rc == SUCCESS) { 239 if (supflag) { 240 pent->sup_count = count; 241 } else if (disflag) { 242 pent->dis_count = count; 243 } 244 } else { 245 free_mechlist(phead); 246 } 247 248 return (rc); 249 } 250 251 static int 252 parse_fips(char *buf, entry_t *pent) 253 { 254 char *value; 255 256 if (strncmp(buf, EF_FIPS_STATUS, sizeof (EF_FIPS_STATUS) - 1) == 0) { 257 if (value = strpbrk(buf, SEP_EQUAL)) { 258 value++; /* get rid of = */ 259 if (strcmp(value, DISABLED_KEYWORD) == 0) { 260 pent->flag_fips_enabled = B_FALSE; 261 } else if (strcmp(value, ENABLED_KEYWORD) == 0) { 262 pent->flag_fips_enabled = B_TRUE; 263 } else { 264 cryptoerror(LOG_ERR, gettext( 265 "Failed to parse kcf.conf file.\n")); 266 return (FAILURE); 267 } 268 return (SUCCESS); 269 } else { 270 return (FAILURE); 271 } 272 } else { 273 /* should not come here */ 274 cryptoerror(LOG_ERR, gettext( 275 "Failed to parse kcf.conf file.\n")); 276 return (FAILURE); 277 } 278 279 } 280 281 /* 282 * Convert a char string containing a line about a provider 283 * from kcf.conf into an entry_t structure. 284 * 285 * See ent2str(), the reverse of this function, for the format of 286 * kcf.conf lines. 287 */ 288 static int 289 interpret(char *buf, entry_t **ppent) 290 { 291 entry_t *pent = NULL; 292 char *token1; 293 char *token2; 294 char *token3; 295 int rc; 296 297 /* Get provider name */ 298 if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */ 299 return (FAILURE); 300 }; 301 302 pent = create_entry(token1); 303 if (pent == NULL) { 304 cryptodebug("out of memory."); 305 return (FAILURE); 306 } 307 308 if (is_fips(token1)) { 309 if ((rc = parse_fips(buf + strlen(token1) + 1, 310 pent)) != SUCCESS) { 311 free_entry(pent); 312 } 313 *ppent = pent; 314 return (rc); 315 } 316 317 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) { 318 /* The entry contains a provider name only */ 319 free_entry(pent); 320 return (FAILURE); 321 } 322 323 if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) { 324 pent->load = B_FALSE; /* cryptoadm unload */ 325 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) { 326 /* The entry contains a provider name:unload only */ 327 free_entry(pent); 328 return (FAILURE); 329 } 330 } 331 332 /* need to get token3 first to satisfy nested strtok invocations */ 333 token3 = strtok(NULL, SEP_SEMICOLON); /* optional */ 334 335 /* parse supportedlist (or disabledlist if no supportedlist) */ 336 if ((token2 != NULL) && ((rc = parse_sup_dis_list(token2, pent)) != 337 SUCCESS)) { 338 free_entry(pent); 339 return (rc); 340 } 341 342 /* parse disabledlist (if there's a supportedlist) */ 343 if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) != 344 SUCCESS)) { 345 free_entry(pent); 346 return (rc); 347 } 348 349 *ppent = pent; 350 return (SUCCESS); 351 } 352 353 354 /* 355 * Add an entry about a provider from kcf.conf to the end of an entry list. 356 * If the entry list pplist is NULL, create the linked list with pent as the 357 * first element. 358 */ 359 static int 360 build_entrylist(entry_t *pent, entrylist_t **pplist) 361 { 362 entrylist_t *pentlist; 363 entrylist_t *pcur = NULL; 364 365 pentlist = malloc(sizeof (entrylist_t)); 366 if (pentlist == NULL) { 367 cryptodebug("out of memory."); 368 return (FAILURE); 369 } 370 pentlist->pent = pent; 371 pentlist->next = NULL; 372 373 if (*pplist) { 374 pcur = *pplist; 375 while (pcur->next != NULL) 376 pcur = pcur->next; 377 pcur->next = pentlist; 378 } else { /* empty list */ 379 *pplist = pentlist; 380 } 381 382 return (SUCCESS); 383 } 384 385 386 387 /* 388 * Find the entry with the "provname" name from the entry list and duplicate 389 * it. Called by getent_kef(). 390 */ 391 static entry_t * 392 getent(char *provname, entrylist_t *entrylist) 393 { 394 boolean_t found = B_FALSE; 395 entry_t *pent1 = NULL; 396 397 if ((provname == NULL) || (entrylist == NULL)) { 398 return (NULL); 399 } 400 401 while (!found && entrylist) { 402 if (strcmp(entrylist->pent->name, provname) == 0) { 403 found = B_TRUE; 404 pent1 = entrylist->pent; 405 } else { 406 entrylist = entrylist->next; 407 } 408 } 409 410 if (!found) { 411 return (NULL); 412 } 413 414 /* duplicate the entry to be returned */ 415 return (dup_entry(pent1)); 416 } 417 418 419 /* 420 * Free memory in entry_t. 421 * That is, the supported and disabled lists for a provider 422 * from kcf.conf. 423 */ 424 void 425 free_entry(entry_t *pent) 426 { 427 if (pent == NULL) { 428 return; 429 } else { 430 free_mechlist(pent->suplist); 431 free_mechlist(pent->dislist); 432 free(pent); 433 } 434 } 435 436 437 /* 438 * Free elements in a entrylist_t linked list, 439 * which lists providers in kcf.conf. 440 */ 441 void 442 free_entrylist(entrylist_t *entrylist) 443 { 444 entrylist_t *pnext; 445 446 while (entrylist != NULL) { 447 pnext = entrylist->next; 448 free_entry(entrylist->pent); 449 entrylist = pnext; 450 } 451 } 452 453 454 /* 455 * Convert an entry to a string. This routine builds a string for the entry 456 * to be inserted in the kcf.conf file. Based on the content of each entry, 457 * the result string can be one of these 6 forms: 458 * - name:supportedlist=m1,m2,...,mj 459 * - name:disabledlist=m1,m2,...,mj 460 * - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk 461 * 462 * - name:unload;supportedlist=m1,m2,...,mj 463 * - name:unload;disabledlist=m1,m2,...,mj 464 * - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk 465 * 466 * Note that the caller is responsible for freeing the returned string 467 * (with free_entry()). 468 * See interpret() for the reverse of this function: converting a string 469 * to an entry_t. 470 */ 471 char * 472 ent2str(entry_t *pent) 473 { 474 char *buf; 475 mechlist_t *pcur = NULL; 476 boolean_t semicolon_separator = B_FALSE; 477 478 479 if (pent == NULL) { 480 return (NULL); 481 } 482 483 if ((buf = malloc(BUFSIZ)) == NULL) { 484 return (NULL); 485 } 486 487 /* convert the provider name */ 488 if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) { 489 free(buf); 490 return (NULL); 491 } 492 493 if (!pent->load) { /* add "unload" keyword */ 494 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { 495 free(buf); 496 return (NULL); 497 } 498 499 if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) { 500 free(buf); 501 return (NULL); 502 } 503 504 semicolon_separator = B_TRUE; 505 } 506 507 /* convert the supported list if any */ 508 pcur = pent->suplist; 509 if (pcur != NULL) { 510 if (strlcat(buf, 511 semicolon_separator ? SEP_SEMICOLON : SEP_COLON, 512 BUFSIZ) >= BUFSIZ) { 513 free(buf); 514 return (NULL); 515 } 516 517 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) { 518 free(buf); 519 return (NULL); 520 } 521 522 while (pcur != NULL) { 523 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { 524 free(buf); 525 return (NULL); 526 } 527 528 pcur = pcur->next; 529 if (pcur != NULL) { 530 if (strlcat(buf, SEP_COMMA, BUFSIZ) 531 >= BUFSIZ) { 532 free(buf); 533 return (NULL); 534 } 535 } 536 } 537 semicolon_separator = B_TRUE; 538 } 539 540 /* convert the disabled list if any */ 541 pcur = pent->dislist; 542 if (pcur != NULL) { 543 if (strlcat(buf, 544 semicolon_separator ? SEP_SEMICOLON : SEP_COLON, 545 BUFSIZ) >= BUFSIZ) { 546 free(buf); 547 return (NULL); 548 } 549 550 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) { 551 free(buf); 552 return (NULL); 553 } 554 555 while (pcur != NULL) { 556 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { 557 free(buf); 558 return (NULL); 559 } 560 561 pcur = pcur->next; 562 if (pcur != NULL) { 563 if (strlcat(buf, SEP_COMMA, BUFSIZ) 564 >= BUFSIZ) { 565 free(buf); 566 return (NULL); 567 } 568 } 569 } 570 semicolon_separator = B_TRUE; 571 } 572 573 if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) { 574 free(buf); 575 return (NULL); 576 } 577 578 return (buf); 579 } 580 581 582 /* 583 * Enable the mechanisms for the provider pointed by *ppent. If allflag is 584 * TRUE, enable all. Otherwise, enable the mechanisms specified in the 3rd 585 * argument "mlist". The result will be stored in ppent also. 586 */ 587 int 588 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist) 589 { 590 entry_t *pent; 591 mechlist_t *phead; /* the current and resulting disabled list */ 592 mechlist_t *ptr = NULL; 593 mechlist_t *pcur = NULL; 594 boolean_t found; 595 596 pent = *ppent; 597 if (pent == NULL) { 598 return (FAILURE); 599 } 600 601 if (allflag) { 602 free_mechlist(pent->dislist); 603 pent->dis_count = 0; 604 pent->dislist = NULL; 605 return (SUCCESS); 606 } 607 608 /* 609 * for each mechanism in the to-be-enabled mechanism list, 610 * - check if it is in the current disabled list 611 * - if found, delete it from the disabled list 612 * otherwise, give a warning. 613 */ 614 ptr = mlist; 615 while (ptr != NULL) { 616 found = B_FALSE; 617 phead = pcur = pent->dislist; 618 while (!found && pcur) { 619 if (strcmp(pcur->name, ptr->name) == 0) { 620 found = B_TRUE; 621 } else { 622 phead = pcur; 623 pcur = pcur->next; 624 } 625 } 626 627 if (found) { 628 if (phead == pcur) { 629 pent->dislist = pent->dislist->next; 630 free(pcur); 631 } else { 632 phead->next = pcur->next; 633 free(pcur); 634 } 635 pent->dis_count--; 636 } else { 637 cryptoerror(LOG_STDERR, gettext( 638 "(Warning) %1$s is either enabled already or not " 639 "a valid mechanism for %2$s"), ptr->name, 640 pent->name); 641 } 642 ptr = ptr->next; 643 } 644 645 if (pent->dis_count == 0) { 646 pent->dislist = NULL; 647 } 648 649 return (SUCCESS); 650 651 } 652 653 654 /* 655 * Determine if the kernel provider name, path, is a device 656 * (that is, it contains a slash character (e.g., "mca/0"). 657 * If so, it is a hardware provider; otherwise it is a software provider. 658 */ 659 boolean_t 660 is_device(char *path) 661 { 662 if (strchr(path, SEP_SLASH) != NULL) { 663 return (B_TRUE); 664 } else { 665 return (B_FALSE); 666 } 667 } 668 669 boolean_t 670 is_fips(char *name) 671 { 672 if (strcmp(name, FIPS_KEYWORD) == 0) { 673 return (B_TRUE); 674 } else { 675 return (B_FALSE); 676 } 677 } 678 679 /* 680 * Split a hardware provider name with the "name/inst_num" format into 681 * a name and a number (e.g., split "mca/0" into "mca" instance 0). 682 */ 683 int 684 split_hw_provname(char *provname, char *pname, int *inst_num) 685 { 686 char name[MAXNAMELEN]; 687 char *inst_str; 688 689 if (provname == NULL) { 690 return (FAILURE); 691 } 692 693 (void) strlcpy(name, provname, MAXNAMELEN); 694 if (strtok(name, "/") == NULL) { 695 return (FAILURE); 696 } 697 698 if ((inst_str = strtok(NULL, "/")) == NULL) { 699 return (FAILURE); 700 } 701 702 (void) strlcpy(pname, name, MAXNAMELEN); 703 *inst_num = atoi(inst_str); 704 705 return (SUCCESS); 706 } 707 708 709 /* 710 * Retrieve information from kcf.conf and build a hardware device entry list 711 * and a software entry list of kernel crypto providers. 712 * 713 * This list is usually incomplete, as kernel crypto providers only have to 714 * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or 715 * if the kernel provider module is not one of the default kernel providers. 716 * 717 * The kcf.conf file is available only in the global zone. 718 */ 719 int 720 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist, 721 entrylist_t **ppfipslist) 722 { 723 FILE *pfile = NULL; 724 char buffer[BUFSIZ]; 725 int len; 726 entry_t *pent = NULL; 727 int rc = SUCCESS; 728 729 if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) { 730 cryptodebug("failed to open the kcf.conf file for read only"); 731 return (FAILURE); 732 } 733 734 *ppdevlist = NULL; 735 *ppsoftlist = NULL; 736 *ppfipslist = NULL; 737 738 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 739 if (buffer[0] == '#' || buffer[0] == ' ' || 740 buffer[0] == '\n'|| buffer[0] == '\t') { 741 continue; /* ignore comment lines */ 742 } 743 744 len = strlen(buffer); 745 if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */ 746 len--; 747 } 748 buffer[len] = '\0'; 749 750 if ((rc = interpret(buffer, &pent)) == SUCCESS) { 751 if (is_fips(pent->name)) { 752 if (*ppfipslist != NULL) { 753 cryptoerror(LOG_STDERR, gettext( 754 "multiple fips entries.")); 755 rc = FAILURE; 756 } else { 757 rc = build_entrylist(pent, ppfipslist); 758 } 759 } else if (is_device(pent->name)) { 760 rc = build_entrylist(pent, ppdevlist); 761 } else { 762 rc = build_entrylist(pent, ppsoftlist); 763 } 764 } else { 765 cryptoerror(LOG_STDERR, gettext( 766 "failed to parse configuration.")); 767 rc = FAILURE; 768 } 769 770 if (rc != SUCCESS) { 771 free_entrylist(*ppdevlist); 772 free_entrylist(*ppsoftlist); 773 free_entrylist(*ppfipslist); 774 free_entry(pent); 775 break; 776 } 777 } 778 779 (void) fclose(pfile); 780 return (rc); 781 } 782 783 /* 784 * Retrieve information from admin device and build a device entry list and 785 * a software entry list. This is used where there is no kcf.conf, e.g., the 786 * non-global zone. 787 */ 788 int 789 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist) 790 { 791 crypto_get_dev_list_t *pdevlist_kernel = NULL; 792 crypto_get_soft_list_t *psoftlist_kernel = NULL; 793 char *devname; 794 int inst_num; 795 int mcount; 796 mechlist_t *pmech = NULL; 797 entry_t *pent_dev = NULL, *pent_soft = NULL; 798 int i; 799 char *psoftname; 800 entrylist_t *tmp_pdev = NULL; 801 entrylist_t *tmp_psoft = NULL; 802 entrylist_t *phardlist = NULL, *psoftlist = NULL; 803 entrylist_t *pfipslist = NULL; 804 805 /* 806 * Get hardware providers 807 */ 808 if (get_dev_list(&pdevlist_kernel) != SUCCESS) { 809 cryptodebug("failed to get hardware provider list from kernel"); 810 return (FAILURE); 811 } 812 813 for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { 814 devname = pdevlist_kernel->dl_devs[i].le_dev_name; 815 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance; 816 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count; 817 818 pmech = NULL; 819 if (get_dev_info(devname, inst_num, mcount, &pmech) != 820 SUCCESS) { 821 cryptodebug( 822 "failed to retrieve the mechanism list for %s/%d.", 823 devname, inst_num); 824 goto fail_out; 825 } 826 827 if ((pent_dev = create_entry(devname)) == NULL) { 828 cryptodebug("out of memory."); 829 free_mechlist(pmech); 830 goto fail_out; 831 } 832 pent_dev->suplist = pmech; 833 pent_dev->sup_count = mcount; 834 835 if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) { 836 goto fail_out; 837 } 838 } 839 840 free(pdevlist_kernel); 841 pdevlist_kernel = NULL; 842 843 /* 844 * Get software providers 845 */ 846 if (getzoneid() == GLOBAL_ZONEID) { 847 if (get_kcfconf_info(&phardlist, &psoftlist, &pfipslist) != 848 SUCCESS) { 849 goto fail_out; 850 } 851 } 852 853 if (get_soft_list(&psoftlist_kernel) != SUCCESS) { 854 cryptodebug("failed to get software provider list from kernel"); 855 goto fail_out; 856 } 857 858 for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; 859 i < psoftlist_kernel->sl_soft_count; 860 i++, psoftname = psoftname + strlen(psoftname) + 1) { 861 pmech = NULL; 862 if (get_soft_info(psoftname, &pmech, phardlist, psoftlist, 863 pfipslist) != SUCCESS) { 864 cryptodebug( 865 "failed to retrieve the mechanism list for %s.", 866 psoftname); 867 goto fail_out; 868 } 869 870 if ((pent_soft = create_entry(psoftname)) == NULL) { 871 cryptodebug("out of memory."); 872 free_mechlist(pmech); 873 goto fail_out; 874 } 875 pent_soft->suplist = pmech; 876 pent_soft->sup_count = get_mech_count(pmech); 877 878 if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) { 879 goto fail_out; 880 } 881 } 882 883 free(psoftlist_kernel); 884 psoftlist_kernel = NULL; 885 886 *ppdevlist = tmp_pdev; 887 *ppsoftlist = tmp_psoft; 888 889 return (SUCCESS); 890 891 fail_out: 892 if (pent_dev != NULL) 893 free_entry(pent_dev); 894 if (pent_soft != NULL) 895 free_entry(pent_soft); 896 897 free_entrylist(tmp_pdev); 898 free_entrylist(tmp_psoft); 899 900 if (pdevlist_kernel != NULL) 901 free(pdevlist_kernel); 902 if (psoftlist_kernel != NULL) 903 free(psoftlist_kernel); 904 905 return (FAILURE); 906 } 907 908 /* 909 * Return configuration information for a kernel provider from kcf.conf. 910 * For kernel software providers return a enabled list and disabled list. 911 * For kernel hardware providers return just a disabled list. 912 * 913 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). 914 * If NULL, this function calls get_kcfconf_info() internally. 915 */ 916 entry_t * 917 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist, 918 entrylist_t *pfipslist) 919 { 920 entry_t *pent = NULL; 921 boolean_t memory_allocated = B_FALSE; 922 923 if ((phardlist == NULL) || (psoftlist == NULL) || (pfipslist == NULL)) { 924 if (get_kcfconf_info(&phardlist, &psoftlist, &pfipslist) != 925 SUCCESS) { 926 return (NULL); 927 } 928 memory_allocated = B_TRUE; 929 } 930 931 if (is_device(provname)) { 932 pent = getent(provname, phardlist); 933 } else if (is_fips(provname)) { 934 pent = getent(provname, pfipslist); 935 } else { 936 pent = getent(provname, psoftlist); 937 } 938 939 if (memory_allocated) { 940 free_entrylist(phardlist); 941 free_entrylist(psoftlist); 942 free_entrylist(pfipslist); 943 } 944 945 return (pent); 946 } 947 948 /* 949 * Print out the provider name and the mechanism list. 950 */ 951 void 952 print_mechlist(char *provname, mechlist_t *pmechlist) 953 { 954 mechlist_t *ptr = NULL; 955 956 if (provname == NULL) { 957 return; 958 } 959 960 (void) printf("%s: ", provname); 961 if (pmechlist == NULL) { 962 (void) printf(gettext("No mechanisms presented.\n")); 963 return; 964 } 965 966 ptr = pmechlist; 967 while (ptr != NULL) { 968 (void) printf("%s", ptr->name); 969 ptr = ptr->next; 970 if (ptr == NULL) { 971 (void) printf("\n"); 972 } else { 973 (void) printf(","); 974 } 975 } 976 } 977 978 979 /* 980 * Update the kcf.conf file based on the update mode: 981 * - If update_mode is MODIFY_MODE, modify the entry with the same name. 982 * If not found, append a new entry to the kcf.conf file. 983 * - If update_mode is DELETE_MODE, delete the entry with the same name. 984 * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file. 985 */ 986 int 987 update_kcfconf(entry_t *pent, int update_mode) 988 { 989 boolean_t add_it = B_FALSE; 990 boolean_t delete_it = B_FALSE; 991 boolean_t this_entry_matches = B_FALSE; 992 boolean_t found_entry = B_FALSE; 993 FILE *pfile = NULL; 994 FILE *pfile_tmp = NULL; 995 char buffer[BUFSIZ]; 996 char buffer2[BUFSIZ]; 997 char tmpfile_name[MAXPATHLEN]; 998 char *name; 999 char *new_str = NULL; 1000 int rc = SUCCESS; 1001 1002 if (pent == NULL) { 1003 cryptoerror(LOG_STDERR, gettext("internal error.")); 1004 return (FAILURE); 1005 } 1006 1007 /* Check the update_mode */ 1008 switch (update_mode) { 1009 case ADD_MODE: 1010 add_it = B_TRUE; 1011 /* FALLTHROUGH */ 1012 case MODIFY_MODE: 1013 /* Convert the entry a string to add to kcf.conf */ 1014 if ((new_str = ent2str(pent)) == NULL) { 1015 return (FAILURE); 1016 } 1017 break; 1018 case DELETE_MODE: 1019 delete_it = B_TRUE; 1020 break; 1021 default: 1022 cryptoerror(LOG_STDERR, gettext("internal error.")); 1023 return (FAILURE); 1024 } 1025 1026 /* Open the kcf.conf file */ 1027 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { 1028 err = errno; 1029 cryptoerror(LOG_STDERR, 1030 gettext("failed to update the configuration - %s"), 1031 strerror(err)); 1032 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); 1033 return (FAILURE); 1034 } 1035 1036 /* Lock the kcf.conf file */ 1037 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 1038 err = errno; 1039 cryptoerror(LOG_STDERR, 1040 gettext("failed to update the configuration - %s"), 1041 strerror(err)); 1042 (void) fclose(pfile); 1043 return (FAILURE); 1044 } 1045 1046 /* 1047 * Create a temporary file in the /etc/crypto directory to save 1048 * updated configuration file first. 1049 */ 1050 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 1051 if (mkstemp(tmpfile_name) == -1) { 1052 err = errno; 1053 cryptoerror(LOG_STDERR, 1054 gettext("failed to create a temporary file - %s"), 1055 strerror(err)); 1056 (void) fclose(pfile); 1057 return (FAILURE); 1058 } 1059 1060 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 1061 err = errno; 1062 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 1063 tmpfile_name, strerror(err)); 1064 (void) fclose(pfile); 1065 return (FAILURE); 1066 } 1067 1068 /* 1069 * Loop thru the entire kcf.conf file, insert, modify or delete 1070 * an entry. 1071 */ 1072 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 1073 if (add_it) { 1074 if (fputs(buffer, pfile_tmp) == EOF) { 1075 err = errno; 1076 cryptoerror(LOG_STDERR, gettext( 1077 "failed to write to a temp file: %s."), 1078 strerror(err)); 1079 rc = FAILURE; 1080 break; 1081 } 1082 1083 } else { /* modify or delete */ 1084 this_entry_matches = B_FALSE; 1085 1086 if (!(buffer[0] == '#' || buffer[0] == ' ' || 1087 buffer[0] == '\n'|| buffer[0] == '\t')) { 1088 /* 1089 * Get the provider name from this line and 1090 * check if this is the entry to be updated 1091 * or deleted. Note: can not use "buffer" 1092 * directly because strtok will change its 1093 * value. 1094 */ 1095 (void) strlcpy(buffer2, buffer, BUFSIZ); 1096 if ((name = strtok(buffer2, SEP_COLON)) == 1097 NULL) { 1098 rc = FAILURE; 1099 break; 1100 } 1101 1102 if (strcmp(pent->name, name) == 0) { 1103 this_entry_matches = B_TRUE; 1104 found_entry = B_TRUE; 1105 } 1106 } 1107 1108 1109 if (!this_entry_matches || !delete_it) { 1110 /* write this entry */ 1111 if (this_entry_matches) { 1112 /* 1113 * Modify this entry: get the 1114 * updated string and place into buffer. 1115 */ 1116 (void) strlcpy(buffer, new_str, BUFSIZ); 1117 free(new_str); 1118 } 1119 /* write the (unchanged or modified) entry */ 1120 if (fputs(buffer, pfile_tmp) == EOF) { 1121 err = errno; 1122 cryptoerror(LOG_STDERR, gettext( 1123 "failed to write to a temp file: " 1124 "%s."), strerror(err)); 1125 rc = FAILURE; 1126 break; 1127 } 1128 } 1129 } 1130 } 1131 1132 if ((!delete_it) && (rc != FAILURE)) { 1133 if (add_it || !found_entry) { 1134 /* append new entry to end of file */ 1135 if (fputs(new_str, pfile_tmp) == EOF) { 1136 err = errno; 1137 cryptoerror(LOG_STDERR, gettext( 1138 "failed to write to a temp file: %s."), 1139 strerror(err)); 1140 rc = FAILURE; 1141 } 1142 free(new_str); 1143 } 1144 } 1145 1146 (void) fclose(pfile); 1147 if (fclose(pfile_tmp) != 0) { 1148 err = errno; 1149 cryptoerror(LOG_STDERR, 1150 gettext("failed to close %s: %s"), tmpfile_name, 1151 strerror(err)); 1152 return (FAILURE); 1153 } 1154 1155 /* Copy the temporary file to the kcf.conf file */ 1156 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { 1157 err = errno; 1158 cryptoerror(LOG_STDERR, 1159 gettext("failed to update the configuration - %s"), 1160 strerror(err)); 1161 cryptodebug("failed to rename %s to %s: %s", tmpfile, 1162 _PATH_KCF_CONF, strerror(err)); 1163 rc = FAILURE; 1164 } else if (chmod(_PATH_KCF_CONF, 1165 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 1166 err = errno; 1167 cryptoerror(LOG_STDERR, 1168 gettext("failed to update the configuration - %s"), 1169 strerror(err)); 1170 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, 1171 strerror(err)); 1172 rc = FAILURE; 1173 } else { 1174 rc = SUCCESS; 1175 } 1176 1177 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { 1178 err = errno; 1179 cryptoerror(LOG_STDERR, gettext( 1180 "(Warning) failed to remove %s: %s"), 1181 tmpfile_name, strerror(err)); 1182 } 1183 1184 return (rc); 1185 } 1186 1187 1188 /* 1189 * Disable the mechanisms for the provider pointed by *ppent. If allflag is 1190 * TRUE, disable all. Otherwise, disable the mechanisms specified in the 1191 * dislist argument. The "infolist" argument contains the mechanism list 1192 * supported by this provider. 1193 */ 1194 int 1195 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag, 1196 mechlist_t *dislist) 1197 { 1198 entry_t *pent; 1199 mechlist_t *plist = NULL; 1200 mechlist_t *phead = NULL; 1201 mechlist_t *pmech = NULL; 1202 int rc = SUCCESS; 1203 1204 pent = *ppent; 1205 if (pent == NULL) { 1206 return (FAILURE); 1207 } 1208 1209 if (allflag) { 1210 free_mechlist(pent->dislist); 1211 pent->dis_count = get_mech_count(infolist); 1212 if (!(pent->dislist = dup_mechlist(infolist))) { 1213 return (FAILURE); 1214 } else { 1215 return (SUCCESS); 1216 } 1217 } 1218 1219 /* 1220 * Not disable all. Now loop thru the mechanisms specified in the 1221 * dislist. If the mechanism is not supported by the provider, 1222 * ignore it with a warning. If the mechanism is disabled already, 1223 * do nothing. Otherwise, prepend it to the beginning of the disabled 1224 * list of the provider. 1225 */ 1226 plist = dislist; 1227 while (plist != NULL) { 1228 if (!is_in_list(plist->name, infolist)) { 1229 cryptoerror(LOG_STDERR, gettext("(Warning) " 1230 "%1$s is not a valid mechanism for %2$s."), 1231 plist->name, pent->name); 1232 } else if (!is_in_list(plist->name, pent->dislist)) { 1233 /* Add this mechanism into the disabled list */ 1234 if ((pmech = create_mech(plist->name)) == NULL) { 1235 rc = FAILURE; 1236 break; 1237 } 1238 1239 if (pent->dislist == NULL) { 1240 pent->dislist = pmech; 1241 } else { 1242 phead = pent->dislist; 1243 pent->dislist = pmech; 1244 pmech->next = phead; 1245 } 1246 pent->dis_count++; 1247 } 1248 plist = plist->next; 1249 } 1250 1251 return (rc); 1252 } 1253 1254 /* 1255 * Remove the mechanism passed, specified by mech, from the list of 1256 * mechanisms, if present in the list. Else, do nothing. 1257 * 1258 * Returns B_TRUE if mechanism is present in the list. 1259 */ 1260 boolean_t 1261 filter_mechlist(mechlist_t **pmechlist, const char *mech) 1262 { 1263 int cnt = 0; 1264 mechlist_t *ptr, *pptr; 1265 boolean_t mech_present = B_FALSE; 1266 1267 ptr = pptr = *pmechlist; 1268 1269 while (ptr != NULL) { 1270 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) { 1271 mech_present = B_TRUE; 1272 if (ptr == *pmechlist) { 1273 pptr = *pmechlist = ptr->next; 1274 free(ptr); 1275 ptr = pptr; 1276 } else { 1277 pptr->next = ptr->next; 1278 free(ptr); 1279 ptr = pptr->next; 1280 } 1281 } else { 1282 pptr = ptr; 1283 ptr = ptr->next; 1284 cnt++; 1285 } 1286 } 1287 1288 /* Only one entry is present */ 1289 if (cnt == 0) 1290 *pmechlist = NULL; 1291 1292 return (mech_present); 1293 } 1294 1295 1296 1297 /* 1298 * Print out the mechanism policy for a kernel provider that has an entry 1299 * in the kcf.conf file. 1300 * 1301 * The flag has_random is set to B_TRUE if the provider does random 1302 * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider 1303 * has some mechanisms. 1304 * 1305 * If pent is NULL, the provider doesn't have a kcf.conf entry. 1306 */ 1307 void 1308 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, 1309 boolean_t has_mechs) 1310 { 1311 mechlist_t *ptr = NULL; 1312 boolean_t rnd_disabled = B_FALSE; 1313 1314 if (pent != NULL) { 1315 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM); 1316 ptr = pent->dislist; 1317 } 1318 1319 (void) printf("%s:", provname); 1320 1321 if (has_mechs == B_TRUE) { 1322 /* 1323 * TRANSLATION_NOTE 1324 * This code block may need to be modified a bit to avoid 1325 * constructing the text message on the fly. 1326 */ 1327 (void) printf(gettext(" all mechanisms are enabled")); 1328 if (ptr != NULL) 1329 (void) printf(gettext(", except ")); 1330 while (ptr != NULL) { 1331 (void) printf("%s", ptr->name); 1332 ptr = ptr->next; 1333 if (ptr != NULL) 1334 (void) printf(","); 1335 } 1336 if (ptr == NULL) 1337 (void) printf("."); 1338 } 1339 1340 /* 1341 * TRANSLATION_NOTE 1342 * "random" is a keyword and not to be translated. 1343 */ 1344 if (rnd_disabled) 1345 (void) printf(gettext(" %s is disabled."), "random"); 1346 else if (has_random) 1347 (void) printf(gettext(" %s is enabled."), "random"); 1348 (void) printf("\n"); 1349 } 1350 1351 1352 /* 1353 * Check if a kernel software provider is in the kernel. 1354 * 1355 * Parameters: 1356 * provname Provider name 1357 * psoftlist_kernel Optional software provider list. If NULL, it will be 1358 * obtained from get_soft_list(). 1359 * in_kernel Set to B_TRUE if device is in the kernel, else B_FALSE 1360 */ 1361 int 1362 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel, 1363 boolean_t *in_kernel) 1364 { 1365 char *ptr; 1366 int i; 1367 boolean_t psoftlist_allocated = B_FALSE; 1368 1369 if (provname == NULL) { 1370 cryptoerror(LOG_STDERR, gettext("internal error.")); 1371 return (FAILURE); 1372 } 1373 1374 if (psoftlist_kernel == NULL) { 1375 if (get_soft_list(&psoftlist_kernel) == FAILURE) { 1376 cryptodebug("failed to get the software provider list" 1377 " from kernel."); 1378 return (FAILURE); 1379 } 1380 psoftlist_allocated = B_TRUE; 1381 } 1382 1383 *in_kernel = B_FALSE; 1384 ptr = psoftlist_kernel->sl_soft_names; 1385 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) { 1386 if (strcmp(provname, ptr) == 0) { 1387 *in_kernel = B_TRUE; 1388 break; 1389 } 1390 ptr = ptr + strlen(ptr) + 1; 1391 } 1392 1393 if (psoftlist_allocated) 1394 free(psoftlist_kernel); 1395 1396 return (SUCCESS); 1397 } 1398 1399 1400 /* 1401 * Check if a kernel hardware provider is in the kernel. 1402 * 1403 * Parameters: 1404 * provname Provider name 1405 * pdevlist Optional Hardware Crypto Device List. If NULL, it will be 1406 * obtained from get_dev_list(). 1407 * in_kernel Set to B_TRUE if device is in the kernel, otherwise B_FALSE 1408 */ 1409 int 1410 check_kernel_for_hard(char *provname, 1411 crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel) 1412 { 1413 char devname[MAXNAMELEN]; 1414 int inst_num; 1415 int i; 1416 boolean_t dev_list_allocated = B_FALSE; 1417 1418 if (provname == NULL) { 1419 cryptoerror(LOG_STDERR, gettext("internal error.")); 1420 return (FAILURE); 1421 } 1422 1423 if (split_hw_provname(provname, devname, &inst_num) == FAILURE) { 1424 return (FAILURE); 1425 } 1426 1427 if (pdevlist == NULL) { 1428 if (get_dev_list(&pdevlist) == FAILURE) { 1429 cryptoerror(LOG_STDERR, gettext("internal error.")); 1430 return (FAILURE); 1431 } 1432 dev_list_allocated = B_TRUE; 1433 } 1434 1435 *in_kernel = B_FALSE; 1436 for (i = 0; i < pdevlist->dl_dev_count; i++) { 1437 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) && 1438 (pdevlist->dl_devs[i].le_dev_instance == inst_num)) { 1439 *in_kernel = B_TRUE; 1440 break; 1441 } 1442 } 1443 1444 if (dev_list_allocated) 1445 free(pdevlist); 1446 1447 return (SUCCESS); 1448 } 1449