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