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