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