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