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