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