Print this page
6414175 kcf.conf's supportedlist not providing much usefulness


  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 


 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 


 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,


 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;


 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) {


 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 




  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 


 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 


 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,


 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;


 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) {


 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