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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <strings.h> 32 #include <unistd.h> 33 #include <locale.h> 34 #include <libgen.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/crypto/ioctladmin.h> 38 #include <signal.h> 39 #include <sys/crypto/elfsign.h> 40 #include "cryptoadm.h" 41 42 static int err; /* to store the value of errno in case being overwritten */ 43 static int check_hardware_provider(char *, char *, int *, int *); 44 45 /* 46 * Display the mechanism list for a kernel software provider. 47 */ 48 int 49 list_mechlist_for_soft(char *provname) 50 { 51 mechlist_t *pmechlist; 52 int rc; 53 54 if (provname == NULL) { 55 return (FAILURE); 56 } 57 58 rc = get_soft_info(provname, &pmechlist); 59 if (rc == SUCCESS) { 60 (void) filter_mechlist(&pmechlist, RANDOM); 61 print_mechlist(provname, pmechlist); 62 free_mechlist(pmechlist); 63 } else { 64 cryptoerror(LOG_STDERR, gettext( 65 "failed to retrieve the mechanism list for %s."), 66 provname); 67 } 68 69 return (rc); 70 71 } 72 73 /* 74 * Display the mechanism list for a kernel hardware provider. 75 */ 76 int 77 list_mechlist_for_hard(char *provname) 78 { 79 mechlist_t *pmechlist; 80 char devname[MAXNAMELEN]; 81 int inst_num; 82 int count; 83 int rc = SUCCESS; 84 85 if (provname == NULL) { 86 return (FAILURE); 87 } 88 89 /* 90 * Check if the provider is valid. If it is valid, get the number of 91 * mechanisms also. 92 */ 93 if (check_hardware_provider(provname, devname, &inst_num, &count) == 94 FAILURE) { 95 return (FAILURE); 96 } 97 98 /* Get the mechanism list for the kernel hardware provider */ 99 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == 100 SUCCESS) { 101 (void) filter_mechlist(&pmechlist, RANDOM); 102 print_mechlist(provname, pmechlist); 103 free_mechlist(pmechlist); 104 } 105 106 return (rc); 107 } 108 109 110 /* 111 * Display the policy information for a kernel software provider. 112 */ 113 int 114 list_policy_for_soft(char *provname) 115 { 116 int rc; 117 entry_t *pent = NULL; 118 mechlist_t *pmechlist; 119 boolean_t has_random = B_FALSE; 120 boolean_t has_mechs = B_FALSE; 121 122 if (provname == NULL) { 123 return (FAILURE); 124 } 125 126 if ((pent = getent_kef(provname)) == NULL) { 127 cryptoerror(LOG_STDERR, gettext("%s does not exist."), 128 provname); 129 return (FAILURE); 130 } 131 132 rc = get_soft_info(provname, &pmechlist); 133 if (rc == SUCCESS) { 134 has_random = filter_mechlist(&pmechlist, RANDOM); 135 if (pmechlist != NULL) { 136 has_mechs = B_TRUE; 137 free_mechlist(pmechlist); 138 } 139 } else { 140 cryptoerror(LOG_STDERR, gettext( 141 "failed to retrieve the mechanism list for %s."), 142 provname); 143 return (rc); 144 } 145 146 print_kef_policy(pent, has_random, has_mechs); 147 free_entry(pent); 148 return (SUCCESS); 149 } 150 151 152 153 /* 154 * Display the policy information for a kernel hardware provider. 155 */ 156 int 157 list_policy_for_hard(char *provname) 158 { 159 entry_t *pent; 160 boolean_t is_active; 161 mechlist_t *pmechlist; 162 char devname[MAXNAMELEN]; 163 int inst_num; 164 int count; 165 int rc = SUCCESS; 166 boolean_t has_random = B_FALSE; 167 boolean_t has_mechs = B_FALSE; 168 169 if (provname == NULL) { 170 return (FAILURE); 171 } 172 173 /* 174 * Check if the provider is valid. If it is valid, get the number of 175 * mechanisms also. 176 */ 177 if (check_hardware_provider(provname, devname, &inst_num, &count) == 178 FAILURE) { 179 return (FAILURE); 180 } 181 182 /* Get the mechanism list for the kernel hardware provider */ 183 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == 184 SUCCESS) { 185 has_random = filter_mechlist(&pmechlist, RANDOM); 186 187 if (pmechlist != NULL) { 188 has_mechs = B_TRUE; 189 free_mechlist(pmechlist); 190 } 191 } else { 192 cryptoerror(LOG_STDERR, gettext( 193 "failed to retrieve the mechanism list for %s."), 194 devname); 195 return (rc); 196 } 197 198 /* 199 * If the hardware provider has an entry in the kcf.conf file, 200 * some of its mechanisms must have been disabled. Print out 201 * the disabled list from the config file entry. Otherwise, 202 * if it is active, then all the mechanisms for it are enabled. 203 */ 204 if ((pent = getent_kef(provname)) != NULL) { 205 print_kef_policy(pent, has_random, has_mechs); 206 free_entry(pent); 207 return (SUCCESS); 208 } else { 209 if (check_active_for_hard(provname, &is_active) == 210 FAILURE) { 211 return (FAILURE); 212 } else if (is_active == B_TRUE) { 213 (void) printf(gettext( 214 "%s: all mechanisms are enabled."), provname); 215 if (has_random) 216 /* 217 * TRANSLATION_NOTE: 218 * "random" is a keyword and not to be 219 * translated. 220 */ 221 (void) printf(gettext(" %s is enabled.\n"), 222 "random"); 223 else 224 (void) printf("\n"); 225 return (SUCCESS); 226 } else { 227 cryptoerror(LOG_STDERR, 228 gettext("%s does not exist."), provname); 229 return (FAILURE); 230 } 231 } 232 } 233 234 235 236 int 237 disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag, 238 mechlist_t *dislist) 239 { 240 crypto_load_dev_disabled_t *pload_dev_dis; 241 mechlist_t *infolist; 242 entry_t *pent; 243 boolean_t new_dev_entry = B_FALSE; 244 char devname[MAXNAMELEN]; 245 int inst_num; 246 int count; 247 int fd; 248 int rc = SUCCESS; 249 250 if (provname == NULL) { 251 return (FAILURE); 252 } 253 254 /* 255 * Check if the provider is valid. If it is valid, get the number of 256 * mechanisms also. 257 */ 258 if (check_hardware_provider(provname, devname, &inst_num, &count) 259 == FAILURE) { 260 return (FAILURE); 261 } 262 263 /* Get the mechanism list for the kernel hardware provider */ 264 if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) { 265 return (FAILURE); 266 } 267 268 /* 269 * Get the entry of this hardware provider from the config file. 270 * If there is no entry yet, create one for it. 271 */ 272 if ((pent = getent_kef(provname)) == NULL) { 273 if ((pent = malloc(sizeof (entry_t))) == NULL) { 274 cryptoerror(LOG_STDERR, gettext("out of memory.")); 275 free_mechlist(infolist); 276 return (FAILURE); 277 } 278 new_dev_entry = B_TRUE; 279 (void) strlcpy(pent->name, provname, MAXNAMELEN); 280 pent->suplist = NULL; 281 pent->sup_count = 0; 282 pent->dislist = NULL; 283 pent->dis_count = 0; 284 } 285 286 /* 287 * kCF treats random as an internal mechanism. So, we need to 288 * filter it from the mechanism list here, if we are NOT disabling 289 * or enabling the random feature. Note that we map random feature at 290 * cryptoadm(1M) level to the "random" mechanism in kCF. 291 */ 292 if (!rndflag) { 293 (void) filter_mechlist(&infolist, RANDOM); 294 } 295 296 /* Calculate the new disabled list */ 297 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { 298 free_entry(pent); 299 return (FAILURE); 300 } 301 302 /* If no mechanisms are to be disabled, return */ 303 if (pent->dis_count == 0) { 304 free_entry(pent); 305 return (SUCCESS); 306 } 307 308 /* Update the config file with the new entry or the updated entry */ 309 if (new_dev_entry) { 310 rc = update_kcfconf(pent, ADD_MODE); 311 } else { 312 rc = update_kcfconf(pent, MODIFY_MODE); 313 } 314 315 if (rc == FAILURE) { 316 free_entry(pent); 317 return (FAILURE); 318 } 319 320 /* Inform kernel about the new disabled mechanism list */ 321 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { 322 free_entry(pent); 323 return (FAILURE); 324 } 325 free_entry(pent); 326 327 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 328 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 329 ADMIN_IOCTL_DEVICE, strerror(errno)); 330 free(pload_dev_dis); 331 return (FAILURE); 332 } 333 334 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { 335 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s", 336 strerror(errno)); 337 free(pload_dev_dis); 338 (void) close(fd); 339 return (FAILURE); 340 } 341 342 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { 343 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = " 344 "%d", pload_dev_dis->dd_return_value); 345 free(pload_dev_dis); 346 (void) close(fd); 347 return (FAILURE); 348 } 349 350 free(pload_dev_dis); 351 (void) close(fd); 352 return (SUCCESS); 353 } 354 355 356 357 int 358 disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag, 359 mechlist_t *dislist) 360 { 361 crypto_load_soft_disabled_t *pload_soft_dis = NULL; 362 mechlist_t *infolist; 363 entry_t *pent; 364 boolean_t is_active; 365 int fd; 366 367 if (provname == NULL) { 368 return (FAILURE); 369 } 370 371 /* Get the entry of this provider from the config file. */ 372 if ((pent = getent_kef(provname)) == NULL) { 373 cryptoerror(LOG_STDERR, 374 gettext("%s does not exist."), provname); 375 return (FAILURE); 376 } 377 378 /* 379 * Check if the kernel software provider is currently unloaded. 380 * If it is unloaded, return FAILURE, because the disable subcommand 381 * can not perform on inactive (unloaded) providers. 382 */ 383 if (check_active_for_soft(provname, &is_active) == FAILURE) { 384 free_entry(pent); 385 return (FAILURE); 386 } else if (is_active == B_FALSE) { 387 /* 388 * TRANSLATION_NOTE: 389 * "disable" is a keyword and not to be translated. 390 */ 391 cryptoerror(LOG_STDERR, 392 gettext("can not do %1$s on an unloaded " 393 "kernel software provider -- %2$s."), "disable", provname); 394 free_entry(pent); 395 return (FAILURE); 396 } 397 398 /* Get the mechanism list for the software provider */ 399 if (get_soft_info(provname, &infolist) == FAILURE) { 400 free(pent); 401 return (FAILURE); 402 } 403 404 /* See comments in disable_kef_hardware() */ 405 if (!rndflag) { 406 (void) filter_mechlist(&infolist, RANDOM); 407 } 408 409 /* Calculate the new disabled list */ 410 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { 411 free_entry(pent); 412 free_mechlist(infolist); 413 return (FAILURE); 414 } 415 416 /* infolist is no longer needed; free it */ 417 free_mechlist(infolist); 418 419 /* Update the kcf.conf file with the updated entry */ 420 if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) { 421 free_entry(pent); 422 return (FAILURE); 423 } 424 425 /* Inform kernel about the new disabled list. */ 426 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { 427 free_entry(pent); 428 return (FAILURE); 429 } 430 431 /* pent is no longer needed; free it. */ 432 free_entry(pent); 433 434 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 435 cryptoerror(LOG_STDERR, 436 gettext("failed to open %s for RW: %s"), 437 ADMIN_IOCTL_DEVICE, strerror(errno)); 438 free(pload_soft_dis); 439 return (FAILURE); 440 } 441 442 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { 443 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", 444 strerror(errno)); 445 free(pload_soft_dis); 446 (void) close(fd); 447 return (FAILURE); 448 } 449 450 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { 451 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " 452 "%d", pload_soft_dis->sd_return_value); 453 free(pload_soft_dis); 454 (void) close(fd); 455 return (FAILURE); 456 } 457 458 free(pload_soft_dis); 459 (void) close(fd); 460 return (SUCCESS); 461 } 462 463 464 int 465 enable_kef(char *provname, boolean_t rndflag, boolean_t allflag, 466 mechlist_t *mlist) 467 { 468 crypto_load_soft_disabled_t *pload_soft_dis = NULL; 469 crypto_load_dev_disabled_t *pload_dev_dis = NULL; 470 entry_t *pent; 471 boolean_t redo_flag = B_FALSE; 472 int fd; 473 int rc = SUCCESS; 474 475 476 /* Get the entry with the provider name from the kcf.conf file */ 477 pent = getent_kef(provname); 478 479 if (is_device(provname)) { 480 if (pent == NULL) { 481 /* 482 * This device doesn't have an entry in the config 483 * file, therefore nothing is disabled. 484 */ 485 cryptoerror(LOG_STDERR, gettext( 486 "all mechanisms are enabled already for %s."), 487 provname); 488 return (SUCCESS); 489 } 490 } else { /* a software module */ 491 if (pent == NULL) { 492 cryptoerror(LOG_STDERR, 493 gettext("%s does not exist."), provname); 494 return (FAILURE); 495 } else if (pent->dis_count == 0) { 496 /* nothing to be enabled. */ 497 cryptoerror(LOG_STDERR, gettext( 498 "all mechanisms are enabled already for %s."), 499 provname); 500 free_entry(pent); 501 return (SUCCESS); 502 } 503 } 504 505 if (!rndflag) { 506 /* See comments in disable_kef_hardware() */ 507 redo_flag = filter_mechlist(&pent->dislist, RANDOM); 508 if (redo_flag) 509 pent->dis_count--; 510 } 511 512 /* Update the entry by enabling mechanisms for this provider */ 513 if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) { 514 free_entry(pent); 515 return (rc); 516 } 517 518 if (redo_flag) { 519 mechlist_t *tmp; 520 521 if ((tmp = create_mech(RANDOM)) == NULL) { 522 free_entry(pent); 523 return (FAILURE); 524 } 525 tmp->next = pent->dislist; 526 pent->dislist = tmp; 527 pent->dis_count++; 528 } 529 530 /* 531 * Update the kcf.conf file with the updated entry. 532 * For a hardware provider, if there is no more disabled mechanism, 533 * the entire entry in the config file should be removed. 534 */ 535 if (is_device(pent->name) && (pent->dis_count == 0)) { 536 rc = update_kcfconf(pent, DELETE_MODE); 537 } else { 538 rc = update_kcfconf(pent, MODIFY_MODE); 539 } 540 541 if (rc == FAILURE) { 542 free_entry(pent); 543 return (FAILURE); 544 } 545 546 547 /* Inform Kernel about the policy change */ 548 549 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 550 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 551 ADMIN_IOCTL_DEVICE, strerror(errno)); 552 return (FAILURE); 553 } 554 555 if (is_device(provname)) { 556 /* LOAD_DEV_DISABLED */ 557 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { 558 return (FAILURE); 559 } 560 561 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { 562 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: " 563 "%s", strerror(errno)); 564 free(pload_dev_dis); 565 (void) close(fd); 566 return (FAILURE); 567 } 568 569 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { 570 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " 571 "return_value = %d", 572 pload_dev_dis->dd_return_value); 573 free(pload_dev_dis); 574 (void) close(fd); 575 return (FAILURE); 576 } 577 578 } else { 579 /* LOAD_SOFT_DISABLED */ 580 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { 581 return (FAILURE); 582 } 583 584 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) 585 == -1) { 586 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: " 587 "%s", strerror(errno)); 588 free(pload_soft_dis); 589 (void) close(fd); 590 return (FAILURE); 591 } 592 593 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { 594 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " 595 "return_value = %d", 596 pload_soft_dis->sd_return_value); 597 free(pload_soft_dis); 598 (void) close(fd); 599 return (FAILURE); 600 } 601 } 602 603 (void) close(fd); 604 return (SUCCESS); 605 } 606 607 608 /* 609 * Install a software module with the specified mechanism list into the system. 610 * This routine adds an entry into the config file for this software module 611 * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel 612 * about the new addition. 613 */ 614 int 615 install_kef(char *provname, mechlist_t *mlist) 616 { 617 crypto_load_soft_config_t *pload_soft_conf = NULL; 618 boolean_t found; 619 entry_t *pent; 620 FILE *pfile; 621 FILE *pfile_tmp; 622 char tmpfile_name[MAXPATHLEN]; 623 char *ptr; 624 char *str; 625 char *name; 626 char buffer[BUFSIZ]; 627 char buffer2[BUFSIZ]; 628 int found_count; 629 int fd; 630 int rc = SUCCESS; 631 632 if ((provname == NULL) || (mlist == NULL)) { 633 return (FAILURE); 634 } 635 636 /* Check if the provider already exists */ 637 if ((pent = getent_kef(provname)) != NULL) { 638 cryptoerror(LOG_STDERR, gettext("%s exists already."), 639 provname); 640 free_entry(pent); 641 return (FAILURE); 642 } 643 644 /* Create an entry with provname and mlist. */ 645 if ((pent = malloc(sizeof (entry_t))) == NULL) { 646 cryptoerror(LOG_STDERR, gettext("out of memory.")); 647 return (FAILURE); 648 } 649 650 (void) strlcpy(pent->name, provname, MAXNAMELEN); 651 pent->sup_count = get_mech_count(mlist); 652 pent->suplist = mlist; 653 pent->dis_count = 0; 654 pent->dislist = NULL; 655 656 /* Append an entry for this software module to the kcf.conf file. */ 657 if ((str = ent2str(pent)) == NULL) { 658 free_entry(pent); 659 return (FAILURE); 660 } 661 662 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { 663 err = errno; 664 cryptoerror(LOG_STDERR, 665 gettext("failed to update the configuration - %s"), 666 strerror(err)); 667 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); 668 free_entry(pent); 669 return (FAILURE); 670 } 671 672 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 673 err = errno; 674 cryptoerror(LOG_STDERR, 675 gettext("failed to lock the configuration - %s"), 676 strerror(err)); 677 free_entry(pent); 678 (void) fclose(pfile); 679 return (FAILURE); 680 } 681 682 /* 683 * Create a temporary file in the /etc/crypto directory. 684 */ 685 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 686 if (mkstemp(tmpfile_name) == -1) { 687 err = errno; 688 cryptoerror(LOG_STDERR, 689 gettext("failed to create a temporary file - %s"), 690 strerror(err)); 691 free_entry(pent); 692 (void) fclose(pfile); 693 return (FAILURE); 694 } 695 696 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 697 err = errno; 698 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 699 tmpfile_name, strerror(err)); 700 free_entry(pent); 701 (void) fclose(pfile); 702 return (FAILURE); 703 } 704 705 706 /* 707 * Loop thru the config file. If the provider was reserved within a 708 * package bracket, just uncomment it. Otherwise, append it at 709 * the end. The resulting file will be saved in the temp file first. 710 */ 711 found_count = 0; 712 rc = SUCCESS; 713 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 714 found = B_FALSE; 715 if (buffer[0] == '#') { 716 (void) strlcpy(buffer2, buffer, BUFSIZ); 717 ptr = buffer2; 718 ptr++; 719 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 720 rc = FAILURE; 721 break; 722 } else if (strcmp(provname, name) == 0) { 723 found = B_TRUE; 724 found_count++; 725 } 726 } 727 728 if (found == B_FALSE) { 729 if (fputs(buffer, pfile_tmp) == EOF) { 730 rc = FAILURE; 731 } 732 } else { 733 if (found_count == 1) { 734 if (fputs(str, pfile_tmp) == EOF) { 735 rc = FAILURE; 736 } 737 } else { 738 /* 739 * Found a second entry with #libname. 740 * Should not happen. The kcf.conf ffile 741 * is corrupted. Give a warning and skip 742 * this entry. 743 */ 744 cryptoerror(LOG_STDERR, gettext( 745 "(Warning) Found an additional reserved " 746 "entry for %s."), provname); 747 } 748 } 749 750 if (rc == FAILURE) { 751 break; 752 } 753 } 754 (void) fclose(pfile); 755 756 if (rc == FAILURE) { 757 cryptoerror(LOG_STDERR, gettext("write error.")); 758 (void) fclose(pfile_tmp); 759 if (unlink(tmpfile_name) != 0) { 760 err = errno; 761 cryptoerror(LOG_STDERR, gettext( 762 "(Warning) failed to remove %s: %s"), tmpfile_name, 763 strerror(err)); 764 } 765 free_entry(pent); 766 return (FAILURE); 767 } 768 769 if (found_count == 0) { 770 /* 771 * This libname was not in package before, append it to the 772 * end of the temp file. 773 */ 774 if (fputs(str, pfile_tmp) == EOF) { 775 cryptoerror(LOG_STDERR, gettext( 776 "failed to write to %s: %s"), tmpfile_name, 777 strerror(errno)); 778 (void) fclose(pfile_tmp); 779 if (unlink(tmpfile_name) != 0) { 780 err = errno; 781 cryptoerror(LOG_STDERR, gettext( 782 "(Warning) failed to remove %s: %s"), 783 tmpfile_name, strerror(err)); 784 } 785 free_entry(pent); 786 return (FAILURE); 787 } 788 } 789 790 if (fclose(pfile_tmp) != 0) { 791 err = errno; 792 cryptoerror(LOG_STDERR, 793 gettext("failed to close %s: %s"), tmpfile_name, 794 strerror(err)); 795 return (FAILURE); 796 } 797 798 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { 799 err = errno; 800 cryptoerror(LOG_STDERR, 801 gettext("failed to update the configuration - %s"), 802 strerror(err)); 803 cryptodebug("failed to rename %s to %s: %s", tmpfile_name, 804 _PATH_KCF_CONF, strerror(err)); 805 rc = FAILURE; 806 } else if (chmod(_PATH_KCF_CONF, 807 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 808 err = errno; 809 cryptoerror(LOG_STDERR, 810 gettext("failed to update the configuration - %s"), 811 strerror(err)); 812 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, 813 strerror(err)); 814 rc = FAILURE; 815 } else { 816 rc = SUCCESS; 817 } 818 819 if (rc == FAILURE) { 820 if (unlink(tmpfile_name) != 0) { 821 err = errno; 822 cryptoerror(LOG_STDERR, gettext( 823 "(Warning) failed to remove %s: %s"), 824 tmpfile_name, strerror(err)); 825 } 826 return (FAILURE); 827 } 828 829 830 /* Inform kernel of this new software module. */ 831 832 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { 833 free_entry(pent); 834 return (FAILURE); 835 } 836 837 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 838 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 839 ADMIN_IOCTL_DEVICE, strerror(errno)); 840 free_entry(pent); 841 free(pload_soft_conf); 842 return (FAILURE); 843 } 844 845 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { 846 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", 847 strerror(errno)); 848 free_entry(pent); 849 free(pload_soft_conf); 850 (void) close(fd); 851 return (FAILURE); 852 } 853 854 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { 855 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, " 856 "return_value = %d", pload_soft_conf->sc_return_value); 857 free_entry(pent); 858 free(pload_soft_conf); 859 (void) close(fd); 860 return (FAILURE); 861 } 862 863 free_entry(pent); 864 free(pload_soft_conf); 865 (void) close(fd); 866 return (SUCCESS); 867 } 868 869 /* 870 * Uninstall the software module. This routine first unloads the software 871 * module with 3 ioctl calls, then deletes its entry from the config file. 872 * Removing an entry from the config file needs to be done last to ensure 873 * that there is still an entry if the earlier unload failed for any reason. 874 */ 875 int 876 uninstall_kef(char *provname) 877 { 878 entry_t *pent; 879 boolean_t is_active; 880 boolean_t in_package; 881 boolean_t found; 882 FILE *pfile; 883 FILE *pfile_tmp; 884 char tmpfile_name[MAXPATHLEN]; 885 char *name; 886 char strbuf[BUFSIZ]; 887 char buffer[BUFSIZ]; 888 char buffer2[BUFSIZ]; 889 char *str; 890 int len; 891 int rc = SUCCESS; 892 893 894 /* Check if it is in the kcf.conf file first. */ 895 if ((pent = getent_kef(provname)) == NULL) { 896 cryptoerror(LOG_STDERR, 897 gettext("%s does not exist."), provname); 898 return (FAILURE); 899 } 900 901 902 /* 903 * Get rid of the disabled list for the provider and get the converted 904 * string for the entry. This is to prepare the string for a provider 905 * that is in a package. 906 */ 907 free_mechlist(pent->dislist); 908 pent->dis_count = 0; 909 pent->dislist = NULL; 910 str = ent2str(pent); 911 free_entry(pent); 912 if (str == NULL) { 913 cryptoerror(LOG_STDERR, gettext("internal error.")); 914 return (FAILURE); 915 } 916 (void) snprintf(strbuf, sizeof (strbuf), "%s%s", "#", str); 917 free(str); 918 919 /* If it is not loaded, unload it first */ 920 if (check_active_for_soft(provname, &is_active) == FAILURE) { 921 return (FAILURE); 922 } else if ((is_active == B_TRUE) && 923 (unload_kef_soft(provname, B_TRUE) == FAILURE)) { 924 cryptoerror(LOG_STDERR, 925 gettext("failed to uninstall %s.\n"), provname); 926 return (FAILURE); 927 } 928 929 /* 930 * Remove the entry from the config file. If the provider to be 931 * uninstalled is in a package, just comment it off. 932 */ 933 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { 934 err = errno; 935 cryptoerror(LOG_STDERR, 936 gettext("failed to update the configuration - %s"), 937 strerror(err)); 938 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); 939 return (FAILURE); 940 } 941 942 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 943 err = errno; 944 cryptoerror(LOG_STDERR, 945 gettext("failed to lock the configuration - %s"), 946 strerror(err)); 947 (void) fclose(pfile); 948 return (FAILURE); 949 } 950 951 /* 952 * Create a temporary file in the /etc/crypto directory to save 953 * the new configuration file first. 954 */ 955 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 956 if (mkstemp(tmpfile_name) == -1) { 957 err = errno; 958 cryptoerror(LOG_STDERR, 959 gettext("failed to create a temporary file - %s"), 960 strerror(err)); 961 (void) fclose(pfile); 962 return (FAILURE); 963 } 964 965 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 966 err = errno; 967 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 968 tmpfile_name, strerror(err)); 969 if (unlink(tmpfile_name) != 0) { 970 err = errno; 971 cryptoerror(LOG_STDERR, gettext( 972 "(Warning) failed to remove %s: %s"), tmpfile_name, 973 strerror(err)); 974 } 975 (void) fclose(pfile); 976 return (FAILURE); 977 } 978 979 /* 980 * Loop thru the config file. If the kernel software provider 981 * to be uninstalled is in a package, just comment it off. 982 */ 983 in_package = B_FALSE; 984 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 985 found = B_FALSE; 986 if (!(buffer[0] == ' ' || buffer[0] == '\n' || 987 buffer[0] == '\t')) { 988 if (strstr(buffer, " Start ") != NULL) { 989 in_package = B_TRUE; 990 } else if (strstr(buffer, " End ") != NULL) { 991 in_package = B_FALSE; 992 } else if (buffer[0] != '#') { 993 (void) strlcpy(buffer2, buffer, BUFSIZ); 994 995 /* get rid of trailing '\n' */ 996 len = strlen(buffer2); 997 if (buffer2[len-1] == '\n') { 998 len--; 999 } 1000 buffer2[len] = '\0'; 1001 1002 if ((name = strtok(buffer2, SEP_COLON)) 1003 == NULL) { 1004 rc = FAILURE; 1005 break; 1006 } else if (strcmp(provname, name) == 0) { 1007 found = B_TRUE; 1008 } 1009 } 1010 } 1011 1012 if (found) { 1013 if (in_package) { 1014 if (fputs(strbuf, pfile_tmp) == EOF) { 1015 rc = FAILURE; 1016 } 1017 } 1018 } else { 1019 if (fputs(buffer, pfile_tmp) == EOF) { 1020 rc = FAILURE; 1021 } 1022 } 1023 1024 if (rc == FAILURE) { 1025 break; 1026 } 1027 } 1028 1029 if (rc == FAILURE) { 1030 cryptoerror(LOG_STDERR, gettext("write error.")); 1031 (void) fclose(pfile); 1032 (void) fclose(pfile_tmp); 1033 if (unlink(tmpfile_name) != 0) { 1034 err = errno; 1035 cryptoerror(LOG_STDERR, gettext( 1036 "(Warning) failed to remove %s: %s"), tmpfile_name, 1037 strerror(err)); 1038 } 1039 return (FAILURE); 1040 } 1041 1042 (void) fclose(pfile); 1043 if (fclose(pfile_tmp) != 0) { 1044 err = errno; 1045 cryptoerror(LOG_STDERR, 1046 gettext("failed to close %s: %s"), tmpfile_name, 1047 strerror(err)); 1048 return (FAILURE); 1049 } 1050 1051 /* Now update the real config file */ 1052 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { 1053 err = errno; 1054 cryptoerror(LOG_STDERR, 1055 gettext("failed to update the configuration - %s"), 1056 strerror(err)); 1057 cryptodebug("failed to rename %1$s to %2$s: %3$s", tmpfile, 1058 _PATH_KCF_CONF, strerror(err)); 1059 rc = FAILURE; 1060 } else if (chmod(_PATH_KCF_CONF, 1061 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 1062 err = errno; 1063 cryptoerror(LOG_STDERR, 1064 gettext("failed to update the configuration - %s"), 1065 strerror(err)); 1066 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, 1067 strerror(err)); 1068 rc = FAILURE; 1069 } else { 1070 rc = SUCCESS; 1071 } 1072 1073 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { 1074 err = errno; 1075 cryptoerror(LOG_STDERR, gettext( 1076 "(Warning) failed to remove %s: %s"), tmpfile_name, 1077 strerror(err)); 1078 } 1079 1080 return (rc); 1081 1082 } 1083 1084 1085 int 1086 refresh(void) 1087 { 1088 crypto_get_soft_list_t *psoftlist_kernel = NULL; 1089 crypto_load_soft_config_t *pload_soft_conf = NULL; 1090 crypto_load_soft_disabled_t *pload_soft_dis = NULL; 1091 crypto_load_dev_disabled_t *pload_dev_dis = NULL; 1092 entrylist_t *pdevlist = NULL; 1093 entrylist_t *psoftlist = NULL; 1094 entrylist_t *ptr; 1095 boolean_t found; 1096 char *psoftname; 1097 int fd; 1098 int rc = SUCCESS; 1099 int i; 1100 1101 if (get_soft_list(&psoftlist_kernel) == FAILURE) { 1102 cryptoerror(LOG_ERR, gettext("Failed to retrieve the " 1103 "software provider list from kernel.")); 1104 return (FAILURE); 1105 } 1106 1107 if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) { 1108 cryptoerror(LOG_ERR, "failed to retrieve the providers' " 1109 "information from the configuration file - %s.", 1110 _PATH_KCF_CONF); 1111 return (FAILURE); 1112 } 1113 1114 /* 1115 * If a kernel software provider is in kernel, but it is not in the 1116 * kcf.conf file, it must have been pkgrm'ed and needs to be unloaded 1117 * now. 1118 */ 1119 if (psoftlist_kernel->sl_soft_count > 0) { 1120 psoftname = psoftlist_kernel->sl_soft_names; 1121 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) { 1122 ptr = psoftlist; 1123 found = B_FALSE; 1124 while (ptr != NULL) { 1125 if (strcmp(psoftname, ptr->pent->name) == 0) { 1126 found = B_TRUE; 1127 break; 1128 } 1129 ptr = ptr->next; 1130 } 1131 1132 if (!found) { 1133 rc = unload_kef_soft(psoftname, B_FALSE); 1134 if (rc == FAILURE) { 1135 cryptoerror(LOG_ERR, gettext( 1136 "WARNING - the provider %s is " 1137 "still in kernel."), psoftname); 1138 } 1139 } 1140 psoftname = psoftname + strlen(psoftname) + 1; 1141 } 1142 } 1143 free(psoftlist_kernel); 1144 1145 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 1146 err = errno; 1147 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 1148 ADMIN_IOCTL_DEVICE, strerror(err)); 1149 free(psoftlist); 1150 free(pdevlist); 1151 return (FAILURE); 1152 } 1153 1154 /* 1155 * For each software module, pass two sets of information to kernel 1156 * - the supported list and the disabled list 1157 */ 1158 ptr = psoftlist; 1159 while (ptr != NULL) { 1160 /* load the supported list */ 1161 if ((pload_soft_conf = setup_soft_conf(ptr->pent)) == NULL) { 1162 rc = FAILURE; 1163 break; 1164 } 1165 1166 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) 1167 == -1) { 1168 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", 1169 strerror(errno)); 1170 free(pload_soft_conf); 1171 rc = FAILURE; 1172 break; 1173 } 1174 1175 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { 1176 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl " 1177 "return_value = %d", 1178 pload_soft_conf->sc_return_value); 1179 free(pload_soft_conf); 1180 rc = FAILURE; 1181 break; 1182 } 1183 1184 /* load the disabled list */ 1185 if (ptr->pent->dis_count != 0) { 1186 pload_soft_dis = setup_soft_dis(ptr->pent); 1187 if (pload_soft_dis == NULL) { 1188 rc = FAILURE; 1189 break; 1190 } 1191 1192 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, 1193 pload_soft_dis) == -1) { 1194 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " 1195 "failed: %s", strerror(errno)); 1196 free(pload_soft_dis); 1197 rc = FAILURE; 1198 break; 1199 } 1200 1201 if (pload_soft_dis->sd_return_value != 1202 CRYPTO_SUCCESS) { 1203 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl " 1204 "return_value = %d", 1205 pload_soft_dis->sd_return_value); 1206 free(pload_soft_dis); 1207 rc = FAILURE; 1208 break; 1209 } 1210 free(pload_soft_dis); 1211 } 1212 1213 free(pload_soft_conf); 1214 ptr = ptr->next; 1215 } 1216 1217 if (rc != SUCCESS) { 1218 (void) close(fd); 1219 return (rc); 1220 } 1221 1222 1223 /* Pass the disabledlist information for Device to kernel */ 1224 ptr = pdevlist; 1225 while (ptr != NULL) { 1226 /* load the disabled list */ 1227 if (ptr->pent->dis_count != 0) { 1228 pload_dev_dis = setup_dev_dis(ptr->pent); 1229 if (pload_dev_dis == NULL) { 1230 rc = FAILURE; 1231 break; 1232 } 1233 1234 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) 1235 == -1) { 1236 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " 1237 "failed: %s", strerror(errno)); 1238 free(pload_dev_dis); 1239 rc = FAILURE; 1240 break; 1241 } 1242 1243 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { 1244 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl " 1245 "return_value = %d", 1246 pload_dev_dis->dd_return_value); 1247 free(pload_dev_dis); 1248 rc = FAILURE; 1249 break; 1250 } 1251 free(pload_dev_dis); 1252 } 1253 1254 ptr = ptr->next; 1255 } 1256 1257 (void) close(fd); 1258 return (rc); 1259 } 1260 1261 /* 1262 * Unload the kernel software provider. Before calling this function, the 1263 * caller should check if the provider is in the config file and if it 1264 * is kernel. This routine makes 3 ioctl calls to remove it from kernel 1265 * completely. The argument do_check set to B_FALSE means that the 1266 * caller knows the provider is not the config file and hence the check 1267 * is skipped. 1268 */ 1269 int 1270 unload_kef_soft(char *provname, boolean_t do_check) 1271 { 1272 crypto_unload_soft_module_t *punload_soft = NULL; 1273 crypto_load_soft_config_t *pload_soft_conf = NULL; 1274 crypto_load_soft_disabled_t *pload_soft_dis = NULL; 1275 entry_t *pent = NULL; 1276 int fd; 1277 1278 if (provname == NULL) { 1279 cryptoerror(LOG_STDERR, gettext("internal error.")); 1280 return (FAILURE); 1281 } 1282 1283 if (!do_check) { 1284 /* Construct an entry using the provname */ 1285 pent = calloc(1, sizeof (entry_t)); 1286 if (pent == NULL) { 1287 cryptoerror(LOG_STDERR, gettext("out of memory.")); 1288 return (FAILURE); 1289 } 1290 (void) strlcpy(pent->name, provname, MAXNAMELEN); 1291 } else if ((pent = getent_kef(provname)) == NULL) { 1292 cryptoerror(LOG_STDERR, gettext("%s does not exist."), 1293 provname); 1294 return (FAILURE); 1295 } 1296 1297 /* Open the admin_ioctl_device */ 1298 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { 1299 err = errno; 1300 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 1301 ADMIN_IOCTL_DEVICE, strerror(err)); 1302 return (FAILURE); 1303 } 1304 1305 /* Inform kernel to unload this software module */ 1306 if ((punload_soft = setup_unload_soft(pent)) == NULL) { 1307 (void) close(fd); 1308 return (FAILURE); 1309 } 1310 1311 if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) { 1312 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s", 1313 strerror(errno)); 1314 free_entry(pent); 1315 free(punload_soft); 1316 (void) close(fd); 1317 return (FAILURE); 1318 } 1319 1320 if (punload_soft->sm_return_value != CRYPTO_SUCCESS) { 1321 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = " 1322 "%d", punload_soft->sm_return_value); 1323 /* 1324 * If the return value is CRYPTO_UNKNOWN_PRIVDER, it means 1325 * that the provider is not registered yet. Should just 1326 * continue. 1327 */ 1328 if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) { 1329 free_entry(pent); 1330 free(punload_soft); 1331 (void) close(fd); 1332 return (FAILURE); 1333 } 1334 } 1335 1336 free(punload_soft); 1337 1338 /* 1339 * Inform kernel to remove the configuration of this software 1340 * module. 1341 */ 1342 free_mechlist(pent->suplist); 1343 pent->suplist = NULL; 1344 pent->sup_count = 0; 1345 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { 1346 free_entry(pent); 1347 (void) close(fd); 1348 return (FAILURE); 1349 } 1350 1351 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { 1352 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", 1353 strerror(errno)); 1354 free_entry(pent); 1355 free(pload_soft_conf); 1356 (void) close(fd); 1357 return (FAILURE); 1358 } 1359 1360 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { 1361 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl return_value = " 1362 "%d", pload_soft_conf->sc_return_value); 1363 free_entry(pent); 1364 free(pload_soft_conf); 1365 (void) close(fd); 1366 return (FAILURE); 1367 } 1368 1369 free(pload_soft_conf); 1370 1371 /* Inform kernel to remove the disabled entries if any */ 1372 if (pent->dis_count == 0) { 1373 free_entry(pent); 1374 (void) close(fd); 1375 return (SUCCESS); 1376 } else { 1377 free_mechlist(pent->dislist); 1378 pent->dislist = NULL; 1379 pent->dis_count = 0; 1380 } 1381 1382 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { 1383 free_entry(pent); 1384 (void) close(fd); 1385 return (FAILURE); 1386 } 1387 1388 /* pent is no longer needed; free it */ 1389 free_entry(pent); 1390 1391 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { 1392 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", 1393 strerror(errno)); 1394 free(pload_soft_dis); 1395 (void) close(fd); 1396 return (FAILURE); 1397 } 1398 1399 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { 1400 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " 1401 "%d", pload_soft_dis->sd_return_value); 1402 free(pload_soft_dis); 1403 (void) close(fd); 1404 return (FAILURE); 1405 } 1406 1407 free(pload_soft_dis); 1408 (void) close(fd); 1409 return (SUCCESS); 1410 } 1411 1412 1413 /* 1414 * Check if a hardware provider is valid. If it is valid, returns its device 1415 * name, instance number and the number of mechanisms it supports. 1416 */ 1417 static int 1418 check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount) 1419 { 1420 crypto_get_dev_list_t *dev_list = NULL; 1421 int i; 1422 1423 if (provname == NULL) { 1424 return (FAILURE); 1425 } 1426 1427 /* First, get the device name and the instance number from provname */ 1428 if (split_hw_provname(provname, pname, pnum) == FAILURE) { 1429 return (FAILURE); 1430 } 1431 1432 /* 1433 * Get the complete device list from kernel and check if this provider 1434 * is in the list. 1435 */ 1436 if (get_dev_list(&dev_list) == FAILURE) { 1437 return (FAILURE); 1438 } 1439 1440 for (i = 0; i < dev_list->dl_dev_count; i++) { 1441 if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) && 1442 (dev_list->dl_devs[i].le_dev_instance == *pnum)) { 1443 break; 1444 } 1445 } 1446 1447 if (i == dev_list->dl_dev_count) { 1448 /* didn't find this provider in the kernel device list */ 1449 cryptoerror(LOG_STDERR, gettext("%s does not exist."), 1450 provname); 1451 free(dev_list); 1452 return (FAILURE); 1453 } 1454 1455 /* This provider is valid. Get its mechanism count */ 1456 *pcount = dev_list->dl_devs[i].le_mechanism_count; 1457 1458 free(dev_list); 1459 return (SUCCESS); 1460 } 1461