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