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