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