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