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