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 }