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 found_entry = B_FALSE; 922 FILE *pfile = NULL; 923 FILE *pfile_tmp = NULL; 924 char buffer[BUFSIZ]; 925 char buffer2[BUFSIZ]; 926 char tmpfile_name[MAXPATHLEN]; 927 char *name; 928 char *new_str = NULL; 929 int rc = SUCCESS; 930 931 if (pent == NULL) { 932 cryptoerror(LOG_STDERR, gettext("internal error.")); 933 return (FAILURE); 934 } 935 936 /* Check the update_mode */ 937 switch (update_mode) { 938 case ADD_MODE: 939 add_it = B_TRUE; 940 /* FALLTHROUGH */ 941 case MODIFY_MODE: 942 /* Convert the entry a string to add to kcf.conf */ 943 if ((new_str = ent2str(pent)) == NULL) { 944 return (FAILURE); 945 } 946 break; 947 case DELETE_MODE: 948 delete_it = B_TRUE; 949 break; 950 default: 951 cryptoerror(LOG_STDERR, gettext("internal error.")); 952 return (FAILURE); 953 } 954 955 /* Open the kcf.conf file */ 956 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { 957 err = errno; 958 cryptoerror(LOG_STDERR, 959 gettext("failed to update the configuration - %s"), 960 strerror(err)); 961 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); 962 return (FAILURE); 963 } 964 965 /* Lock the kcf.conf file */ 966 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 967 err = errno; 968 cryptoerror(LOG_STDERR, 969 gettext("failed to update the configuration - %s"), 970 strerror(err)); 971 (void) fclose(pfile); 972 return (FAILURE); 973 } 974 975 /* 976 * Create a temporary file in the /etc/crypto directory to save 977 * updated configuration file first. 978 */ 979 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 980 if (mkstemp(tmpfile_name) == -1) { 981 err = errno; 982 cryptoerror(LOG_STDERR, 983 gettext("failed to create a temporary file - %s"), 984 strerror(err)); 985 (void) fclose(pfile); 986 return (FAILURE); 987 } 988 989 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 990 err = errno; 991 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 992 tmpfile_name, strerror(err)); 993 (void) fclose(pfile); 994 return (FAILURE); 995 } 996 997 /* 998 * Loop thru the entire kcf.conf file, insert, modify or delete 999 * an entry. 1000 */ 1001 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 1002 if (add_it) { 1003 if (fputs(buffer, pfile_tmp) == EOF) { 1004 err = errno; 1005 cryptoerror(LOG_STDERR, gettext( 1006 "failed to write to a temp file: %s."), 1007 strerror(err)); 1008 rc = FAILURE; 1009 break; 1010 } 1011 1012 } else { /* modify or delete */ 1013 found_entry = B_FALSE; 1014 1015 if (!(buffer[0] == '#' || buffer[0] == ' ' || 1016 buffer[0] == '\n'|| buffer[0] == '\t')) { 1017 /* 1018 * Get the provider name from this line and 1019 * check if this is the entry to be updated 1020 * or deleted. Note: can not use "buffer" 1021 * directly because strtok will change its 1022 * value. 1023 */ 1024 (void) strlcpy(buffer2, buffer, BUFSIZ); 1025 if ((name = strtok(buffer2, SEP_COLON)) == 1026 NULL) { 1027 rc = FAILURE; 1028 break; 1029 } 1030 1031 if (strcmp(pent->name, name) == 0) { 1032 found_entry = B_TRUE; 1033 } 1034 } 1035 1036 if (found_entry && !delete_it) { 1037 /* 1038 * This is the entry to be updated; get the 1039 * updated string and place into buffer. 1040 */ 1041 (void) strlcpy(buffer, new_str, BUFSIZ); 1042 free(new_str); 1043 } 1044 1045 if (!(found_entry && delete_it)) { 1046 /* This is the entry to be updated/reserved */ 1047 if (fputs(buffer, pfile_tmp) == EOF) { 1048 err = errno; 1049 cryptoerror(LOG_STDERR, gettext( 1050 "failed to write to a temp file: " 1051 "%s."), strerror(err)); 1052 rc = FAILURE; 1053 break; 1054 } 1055 } 1056 } 1057 } 1058 1059 if ((!delete_it) && (rc != FAILURE)) { 1060 if (add_it || !found_entry) { 1061 /* append new entry to end of file */ 1062 if (fputs(new_str, pfile_tmp) == EOF) { 1063 err = errno; 1064 cryptoerror(LOG_STDERR, gettext( 1065 "failed to write to a temp file: %s."), 1066 strerror(err)); 1067 rc = FAILURE; 1068 } 1069 free(new_str); 1070 } 1071 } 1072 1073 (void) fclose(pfile); 1074 if (fclose(pfile_tmp) != 0) { 1075 err = errno; 1076 cryptoerror(LOG_STDERR, 1077 gettext("failed to close %s: %s"), tmpfile_name, 1078 strerror(err)); 1079 return (FAILURE); 1080 } 1081 1082 /* Copy the temporary file to the kcf.conf file */ 1083 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { 1084 err = errno; 1085 cryptoerror(LOG_STDERR, 1086 gettext("failed to update the configuration - %s"), 1087 strerror(err)); 1088 cryptodebug("failed to rename %s to %s: %s", tmpfile, 1089 _PATH_KCF_CONF, strerror(err)); 1090 rc = FAILURE; 1091 } else if (chmod(_PATH_KCF_CONF, 1092 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 1093 err = errno; 1094 cryptoerror(LOG_STDERR, 1095 gettext("failed to update the configuration - %s"), 1096 strerror(err)); 1097 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, 1098 strerror(err)); 1099 rc = FAILURE; 1100 } else { 1101 rc = SUCCESS; 1102 } 1103 1104 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { 1105 err = errno; 1106 cryptoerror(LOG_STDERR, gettext( 1107 "(Warning) failed to remove %s: %s"), 1108 tmpfile_name, strerror(err)); 1109 } 1110 1111 return (rc); 1112 } 1113 1114 1115 /* 1116 * Disable the mechanisms for the provider pointed by *ppent. If allflag is 1117 * TRUE, disable all. Otherwise, disable the mechanisms specified in the 1118 * dislist argument. The "infolist" argument contains the mechanism list 1119 * supported by this provider. 1120 */ 1121 int 1122 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag, 1123 mechlist_t *dislist) 1124 { 1125 entry_t *pent; 1126 mechlist_t *plist = NULL; 1127 mechlist_t *phead = NULL; 1128 mechlist_t *pmech = NULL; 1129 int rc = SUCCESS; 1130 1131 pent = *ppent; 1132 if (pent == NULL) { 1133 return (FAILURE); 1134 } 1135 1136 if (allflag) { 1137 free_mechlist(pent->dislist); 1138 pent->dis_count = get_mech_count(infolist); 1139 if (!(pent->dislist = dup_mechlist(infolist))) { 1140 return (FAILURE); 1141 } else { 1142 return (SUCCESS); 1143 } 1144 } 1145 1146 /* 1147 * Not disable all. Now loop thru the mechanisms specified in the 1148 * dislist. If the mechanism is not supported by the provider, 1149 * ignore it with a warning. If the mechanism is disabled already, 1150 * do nothing. Otherwise, prepend it to the beginning of the disabled 1151 * list of the provider. 1152 */ 1153 plist = dislist; 1154 while (plist != NULL) { 1155 if (!is_in_list(plist->name, infolist)) { 1156 cryptoerror(LOG_STDERR, gettext("(Warning) " 1157 "%1$s is not a valid mechanism for %2$s."), 1158 plist->name, pent->name); 1159 } else if (!is_in_list(plist->name, pent->dislist)) { 1160 /* Add this mechanism into the disabled list */ 1161 if ((pmech = create_mech(plist->name)) == NULL) { 1162 rc = FAILURE; 1163 break; 1164 } 1165 1166 if (pent->dislist == NULL) { 1167 pent->dislist = pmech; 1168 } else { 1169 phead = pent->dislist; 1170 pent->dislist = pmech; 1171 pmech->next = phead; 1172 } 1173 pent->dis_count++; 1174 } 1175 plist = plist->next; 1176 } 1177 1178 return (rc); 1179 } 1180 1181 /* 1182 * Remove the mechanism passed, specified by mech, from the list of 1183 * mechanisms, if present in the list. Else, do nothing. 1184 * 1185 * Returns B_TRUE if mechanism is present in the list. 1186 */ 1187 boolean_t 1188 filter_mechlist(mechlist_t **pmechlist, const char *mech) 1189 { 1190 int cnt = 0; 1191 mechlist_t *ptr, *pptr; 1192 boolean_t mech_present = B_FALSE; 1193 1194 ptr = pptr = *pmechlist; 1195 1196 while (ptr != NULL) { 1197 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) { 1198 mech_present = B_TRUE; 1199 if (ptr == *pmechlist) { 1200 pptr = *pmechlist = ptr->next; 1201 free(ptr); 1202 ptr = pptr; 1203 } else { 1204 pptr->next = ptr->next; 1205 free(ptr); 1206 ptr = pptr->next; 1207 } 1208 } else { 1209 pptr = ptr; 1210 ptr = ptr->next; 1211 cnt++; 1212 } 1213 } 1214 1215 /* Only one entry is present */ 1216 if (cnt == 0) 1217 *pmechlist = NULL; 1218 1219 return (mech_present); 1220 } 1221 1222 1223 1224 /* 1225 * Print out the mechanism policy for a kernel provider that has an entry 1226 * in the kcf.conf file. 1227 * 1228 * The flag has_random is set to B_TRUE if the provider does random 1229 * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider 1230 * has some mechanisms. 1231 * 1232 * If pent is NULL, the provider doesn't have a kcf.conf entry. 1233 */ 1234 void 1235 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, 1236 boolean_t has_mechs) 1237 { 1238 mechlist_t *ptr = NULL; 1239 boolean_t rnd_disabled = B_FALSE; 1240 1241 if (pent != NULL) { 1242 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM); 1243 ptr = pent->dislist; 1244 } 1245 1246 (void) printf("%s:", provname); 1247 1248 if (has_mechs == B_TRUE) { 1249 /* 1250 * TRANSLATION_NOTE 1251 * This code block may need to be modified a bit to avoid 1252 * constructing the text message on the fly. 1253 */ 1254 (void) printf(gettext(" all mechanisms are enabled")); 1255 if (ptr != NULL) 1256 (void) printf(gettext(", except ")); 1257 while (ptr != NULL) { 1258 (void) printf("%s", ptr->name); 1259 ptr = ptr->next; 1260 if (ptr != NULL) 1261 (void) printf(","); 1262 } 1263 if (ptr == NULL) 1264 (void) printf("."); 1265 } 1266 1267 /* 1268 * TRANSLATION_NOTE 1269 * "random" is a keyword and not to be translated. 1270 */ 1271 if (rnd_disabled) 1272 (void) printf(gettext(" %s is disabled."), "random"); 1273 else if (has_random) 1274 (void) printf(gettext(" %s is enabled."), "random"); 1275 (void) printf("\n"); 1276 } 1277 1278 1279 /* 1280 * Check if a kernel software provider is in the kernel. 1281 * 1282 * Parameters: 1283 * provname Provider name 1284 * psoftlist_kernel Optional software provider list. If NULL, it will be 1285 * obtained from get_soft_list(). 1286 * in_kernel Set to B_TRUE if device is in the kernel, else B_FALSE 1287 */ 1288 int 1289 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel, 1290 boolean_t *in_kernel) 1291 { 1292 char *ptr; 1293 int i; 1294 boolean_t psoftlist_allocated = B_FALSE; 1295 1296 if (provname == NULL) { 1297 cryptoerror(LOG_STDERR, gettext("internal error.")); 1298 return (FAILURE); 1299 } 1300 1301 if (psoftlist_kernel == NULL) { 1302 if (get_soft_list(&psoftlist_kernel) == FAILURE) { 1303 cryptodebug("failed to get the software provider list" 1304 " from kernel."); 1305 return (FAILURE); 1306 } 1307 psoftlist_allocated = B_TRUE; 1308 } 1309 1310 *in_kernel = B_FALSE; 1311 ptr = psoftlist_kernel->sl_soft_names; 1312 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) { 1313 if (strcmp(provname, ptr) == 0) { 1314 *in_kernel = B_TRUE; 1315 break; 1316 } 1317 ptr = ptr + strlen(ptr) + 1; 1318 } 1319 1320 if (psoftlist_allocated) 1321 free(psoftlist_kernel); 1322 1323 return (SUCCESS); 1324 } 1325 1326 1327 /* 1328 * Check if a kernel hardware provider is in the kernel. 1329 * 1330 * Parameters: 1331 * provname Provider name 1332 * pdevlist Optional Hardware Crypto Device List. If NULL, it will be 1333 * obtained from get_dev_list(). 1334 * in_kernel Set to B_TRUE if device is in the kernel, otherwise B_FALSE 1335 */ 1336 int 1337 check_kernel_for_hard(char *provname, 1338 crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel) 1339 { 1340 char devname[MAXNAMELEN]; 1341 int inst_num; 1342 int i; 1343 boolean_t dev_list_allocated = B_FALSE; 1344 1345 if (provname == NULL) { 1346 cryptoerror(LOG_STDERR, gettext("internal error.")); 1347 return (FAILURE); 1348 } 1349 1350 if (split_hw_provname(provname, devname, &inst_num) == FAILURE) { 1351 return (FAILURE); 1352 } 1353 1354 if (pdevlist == NULL) { 1355 if (get_dev_list(&pdevlist) == FAILURE) { 1356 cryptoerror(LOG_STDERR, gettext("internal error.")); 1357 return (FAILURE); 1358 } 1359 dev_list_allocated = B_TRUE; 1360 } 1361 1362 *in_kernel = B_FALSE; 1363 for (i = 0; i < pdevlist->dl_dev_count; i++) { 1364 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) && 1365 (pdevlist->dl_devs[i].le_dev_instance == inst_num)) { 1366 *in_kernel = B_TRUE; 1367 break; 1368 } 1369 } 1370 1371 if (dev_list_allocated) 1372 free(pdevlist); 1373 1374 return (SUCCESS); 1375 } 1376