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