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


  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <strings.h>
  31 #include <time.h>
  32 #include <unistd.h>
  33 #include <locale.h>
  34 #include <sys/types.h>

  35 #include <sys/stat.h>
  36 #include "cryptoadm.h"
  37 
  38 static int err; /* To store errno which may be overwritten by gettext() */
  39 static int build_entrylist(entry_t *, entrylist_t **);
  40 static entry_t *dup_entry(entry_t *);
  41 static mechlist_t *dup_mechlist(mechlist_t *);
  42 static entry_t *getent(char *, entrylist_t *);
  43 static int interpret(char *, entry_t **);
  44 static int parse_dislist(char *, entry_t *);
  45 
  46 
  47 /*
  48  * Duplicate the mechanism list.  A null pointer is returned if the storage
  49  * space available is insufficient or the input argument is NULL.
  50  */
  51 static mechlist_t *
  52 dup_mechlist(mechlist_t *plist)
  53 {
  54         mechlist_t *pres = NULL;
  55         mechlist_t *pcur;
  56         mechlist_t *ptmp;
  57         int rc = SUCCESS;
  58 
  59         while (plist != NULL) {
  60                 if (!(ptmp = create_mech(plist->name))) {
  61                         rc = FAILURE;
  62                         break;
  63                 }
  64 


  78 
  79         return (pres);
  80 }
  81 
  82 
  83 /*
  84  * Get the number of mechanisms in the mechanism list.
  85  */
  86 int
  87 get_mech_count(mechlist_t *plist)
  88 {
  89         int count = 0;
  90 
  91         while (plist != NULL) {
  92                 count++;
  93                 plist = plist->next;
  94         }
  95         return (count);
  96 }
  97 








  98 




















  99 /*
 100  * Duplicate an entry.  A null pointer is returned if the storage space
 101  * available is insufficient or the input argument is NULL.

 102  */
 103 static entry_t *
 104 dup_entry(entry_t *pent1)
 105 {
 106         entry_t *pent2 = NULL;
 107 
 108         if (pent1 == NULL) {
 109                 return (NULL);
 110         }
 111 
 112         if ((pent2 = malloc(sizeof (entry_t))) == NULL) {
 113                 cryptodebug("out of memory.");
 114                 return (NULL);
 115         }
 116 
 117         (void) strlcpy(pent2->name, pent1->name, sizeof (pent2->name));
 118         pent2->sup_count = pent1->sup_count;
 119         pent2->dis_count = pent1->dis_count;
 120         pent2->suplist = NULL;
 121         pent2->dislist = NULL;
 122         if (pent1->suplist != NULL) {
 123                 pent2->suplist = dup_mechlist(pent1->suplist);
 124                 if (pent2->suplist == NULL) {
 125                         free_entry(pent2);
 126                         return (NULL);
 127                 }
 128         }
 129         if (pent1->dislist != NULL) {
 130                 pent2->dislist = dup_mechlist(pent1->dislist);
 131                 if (pent2->dislist == NULL) {
 132                         free_entry(pent2);
 133                         return (NULL);
 134                 }
 135         }
 136 
 137         return (pent2);
 138 }
 139 
 140 
 141 /*
 142  * This routine parses the disabledlist or the supportedlist of an entry
 143  * in the kcf.conf configuration file.
 144  *
 145  * Arguments:
 146  *      buf: an input argument which is a char string with the format of
 147  *           "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
 148  *      pent: the entry for the disabledlist.  This is an IN/OUT argument.
 149  *
 150  * Return value: SUCCESS or FAILURE.
 151  */
 152 static int
 153 parse_dislist(char *buf, entry_t *pent)
 154 {
 155         mechlist_t *pmech;
 156         mechlist_t *phead;
 157         char *next_token;
 158         char *value;
 159         int count;
 160         int supflag = B_FALSE;
 161         int disflag = B_FALSE;
 162         int rc = SUCCESS;
 163 
 164         if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
 165                 supflag = B_TRUE;
 166         } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
 167                 disflag = B_TRUE;
 168         } else {
 169                 /* should not come here */
 170                 return (FAILURE);
 171         }
 172 
 173         if (value = strpbrk(buf, SEP_EQUAL)) {
 174                 value++; /* get rid of = */
 175         } else {
 176                 cryptodebug("failed to parse the kcf.conf file.");


 202                         count++;
 203                         phead->next = pmech;
 204                         phead = phead->next;
 205                 }
 206         }
 207 
 208         if (rc == SUCCESS) {
 209                 if (supflag) {
 210                         pent->sup_count = count;
 211                 } else if (disflag) {
 212                         pent->dis_count = count;
 213                 }
 214         } else {
 215                 free_mechlist(phead);
 216         }
 217 
 218         return (rc);
 219 }
 220 
 221 
 222 
 223 /*
 224  * This routine converts a char string into an entry_t structure




 225  */
 226 static int
 227 interpret(char *buf, entry_t **ppent)
 228 {
 229         entry_t *pent;
 230         char *token1;
 231         char *token2;
 232         char *token3;
 233         int rc;
 234 

 235         if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
 236                 return (FAILURE);
 237         };
 238 
 239         pent = malloc(sizeof (entry_t));
 240         if (pent == NULL) {
 241                 cryptodebug("out of memory.");
 242                 return (FAILURE);
 243         }
 244         (void) strlcpy(pent->name, token1, sizeof (pent->name));
 245         pent->suplist = NULL;
 246         pent->dislist = NULL;
 247         pent->sup_count = 0;
 248         pent->dis_count = 0;
 249 
 250         if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 251                 /* The entry contains a provider name only */
 252                 free_entry(pent);
 253                 return (FAILURE);
 254         }
 255 









 256         /* need to get token3 first to satisfy nested strtok invocations */
 257         token3 = strtok(NULL, SEP_SEMICOLON);
 258 
 259         if (token2 && ((rc = parse_dislist(token2, pent)) != SUCCESS)) {


 260                 free_entry(pent);
 261                 return (rc);
 262         }
 263 
 264         if (token3 && ((rc = parse_dislist(token3, pent)) != SUCCESS)) {


 265                 free_entry(pent);
 266                 return (rc);
 267         }
 268 
 269         *ppent = pent;
 270         return (SUCCESS);
 271 }
 272 
 273 
 274 /*
 275  * Add an entry to the end of an entry list. If the entry list is NULL, will
 276  * create an entry list with the pent.

 277  */
 278 static int
 279 build_entrylist(entry_t *pent, entrylist_t **pplist)
 280 {
 281         entrylist_t *pentlist;
 282         entrylist_t *pcur;
 283 
 284         pentlist = malloc(sizeof (entrylist_t));
 285         if (pentlist == NULL) {
 286                 cryptodebug("out of memory.");
 287                 return (FAILURE);
 288         }
 289         pentlist->pent = pent;
 290         pentlist->next = NULL;
 291 
 292         if (*pplist) {
 293                 pcur = *pplist;
 294                 while (pcur->next != NULL)
 295                         pcur = pcur->next;
 296                 pcur->next = pentlist;
 297         } else { /* empty list */
 298                 *pplist = pentlist;
 299         }
 300 
 301         return (SUCCESS);
 302 }
 303 
 304 
 305 
 306 /*
 307  * Find the entry with the "provname" name from the entry list and duplicate
 308  * it.
 309  */
 310 static entry_t *
 311 getent(char *provname, entrylist_t *entrylist)
 312 {
 313         boolean_t       found = B_FALSE;
 314         entry_t         *pent1 = NULL;
 315 
 316         if ((provname == NULL) || (entrylist == NULL)) {
 317                 return (NULL);
 318         }
 319 
 320         while (!found && entrylist) {
 321                 if (strcmp(entrylist->pent->name, provname) == 0) {
 322                         found = B_TRUE;
 323                         pent1 = entrylist->pent;
 324                 } else {
 325                         entrylist = entrylist->next;
 326                 }
 327         }
 328 
 329         if (!found) {
 330                 return (NULL);
 331         }
 332 
 333         /* duplicate the entry to be returned */
 334         return (dup_entry(pent1));
 335 }
 336 
 337 
 338 




 339 void
 340 free_entry(entry_t  *pent)
 341 {
 342         if (pent == NULL) {
 343                 return;
 344         } else {
 345                 free_mechlist(pent->suplist);
 346                 free_mechlist(pent->dislist);
 347                 free(pent);
 348         }
 349 }
 350 
 351 




 352 void
 353 free_entrylist(entrylist_t *entrylist)
 354 {
 355         entrylist_t *pnext;
 356 
 357         while (entrylist != NULL) {
 358                 pnext = entrylist->next;
 359                 free_entry(entrylist->pent);
 360                 entrylist = pnext;
 361         }
 362 }
 363 
 364 
 365 /*
 366  * Convert an entry to a string.  This routine builds a string for the entry
 367  * to be inserted in the config file.  Based on the content of each entry,
 368  * the result string can be one of the 4 forms:
 369  *  - name
 370  *  - name:supportedlist=m1,m2,...,mj
 371  *  - name:disabledlist=m1,m2,...,mj
 372  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 373  *
 374  * Note that the caller is responsible for freeing the returned string.







 375  */
 376 char *
 377 ent2str(entry_t *pent)
 378 {
 379         char    *buf;
 380         mechlist_t  *phead;
 381         boolean_t supflag = B_FALSE;
 382 
 383 
 384         if (pent == NULL) {
 385                 return (NULL);
 386         }
 387 
 388         if ((buf = malloc(BUFSIZ)) == NULL) {
 389                 return (NULL);
 390         }
 391 
 392         /* convert the provider name */
 393         if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
 394                 free(buf);
 395                 return (NULL);
 396         }
 397 
 398         /* convert the supported list if any */
 399         phead = pent->suplist;
 400         if (phead != NULL) {
 401                 supflag = B_TRUE;
 402 
 403                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
 404                         free(buf);
 405                         return (NULL);
 406                 }
 407 


















 408                 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
 409                         free(buf);
 410                         return (NULL);
 411                 }
 412 
 413                 while (phead != NULL) {
 414                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
 415                                 free(buf);
 416                                 return (NULL);
 417                         }
 418 
 419                         phead = phead->next;
 420                         if (phead != NULL) {
 421                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 422                                     >= BUFSIZ) {
 423                                         free(buf);
 424                                         return (NULL);
 425                                 }
 426                         }
 427                 }

 428         }
 429 
 430         /* convert the disabled list if any */
 431         phead = pent->dislist;
 432         if (phead != NULL) {
 433                 if (supflag) {
 434                         if (strlcat(buf, ";disabledlist=", BUFSIZ) >= BUFSIZ) {

 435                                 free(buf);
 436                                 return (NULL);
 437                         }
 438                 } else {
 439                         if (strlcat(buf, ":disabledlist=", BUFSIZ) >= BUFSIZ) {
 440                                 free(buf);
 441                                 return (NULL);
 442                         }
 443                 }
 444 
 445                 while (phead != NULL) {
 446                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
 447                                 free(buf);
 448                                 return (NULL);
 449                         }
 450 
 451                         phead = phead->next;
 452                         if (phead != NULL) {
 453                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 454                                     >= BUFSIZ) {
 455                                         free(buf);
 456                                         return (NULL);
 457                                 }
 458                         }
 459                 }

 460         }
 461 
 462         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
 463                 free(buf);
 464                 return (NULL);
 465         }
 466 
 467         return (buf);
 468 }
 469 
 470 
 471 /*
 472  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
 473  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
 474  * argument "mlist".  The result will be stored in ppent also.
 475  */
 476 int
 477 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
 478 {
 479         entry_t *pent;
 480         mechlist_t *phead; /* the current and resulting disabled list */
 481         mechlist_t *ptr;
 482         mechlist_t *pcur;
 483         boolean_t found;
 484 
 485         pent = *ppent;
 486         if (pent == NULL) {
 487                 return (FAILURE);
 488         }
 489 
 490         if (allflag) {
 491                 free_mechlist(pent->dislist);
 492                 pent->dis_count = 0;
 493                 pent->dislist = NULL;
 494                 return (SUCCESS);
 495         }
 496 
 497         /*
 498          * for each mechanism in the to-be-enabled mechanism list,
 499          * -    check if it is in the current disabled list
 500          * -    if found, delete it from the disabled list
 501          *      otherwise, give a warning.
 502          */


 523                         }
 524                         pent->dis_count--;
 525                 } else {
 526                         cryptoerror(LOG_STDERR, gettext(
 527                             "(Warning) %1$s is either enabled already or not "
 528                             "a valid mechanism for %2$s"), ptr->name,
 529                             pent->name);
 530                 }
 531                 ptr = ptr->next;
 532         }
 533 
 534         if (pent->dis_count == 0) {
 535                 pent->dislist = NULL;
 536         }
 537 
 538         return (SUCCESS);
 539 
 540 }
 541 
 542 





 543 boolean_t
 544 is_device(char *path)
 545 {
 546         if (strchr(path, SEP_SLASH) != NULL) {
 547                 return (B_TRUE);
 548         } else {
 549                 return (B_FALSE);
 550         }
 551 }
 552 
 553 /*
 554  * Split a hardware provider name with the "name/inst_num" format into
 555  * a name and a number.
 556  */
 557 int
 558 split_hw_provname(char *provname, char *pname, int *inst_num)
 559 {
 560         char    name[MAXNAMELEN];
 561         char    *inst_str;
 562 
 563         if (provname == NULL) {
 564                 return (FAILURE);
 565         }
 566 
 567         (void) strlcpy(name, provname, MAXNAMELEN);
 568         if (strtok(name, "/") == NULL) {
 569                 return (FAILURE);
 570         }
 571 
 572         if ((inst_str = strtok(NULL, "/")) == NULL) {
 573                 return (FAILURE);
 574         }
 575 
 576         (void) strlcpy(pname, name, MAXNAMELEN);
 577         *inst_num = atoi(inst_str);
 578 
 579         return (SUCCESS);
 580 }
 581 
 582 
 583 /*
 584  * Retrieve information from kcf.conf and build a device entry list and
 585  * a software entry list






 586  */
 587 int
 588 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 589 {
 590         FILE *pfile;
 591         char buffer[BUFSIZ];
 592         int len;
 593         entry_t *pent = NULL;
 594         int rc = SUCCESS;
 595 
 596         if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
 597                 cryptodebug("failed to open the kcf.conf file for read only");
 598                 return (FAILURE);
 599         }
 600 
 601         *ppdevlist = NULL;
 602         *ppsoftlist = NULL;
 603         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 604                 if (buffer[0] == '#' || buffer[0] == ' ' ||
 605                     buffer[0] == '\n'|| buffer[0] == '\t') {
 606                         continue;   /* ignore comment lines */
 607                 }
 608 
 609                 len = strlen(buffer);
 610                 if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
 611                         len--;
 612                 }
 613                 buffer[len] = '\0';
 614 
 615                 if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
 616                         if (is_device(pent->name)) {
 617                                 rc = build_entrylist(pent, ppdevlist);
 618                         } else {
 619                                 rc = build_entrylist(pent, ppsoftlist);
 620                         }
 621                 } else {
 622                         cryptoerror(LOG_STDERR, gettext(
 623                             "failed to parse configuration."));
 624                 }
 625 
 626                 if (rc != SUCCESS) {
 627                         free_entrylist(*ppdevlist);
 628                         free_entrylist(*ppsoftlist);
 629                         free_entry(pent);
 630                         break;
 631                 }
 632         }
 633 
 634         (void) fclose(pfile);
 635         return (rc);
 636 }
 637 
 638 /*
 639  * Retrieve information from admin device and build a device entry list and
 640  * a software entry list.  This is used where there is no kcf.conf, e.g.
 641  * non-global zone.
 642  */
 643 int
 644 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 645 {
 646         crypto_get_dev_list_t *pdevlist_kernel = NULL;
 647         crypto_get_soft_list_t *psoftlist_kernel = NULL;
 648         char *devname;
 649         int inst_num;
 650         int mcount;
 651         mechlist_t *pmech;
 652         entry_t *pent = NULL;
 653         int i;
 654         char *psoftname;
 655         entrylist_t *tmp_pdev = NULL;
 656         entrylist_t *tmp_psoft = NULL;

 657 



 658         if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 659                 cryptodebug("failed to get hardware provider list from kernel");
 660                 return (FAILURE);
 661         }
 662 
 663         for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
 664                 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
 665                 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
 666                 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
 667 
 668                 pmech = NULL;
 669                 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
 670                     SUCCESS) {
 671                         cryptodebug(
 672                             "failed to retrieve the mechanism list for %s/%d.",
 673                             devname, inst_num);
 674                         goto fail_out;
 675                 }
 676 
 677                 if ((pent = malloc(sizeof (entry_t))) == NULL) {
 678                         cryptodebug("out of memory.");
 679                         free_mechlist(pmech);
 680                         goto fail_out;
 681                 }


 682 
 683                 (void) strlcpy(pent->name, devname, MAXNAMELEN);
 684                 pent->suplist = pmech;
 685                 pent->sup_count = mcount;
 686                 pent->dislist = NULL;
 687                 pent->dis_count = 0;
 688 
 689                 if (build_entrylist(pent, &tmp_pdev) != SUCCESS) {
 690                         goto fail_out;
 691                 }
 692 
 693                 /* because incorporated in tmp_pdev */
 694                 pent = NULL;
 695         }
 696 
 697         free(pdevlist_kernel);
 698         pdevlist_kernel = NULL;
 699 









 700         if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
 701                 cryptodebug("failed to get software provider list from kernel");
 702                 goto fail_out;
 703         }
 704 
 705         for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
 706             i < psoftlist_kernel->sl_soft_count;
 707             i++, psoftname = psoftname + strlen(psoftname) + 1) {
 708                 pmech = NULL;
 709                 if (get_soft_info(psoftname, &pmech) != SUCCESS) {

 710                         cryptodebug(
 711                             "failed to retrieve the mechanism list for %s.",
 712                             psoftname);
 713                         goto fail_out;
 714                 }
 715 
 716                 if ((pent = malloc(sizeof (entry_t))) == NULL) {
 717                         cryptodebug("out of memory.");
 718                         free_mechlist(pmech);
 719                         goto fail_out;
 720                 }


 721 
 722                 (void) strlcpy(pent->name, psoftname, MAXNAMELEN);
 723                 pent->suplist = pmech;
 724                 pent->sup_count = get_mech_count(pmech);
 725                 pent->dislist = NULL;
 726                 pent->dis_count = 0;
 727 
 728                 if (build_entrylist(pent, &tmp_psoft) != SUCCESS) {
 729                         goto fail_out;
 730                 }
 731         }
 732 
 733         free(psoftlist_kernel);
 734         psoftlist_kernel = NULL;
 735 
 736         *ppdevlist = tmp_pdev;
 737         *ppsoftlist = tmp_psoft;
 738 
 739         return (SUCCESS);
 740 
 741 fail_out:
 742         if (pent != NULL)
 743                 free_entry(pent);


 744 
 745         free_entrylist(tmp_pdev);
 746         free_entrylist(tmp_psoft);
 747 
 748         if (pdevlist_kernel != NULL)
 749                 free(pdevlist_kernel);
 750         if (psoftlist_kernel != NULL)
 751                 free(psoftlist_kernel);
 752 
 753         return (FAILURE);
 754 }
 755 
 756 /*
 757  * Find the entry in the "kcf.conf" file with "provname" as the provider name.
 758  * Return the entry if found, otherwise return NULL.




 759  */
 760 entry_t *
 761 getent_kef(char *provname)
 762 {
 763         entrylist_t *pdevlist = NULL;
 764         entrylist_t *psoftlist = NULL;
 765         entry_t *pent = NULL;

 766 
 767         if (get_kcfconf_info(&pdevlist, &psoftlist) != SUCCESS) {

 768                 return (NULL);
 769         }


 770 
 771         if (is_device(provname)) {
 772                 pent = getent(provname, pdevlist);
 773         } else {
 774                 pent = getent(provname, psoftlist);
 775         }
 776 
 777         free_entrylist(pdevlist);

 778         free_entrylist(psoftlist);

 779 
 780         return (pent);
 781 }
 782 
 783 /*
 784  * Print out the provider name and the mechanism list.
 785  */
 786 void
 787 print_mechlist(char *provname, mechlist_t *pmechlist)
 788 {
 789         mechlist_t *ptr;
 790 
 791         if (provname == NULL) {
 792                 return;
 793         }
 794 
 795         (void) printf("%s: ", provname);
 796         if (pmechlist == NULL) {
 797                 (void) printf(gettext("No mechanisms presented.\n"));
 798                 return;
 799         }
 800 
 801         ptr = pmechlist;
 802         while (ptr != NULL) {
 803                 (void) printf("%s", ptr->name);
 804                 ptr = ptr->next;
 805                 if (ptr == NULL) {
 806                         (void) printf("\n");
 807                 } else {
 808                         (void) printf(",");
 809                 }
 810         }
 811 }
 812 
 813 
 814 /*
 815  * Update the kcf.conf file based on the specified entry and the update mode.
 816  * - If update_mode is MODIFY_MODE or DELETE_MODE, the entry with the same
 817  *   provider name will be modified or deleted.
 818  * - If update_mode is ADD_MODE, this must be a hardware provider without
 819  *   an entry in the kcf.conf file yet.  Need to locate its driver package
 820  *   bracket and insert an entry into the bracket.
 821  */
 822 int
 823 update_kcfconf(entry_t *pent, int update_mode)
 824 {
 825         boolean_t       add_it = B_FALSE;
 826         boolean_t       delete_it = B_FALSE;
 827         boolean_t       found_package = B_FALSE;
 828         boolean_t       found_entry = B_FALSE;
 829         FILE    *pfile;
 830         FILE    *pfile_tmp;
 831         char    buffer[BUFSIZ];
 832         char    buffer2[BUFSIZ];
 833         char    devname[MAXNAMELEN];
 834         char    tmpfile_name[MAXPATHLEN];
 835         char    *name;
 836         char    *str;
 837         char    *new_str = NULL;
 838         int     inst_num;
 839         int rc = SUCCESS;
 840 
 841 
 842         if (pent == NULL) {
 843                 cryptoerror(LOG_STDERR, gettext("internal error."));
 844                 return (FAILURE);
 845         }
 846 
 847         /* Check the update_mode */
 848         if (update_mode == ADD_MODE) {

 849                 add_it = B_TRUE;
 850                 /* Get the hardware provider name first */
 851                 if (split_hw_provname(pent->name, devname, &inst_num) ==
 852                     FAILURE) {
 853                         return (FAILURE);
 854                 }
 855 
 856                 /* Convert the entry to be a string  */
 857                 if ((new_str = ent2str(pent)) == NULL) {
 858                         return (FAILURE);
 859                 }
 860         } else if (update_mode == DELETE_MODE) {

 861                 delete_it = B_TRUE;
 862         } else if (update_mode != MODIFY_MODE) {

 863                 cryptoerror(LOG_STDERR, gettext("internal error."));
 864                 return (FAILURE);
 865         }
 866 
 867 
 868         /* Open the kcf.conf file */
 869         if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 870                 err = errno;
 871                 cryptoerror(LOG_STDERR,
 872                     gettext("failed to update the configuration - %s"),
 873                     strerror(err));
 874                 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
 875                 return (FAILURE);
 876         }
 877 
 878         /* Lock the kcf.conf file */
 879         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 880                 err = errno;
 881                 cryptoerror(LOG_STDERR,
 882                     gettext("failed to update the configuration - %s"),
 883                         strerror(err));
 884                 (void) fclose(pfile);
 885                 return (FAILURE);
 886         }
 887 


 896                     gettext("failed to create a temporary file - %s"),
 897                     strerror(err));
 898                 (void) fclose(pfile);
 899                 return (FAILURE);
 900         }
 901 
 902         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 903                 err = errno;
 904                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 905                     tmpfile_name, strerror(err));
 906                 (void) fclose(pfile);
 907                 return (FAILURE);
 908         }
 909 
 910         /*
 911          * Loop thru the entire kcf.conf file, insert, modify or delete
 912          * an entry.
 913          */
 914         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 915                 if (add_it) {
 916                         /* always keep the current line */
 917                         if (fputs(buffer, pfile_tmp) == EOF) {
 918                                 err = errno;
 919                                 cryptoerror(LOG_STDERR, gettext(
 920                                     "failed to write to a temp file: %s."),
 921                                     strerror(err));
 922                                 rc = FAILURE;
 923                                 break;
 924                         }
 925 
 926                         /*
 927                          * If the current position is the beginning of a driver
 928                          * package and if the driver name matches the hardware
 929                          * provider name, then we want to insert the entry
 930                          * here.
 931                          */
 932                         if ((strstr(buffer, HW_DRIVER_STRING) != NULL) &&
 933                             (strstr(buffer, devname) != NULL)) {
 934                                 found_package = B_TRUE;
 935                                 if (fputs(new_str, pfile_tmp) == EOF) {
 936                                         err = errno;
 937                                         cryptoerror(LOG_STDERR, gettext(
 938                                             "failed to write to a temp file: "
 939                                             "%s."), strerror(err));
 940                                         rc = FAILURE;
 941                                         break;
 942                                 }
 943                         }
 944                 } else { /* modify or delete */
 945                         found_entry = B_FALSE;

 946                         if (!(buffer[0] == '#' || buffer[0] == ' ' ||
 947                             buffer[0] == '\n'|| buffer[0] == '\t')) {
 948                                 /*
 949                                  * Get the provider name from this line and
 950                                  * check if this is the entry to be updated
 951                                  * or deleted. Note: can not use "buffer"
 952                                  * directly because strtok will change its
 953                                  * value.
 954                                  */
 955                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
 956                                 if ((name = strtok(buffer2, SEP_COLON)) ==
 957                                     NULL) {
 958                                         rc = FAILURE;
 959                                         break;
 960                                 }
 961 
 962                                 if (strcmp(pent->name, name) == 0) {
 963                                         found_entry = B_TRUE;
 964                                 }
 965                         }
 966 
 967                         if (found_entry && !delete_it) {
 968                                 /*
 969                                  * This is the entry to be updated; get the
 970                                  * updated string and place into buffer.
 971                                  */
 972                                 if ((str = ent2str(pent)) == NULL) {
 973                                         rc = FAILURE;
 974                                         break;
 975                                 } else {
 976                                         (void) strlcpy(buffer, str, BUFSIZ);
 977                                         free(str);
 978                                 }
 979                         }
 980 
 981                         if (!(found_entry && delete_it)) {
 982                                 /* This is the entry to be updated/reserved */
 983                                 if (fputs(buffer, pfile_tmp) == EOF) {
 984                                         err = errno;
 985                                         cryptoerror(LOG_STDERR, gettext(
 986                                             "failed to write to a temp file: "
 987                                             "%s."), strerror(err));
 988                                         rc = FAILURE;
 989                                         break;
 990                                 }
 991                         }
 992                 }
 993         }
 994 
 995         if (add_it) {
 996                 free(new_str);
 997         }
 998 
 999         if ((add_it && !found_package) || (rc == FAILURE)) {
1000                 if (add_it && !found_package) {
1001                         cryptoerror(LOG_STDERR,
1002                             gettext("failed to update configuration - no "
1003                             "driver package information."));
1004                 }
1005 
1006                 (void) fclose(pfile);
1007                 (void) fclose(pfile_tmp);
1008                 if (unlink(tmpfile_name) != 0) {
1009                         err = errno;
1010                         cryptoerror(LOG_STDERR, gettext(
1011                             "(Warning) failed to remove %s: %s"),
1012                             tmpfile_name, strerror(err));

1013                 }
1014                 return (FAILURE);
1015         }

1016 
1017         (void) fclose(pfile);
1018         if (fclose(pfile_tmp) != 0) {
1019                 err = errno;
1020                 cryptoerror(LOG_STDERR,
1021                     gettext("failed to close %s: %s"), tmpfile_name,
1022                     strerror(err));
1023                 return (FAILURE);
1024         }
1025 
1026         /* Copy the temporary file to the kcf.conf file */
1027         if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1028                 err = errno;
1029                 cryptoerror(LOG_STDERR,
1030                     gettext("failed to update the configuration - %s"),
1031                     strerror(err));
1032                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1033                     _PATH_KCF_CONF, strerror(err));
1034                 rc = FAILURE;
1035         } else if (chmod(_PATH_KCF_CONF,


1050                 cryptoerror(LOG_STDERR, gettext(
1051                     "(Warning) failed to remove %s: %s"),
1052                     tmpfile_name, strerror(err));
1053         }
1054 
1055         return (rc);
1056 }
1057 
1058 
1059 /*
1060  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1061  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1062  * dislist argument.  The "infolist" argument contains the mechanism list
1063  * supported by this provider.
1064  */
1065 int
1066 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1067 mechlist_t *dislist)
1068 {
1069         entry_t *pent;
1070         mechlist_t *plist;
1071         mechlist_t *phead;
1072         mechlist_t *pmech;
1073         int rc = SUCCESS;
1074 
1075         pent = *ppent;
1076         if (pent == NULL) {
1077                 return (FAILURE);
1078         }
1079 
1080         if (allflag) {
1081                 free_mechlist(pent->dislist);
1082                 pent->dis_count = get_mech_count(infolist);
1083                 if (!(pent->dislist = dup_mechlist(infolist))) {
1084                         return (FAILURE);
1085                 } else {
1086                         return (SUCCESS);
1087                 }
1088         }
1089 
1090         /*
1091          * Not disable all. Now loop thru the mechanisms specified in the
1092          * dislist.  If the mechanism is not supported by the provider,


1155                         cnt++;
1156                 }
1157         }
1158 
1159         /* Only one entry is present */
1160         if (cnt == 0)
1161                 *pmechlist = NULL;
1162 
1163         return (mech_present);
1164 }
1165 
1166 
1167 
1168 /*
1169  * Print out the mechanism policy for a kernel provider that has an entry
1170  * in the kcf.conf file.
1171  *
1172  * The flag has_random is set to B_TRUE if the provider does random
1173  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1174  * has some mechanisms.


1175  */
1176 void
1177 print_kef_policy(entry_t *pent, boolean_t has_random, boolean_t has_mechs)

1178 {
1179         mechlist_t *ptr;
1180         boolean_t rnd_disabled = B_FALSE;
1181 
1182         if (pent == NULL) {
1183                 return;
1184         }
1185 
1186         rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1187         ptr = pent->dislist;

1188 
1189         (void) printf("%s:", pent->name);
1190 
1191         if (has_mechs == B_TRUE) {
1192                 /*
1193                  * TRANSLATION_NOTE
1194                  * This code block may need to be modified a bit to avoid
1195                  * constructing the text message on the fly.
1196                  */
1197                 (void) printf(gettext(" all mechanisms are enabled"));
1198                 if (ptr != NULL)
1199                         (void) printf(gettext(", except "));
1200                 while (ptr != NULL) {
1201                         (void) printf("%s", ptr->name);
1202                         ptr = ptr->next;
1203                         if (ptr != NULL)
1204                                 (void) printf(",");
1205                 }
1206                 if (ptr == NULL)
1207                         (void) printf(".");
1208         }
1209 
1210         /*
1211          * TRANSLATION_NOTE
1212          * "random" is a keyword and not to be translated.
1213          */
1214         if (rnd_disabled)
1215                 (void) printf(gettext(" %s is disabled."), "random");
1216         else if (has_random)
1217                 (void) printf(gettext(" %s is enabled."), "random");
1218         (void) printf("\n");
1219 }
1220 

1221 /*
1222  * Check if a kernel software provider is in the kernel.






1223  */
1224 int
1225 check_active_for_soft(char *provname, boolean_t *is_active)

1226 {
1227         crypto_get_soft_list_t  *psoftlist_kernel = NULL;
1228         char    *ptr;
1229         int     i;

1230 
1231         if (provname == NULL) {
1232                 cryptoerror(LOG_STDERR, gettext("internal error."));
1233                 return (FAILURE);
1234         }
1235 

1236         if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1237                 cryptodebug("failed to get the software provider list from"
1238                     "kernel.");
1239                 return (FAILURE);
1240         }


1241 
1242         *is_active = B_FALSE;
1243         ptr = psoftlist_kernel->sl_soft_names;
1244         for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1245                 if (strcmp(provname, ptr) == 0) {
1246                         *is_active = B_TRUE;
1247                         break;
1248                 }
1249                 ptr = ptr + strlen(ptr) + 1;
1250         }


1251         free(psoftlist_kernel);
1252 
1253         return (SUCCESS);
1254 }
1255 
1256 
1257 /*
1258  * Check if a kernel hardware provider is in the kernel.






1259  */
1260 int
1261 check_active_for_hard(char *provname, boolean_t *is_active)

1262 {
1263         crypto_get_dev_list_t   *pdevlist = NULL;
1264         char    devname[MAXNAMELEN];
1265         int     inst_num;
1266         int     i;

1267 
1268         if (provname == NULL) {
1269                 cryptoerror(LOG_STDERR, gettext("internal error."));
1270                 return (FAILURE);
1271         }
1272 
1273         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1274                 return (FAILURE);
1275         }
1276 

1277         if (get_dev_list(&pdevlist) == FAILURE) {
1278                 cryptoerror(LOG_STDERR, gettext("internal error."));
1279                 return (FAILURE);
1280         }


1281 
1282         *is_active = B_FALSE;
1283         for (i = 0; i < pdevlist->dl_dev_count; i++) {
1284                 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1285                     (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1286                         *is_active = B_TRUE;
1287                         break;
1288                 }
1289         }


1290         free(pdevlist);
1291 
1292         return (SUCCESS);
1293 }


  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <strings.h>
  31 #include <time.h>
  32 #include <unistd.h>
  33 #include <locale.h>
  34 #include <sys/types.h>
  35 #include <zone.h>
  36 #include <sys/stat.h>
  37 #include "cryptoadm.h"
  38 
  39 static int err; /* To store errno which may be overwritten by gettext() */
  40 static int build_entrylist(entry_t *, entrylist_t **);
  41 static entry_t *dup_entry(entry_t *);
  42 static mechlist_t *dup_mechlist(mechlist_t *);
  43 static entry_t *getent(char *, entrylist_t *);
  44 static int interpret(char *, entry_t **);
  45 static int parse_sup_dis_list(char *, entry_t *);
  46 
  47 
  48 /*
  49  * Duplicate the mechanism list.  A null pointer is returned if the storage
  50  * space available is insufficient or the input argument is NULL.
  51  */
  52 static mechlist_t *
  53 dup_mechlist(mechlist_t *plist)
  54 {
  55         mechlist_t      *pres = NULL;
  56         mechlist_t      *pcur;
  57         mechlist_t      *ptmp;
  58         int             rc = SUCCESS;
  59 
  60         while (plist != NULL) {
  61                 if (!(ptmp = create_mech(plist->name))) {
  62                         rc = FAILURE;
  63                         break;
  64                 }
  65 


  79 
  80         return (pres);
  81 }
  82 
  83 
  84 /*
  85  * Get the number of mechanisms in the mechanism list.
  86  */
  87 int
  88 get_mech_count(mechlist_t *plist)
  89 {
  90         int count = 0;
  91 
  92         while (plist != NULL) {
  93                 count++;
  94                 plist = plist->next;
  95         }
  96         return (count);
  97 }
  98 
  99 /*
 100  * Create one item of type entry_t with the provider name.
 101  * Return NULL if there's not enough memory or provname is NULL.
 102  */
 103 entry_t *
 104 create_entry(char *provname)
 105 {
 106         entry_t         *pent = NULL;
 107 
 108         if (provname == NULL) {
 109                 return (NULL);
 110         }
 111 
 112         pent = calloc(1, sizeof (entry_t));
 113         if (pent == NULL) {
 114                 cryptodebug("out of memory.");
 115                 return (NULL);
 116         }
 117 
 118         (void) strlcpy(pent->name, provname, MAXNAMELEN);
 119         pent->suplist = NULL;
 120         pent->sup_count = 0;
 121         pent->dislist = NULL;
 122         pent->dis_count = 0;
 123         pent->load = B_TRUE;
 124 
 125         return (pent);
 126 }
 127 
 128 /*
 129  * Duplicate an entry for a provider from kcf.conf.
 130  * Return NULL if memory is insufficient or the input argument is NULL.
 131  * Called by getent().
 132  */
 133 static entry_t *
 134 dup_entry(entry_t *pent1)
 135 {
 136         entry_t *pent2 = NULL;
 137 
 138         if (pent1 == NULL) {
 139                 return (NULL);
 140         }
 141 
 142         if ((pent2 = create_entry(pent1->name)) == NULL) {
 143                 cryptodebug("out of memory.");
 144                 return (NULL);
 145         }
 146 

 147         pent2->sup_count = pent1->sup_count;
 148         pent2->dis_count = pent1->dis_count;
 149         pent2->load = pent1->load;

 150         if (pent1->suplist != NULL) {
 151                 pent2->suplist = dup_mechlist(pent1->suplist);
 152                 if (pent2->suplist == NULL) {
 153                         free_entry(pent2);
 154                         return (NULL);
 155                 }
 156         }
 157         if (pent1->dislist != NULL) {
 158                 pent2->dislist = dup_mechlist(pent1->dislist);
 159                 if (pent2->dislist == NULL) {
 160                         free_entry(pent2);
 161                         return (NULL);
 162                 }
 163         }
 164 
 165         return (pent2);
 166 }
 167 
 168 
 169 /*
 170  * This routine parses the disabledlist or the supportedlist of an entry
 171  * in the kcf.conf configuration file.
 172  *
 173  * Arguments:
 174  *      buf: an input argument which is a char string with the format of
 175  *           "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
 176  *      pent: the entry for the disabledlist.  This is an IN/OUT argument.
 177  *
 178  * Return value: SUCCESS or FAILURE.
 179  */
 180 static int
 181 parse_sup_dis_list(char *buf, entry_t *pent)
 182 {
 183         mechlist_t      *pmech = NULL;
 184         mechlist_t      *phead = NULL;
 185         char            *next_token;
 186         char            *value;
 187         int             count;
 188         int             supflag = B_FALSE;
 189         int             disflag = B_FALSE;
 190         int             rc = SUCCESS;
 191 
 192         if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
 193                 supflag = B_TRUE;
 194         } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
 195                 disflag = B_TRUE;
 196         } else {
 197                 /* should not come here */
 198                 return (FAILURE);
 199         }
 200 
 201         if (value = strpbrk(buf, SEP_EQUAL)) {
 202                 value++; /* get rid of = */
 203         } else {
 204                 cryptodebug("failed to parse the kcf.conf file.");


 230                         count++;
 231                         phead->next = pmech;
 232                         phead = phead->next;
 233                 }
 234         }
 235 
 236         if (rc == SUCCESS) {
 237                 if (supflag) {
 238                         pent->sup_count = count;
 239                 } else if (disflag) {
 240                         pent->dis_count = count;
 241                 }
 242         } else {
 243                 free_mechlist(phead);
 244         }
 245 
 246         return (rc);
 247 }
 248 
 249 

 250 /*
 251  * Convert a char string containing a line about a provider
 252  * from kcf.conf into an entry_t structure.
 253  *
 254  * See ent2str(), the reverse of this function, for the format of
 255  * kcf.conf lines.
 256  */
 257 static int
 258 interpret(char *buf, entry_t **ppent)
 259 {
 260         entry_t *pent = NULL;
 261         char    *token1;
 262         char    *token2;
 263         char    *token3;
 264         int     rc;
 265 
 266         /* Get provider name */
 267         if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
 268                 return (FAILURE);
 269         };
 270 
 271         pent = create_entry(token1);
 272         if (pent == NULL) {
 273                 cryptodebug("out of memory.");
 274                 return (FAILURE);
 275         }





 276 
 277         if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 278                 /* The entry contains a provider name only */
 279                 free_entry(pent);
 280                 return (FAILURE);
 281         }
 282 
 283         if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
 284                 pent->load = B_FALSE; /* cryptoadm unload */
 285                 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 286                         /* The entry contains a provider name:unload only */
 287                         free_entry(pent);
 288                         return (FAILURE);
 289                 }
 290         }
 291 
 292         /* need to get token3 first to satisfy nested strtok invocations */
 293         token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
 294 
 295         /* parse supportedlist (or disabledlist if no supportedlist) */
 296         if ((token2 != NULL) && ((rc = parse_sup_dis_list(token2, pent)) !=
 297             SUCCESS)) {
 298                 free_entry(pent);
 299                 return (rc);
 300         }
 301 
 302         /* parse disabledlist (if there's a supportedlist) */
 303         if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) !=
 304             SUCCESS)) {
 305                 free_entry(pent);
 306                 return (rc);
 307         }
 308 
 309         *ppent = pent;
 310         return (SUCCESS);
 311 }
 312 
 313 
 314 /*
 315  * Add an entry about a provider from kcf.conf to the end of an entry list.
 316  * If the entry list pplist is NULL, create the linked list with pent as the
 317  * first element.
 318  */
 319 static int
 320 build_entrylist(entry_t *pent, entrylist_t **pplist)
 321 {
 322         entrylist_t     *pentlist;
 323         entrylist_t     *pcur = NULL;
 324 
 325         pentlist = malloc(sizeof (entrylist_t));
 326         if (pentlist == NULL) {
 327                 cryptodebug("out of memory.");
 328                 return (FAILURE);
 329         }
 330         pentlist->pent = pent;
 331         pentlist->next = NULL;
 332 
 333         if (*pplist) {
 334                 pcur = *pplist;
 335                 while (pcur->next != NULL)
 336                         pcur = pcur->next;
 337                 pcur->next = pentlist;
 338         } else { /* empty list */
 339                 *pplist = pentlist;
 340         }
 341 
 342         return (SUCCESS);
 343 }
 344 
 345 
 346 
 347 /*
 348  * Find the entry with the "provname" name from the entry list and duplicate
 349  * it.  Called by getent_kef().
 350  */
 351 static entry_t *
 352 getent(char *provname, entrylist_t *entrylist)
 353 {
 354         boolean_t       found = B_FALSE;
 355         entry_t         *pent1 = NULL;
 356 
 357         if ((provname == NULL) || (entrylist == NULL)) {
 358                 return (NULL);
 359         }
 360 
 361         while (!found && entrylist) {
 362                 if (strcmp(entrylist->pent->name, provname) == 0) {
 363                         found = B_TRUE;
 364                         pent1 = entrylist->pent;
 365                 } else {
 366                         entrylist = entrylist->next;
 367                 }
 368         }
 369 
 370         if (!found) {
 371                 return (NULL);
 372         }
 373 
 374         /* duplicate the entry to be returned */
 375         return (dup_entry(pent1));
 376 }
 377 
 378 
 379 /*
 380  * Free memory in entry_t.
 381  * That is, the supported and disabled lists for a provider
 382  * from kcf.conf.
 383  */
 384 void
 385 free_entry(entry_t  *pent)
 386 {
 387         if (pent == NULL) {
 388                 return;
 389         } else {
 390                 free_mechlist(pent->suplist);
 391                 free_mechlist(pent->dislist);
 392                 free(pent);
 393         }
 394 }
 395 
 396 
 397 /*
 398  * Free elements in a entrylist_t linked list,
 399  * which lists providers in kcf.conf.
 400  */
 401 void
 402 free_entrylist(entrylist_t *entrylist)
 403 {
 404         entrylist_t *pnext;
 405 
 406         while (entrylist != NULL) {
 407                 pnext = entrylist->next;
 408                 free_entry(entrylist->pent);
 409                 entrylist = pnext;
 410         }
 411 }
 412 
 413 
 414 /*
 415  * Convert an entry to a string.  This routine builds a string for the entry
 416  * to be inserted in the kcf.conf file.  Based on the content of each entry,
 417  * the result string can be one of these 6 forms:

 418  *  - name:supportedlist=m1,m2,...,mj
 419  *  - name:disabledlist=m1,m2,...,mj
 420  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 421  *
 422  *  - name:unload;supportedlist=m1,m2,...,mj
 423  *  - name:unload;disabledlist=m1,m2,...,mj
 424  *  - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 425  *
 426  * Note that the caller is responsible for freeing the returned string
 427  * (with free_entry()).
 428  * See interpret() for the reverse of this function: converting a string
 429  * to an entry_t.
 430  */
 431 char *
 432 ent2str(entry_t *pent)
 433 {
 434         char            *buf;
 435         mechlist_t      *pcur = NULL;
 436         boolean_t       semicolon_separator = B_FALSE;
 437 
 438 
 439         if (pent == NULL) {
 440                 return (NULL);
 441         }
 442 
 443         if ((buf = malloc(BUFSIZ)) == NULL) {
 444                 return (NULL);
 445         }
 446 
 447         /* convert the provider name */
 448         if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
 449                 free(buf);
 450                 return (NULL);
 451         }
 452 
 453         if (!pent->load) { /* add "unload" keyword */




 454                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
 455                         free(buf);
 456                         return (NULL);
 457                 }
 458 
 459                 if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
 460                         free(buf);
 461                         return (NULL);
 462                 }
 463 
 464                 semicolon_separator = B_TRUE;
 465         }
 466 
 467         /* convert the supported list if any */
 468         pcur = pent->suplist;
 469         if (pcur != NULL) {
 470                 if (strlcat(buf,
 471                     semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
 472                     BUFSIZ) >= BUFSIZ) {
 473                         free(buf);
 474                         return (NULL);
 475                 }
 476 
 477                 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
 478                         free(buf);
 479                         return (NULL);
 480                 }
 481 
 482                 while (pcur != NULL) {
 483                         if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 484                                 free(buf);
 485                                 return (NULL);
 486                         }
 487 
 488                         pcur = pcur->next;
 489                         if (pcur != NULL) {
 490                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 491                                     >= BUFSIZ) {
 492                                         free(buf);
 493                                         return (NULL);
 494                                 }
 495                         }
 496                 }
 497                 semicolon_separator = B_TRUE;
 498         }
 499 
 500         /* convert the disabled list if any */
 501         pcur = pent->dislist;
 502         if (pcur != NULL) {
 503                 if (strlcat(buf,
 504                     semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
 505                     BUFSIZ) >= BUFSIZ) {
 506                         free(buf);
 507                         return (NULL);
 508                 }
 509 
 510                 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
 511                         free(buf);
 512                         return (NULL);
 513                 }

 514 
 515                 while (pcur != NULL) {
 516                         if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 517                                 free(buf);
 518                                 return (NULL);
 519                         }
 520 
 521                         pcur = pcur->next;
 522                         if (pcur != NULL) {
 523                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 524                                     >= BUFSIZ) {
 525                                         free(buf);
 526                                         return (NULL);
 527                                 }
 528                         }
 529                 }
 530                 semicolon_separator = B_TRUE;
 531         }
 532 
 533         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
 534                 free(buf);
 535                 return (NULL);
 536         }
 537 
 538         return (buf);
 539 }
 540 
 541 
 542 /*
 543  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
 544  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
 545  * argument "mlist".  The result will be stored in ppent also.
 546  */
 547 int
 548 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
 549 {
 550         entry_t         *pent;
 551         mechlist_t      *phead; /* the current and resulting disabled list */
 552         mechlist_t      *ptr = NULL;
 553         mechlist_t      *pcur = NULL;
 554         boolean_t       found;
 555 
 556         pent = *ppent;
 557         if (pent == NULL) {
 558                 return (FAILURE);
 559         }
 560 
 561         if (allflag) {
 562                 free_mechlist(pent->dislist);
 563                 pent->dis_count = 0;
 564                 pent->dislist = NULL;
 565                 return (SUCCESS);
 566         }
 567 
 568         /*
 569          * for each mechanism in the to-be-enabled mechanism list,
 570          * -    check if it is in the current disabled list
 571          * -    if found, delete it from the disabled list
 572          *      otherwise, give a warning.
 573          */


 594                         }
 595                         pent->dis_count--;
 596                 } else {
 597                         cryptoerror(LOG_STDERR, gettext(
 598                             "(Warning) %1$s is either enabled already or not "
 599                             "a valid mechanism for %2$s"), ptr->name,
 600                             pent->name);
 601                 }
 602                 ptr = ptr->next;
 603         }
 604 
 605         if (pent->dis_count == 0) {
 606                 pent->dislist = NULL;
 607         }
 608 
 609         return (SUCCESS);
 610 
 611 }
 612 
 613 
 614 /*
 615  * Determine if the kernel provider name, path, is a device
 616  * (that is, it contains a slash character (e.g., "mca/0").
 617  * If so, it is a hardware provider; otherwise it is a software provider.
 618  */
 619 boolean_t
 620 is_device(char *path)
 621 {
 622         if (strchr(path, SEP_SLASH) != NULL) {
 623                 return (B_TRUE);
 624         } else {
 625                 return (B_FALSE);
 626         }
 627 }
 628 
 629 /*
 630  * Split a hardware provider name with the "name/inst_num" format into
 631  * a name and a number (e.g., split "mca/0" into "mca" instance 0).
 632  */
 633 int
 634 split_hw_provname(char *provname, char *pname, int *inst_num)
 635 {
 636         char    name[MAXNAMELEN];
 637         char    *inst_str;
 638 
 639         if (provname == NULL) {
 640                 return (FAILURE);
 641         }
 642 
 643         (void) strlcpy(name, provname, MAXNAMELEN);
 644         if (strtok(name, "/") == NULL) {
 645                 return (FAILURE);
 646         }
 647 
 648         if ((inst_str = strtok(NULL, "/")) == NULL) {
 649                 return (FAILURE);
 650         }
 651 
 652         (void) strlcpy(pname, name, MAXNAMELEN);
 653         *inst_num = atoi(inst_str);
 654 
 655         return (SUCCESS);
 656 }
 657 
 658 
 659 /*
 660  * Retrieve information from kcf.conf and build a hardware device entry list
 661  * and a software entry list of kernel crypto providers.
 662  *
 663  * This list is usually incomplete, as kernel crypto providers only have to
 664  * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
 665  * if the kernel provider module is not one of the default kernel providers.
 666  *
 667  * The kcf.conf file is available only in the global zone.
 668  */
 669 int
 670 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 671 {
 672         FILE    *pfile = NULL;
 673         char    buffer[BUFSIZ];
 674         int     len;
 675         entry_t *pent = NULL;
 676         int     rc = SUCCESS;
 677 
 678         if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
 679                 cryptodebug("failed to open the kcf.conf file for read only");
 680                 return (FAILURE);
 681         }
 682 
 683         *ppdevlist = NULL;
 684         *ppsoftlist = NULL;
 685         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 686                 if (buffer[0] == '#' || buffer[0] == ' ' ||
 687                     buffer[0] == '\n'|| buffer[0] == '\t') {
 688                         continue;   /* ignore comment lines */
 689                 }
 690 
 691                 len = strlen(buffer);
 692                 if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
 693                         len--;
 694                 }
 695                 buffer[len] = '\0';
 696 
 697                 if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
 698                         if (is_device(pent->name)) {
 699                                 rc = build_entrylist(pent, ppdevlist);
 700                         } else {
 701                                 rc = build_entrylist(pent, ppsoftlist);
 702                         }
 703                 } else {
 704                         cryptoerror(LOG_STDERR, gettext(
 705                             "failed to parse configuration."));
 706                 }
 707 
 708                 if (rc != SUCCESS) {
 709                         free_entrylist(*ppdevlist);
 710                         free_entrylist(*ppsoftlist);
 711                         free_entry(pent);
 712                         break;
 713                 }
 714         }
 715 
 716         (void) fclose(pfile);
 717         return (rc);
 718 }
 719 
 720 /*
 721  * Retrieve information from admin device and build a device entry list and
 722  * a software entry list.  This is used where there is no kcf.conf, e.g., the
 723  * non-global zone.
 724  */
 725 int
 726 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 727 {
 728         crypto_get_dev_list_t   *pdevlist_kernel = NULL;
 729         crypto_get_soft_list_t  *psoftlist_kernel = NULL;
 730         char                    *devname;
 731         int                     inst_num;
 732         int                     mcount;
 733         mechlist_t              *pmech = NULL;
 734         entry_t                 *pent_dev = NULL, *pent_soft = NULL;
 735         int                     i;
 736         char                    *psoftname;
 737         entrylist_t             *tmp_pdev = NULL;
 738         entrylist_t             *tmp_psoft = NULL;
 739         entrylist_t             *phardlist = NULL, *psoftlist = NULL;
 740 
 741         /*
 742          * Get hardware providers
 743          */
 744         if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 745                 cryptodebug("failed to get hardware provider list from kernel");
 746                 return (FAILURE);
 747         }
 748 
 749         for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
 750                 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
 751                 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
 752                 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
 753 
 754                 pmech = NULL;
 755                 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
 756                     SUCCESS) {
 757                         cryptodebug(
 758                             "failed to retrieve the mechanism list for %s/%d.",
 759                             devname, inst_num);
 760                         goto fail_out;
 761                 }
 762 
 763                 if ((pent_dev = create_entry(devname)) == NULL) {
 764                         cryptodebug("out of memory.");
 765                         free_mechlist(pmech);
 766                         goto fail_out;
 767                 }
 768                 pent_dev->suplist = pmech;
 769                 pent_dev->sup_count = mcount;
 770 
 771                 if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {






 772                         goto fail_out;
 773                 }



 774         }
 775 
 776         free(pdevlist_kernel);
 777         pdevlist_kernel = NULL;
 778 
 779         /*
 780          * Get software providers
 781          */
 782         if (getzoneid() == GLOBAL_ZONEID) {
 783                 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
 784                         goto fail_out;
 785                 }
 786         }
 787 
 788         if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
 789                 cryptodebug("failed to get software provider list from kernel");
 790                 goto fail_out;
 791         }
 792 
 793         for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
 794             i < psoftlist_kernel->sl_soft_count;
 795             i++, psoftname = psoftname + strlen(psoftname) + 1) {
 796                 pmech = NULL;
 797                 if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) !=
 798                     SUCCESS) {
 799                         cryptodebug(
 800                             "failed to retrieve the mechanism list for %s.",
 801                             psoftname);
 802                         goto fail_out;
 803                 }
 804 
 805                 if ((pent_soft = create_entry(psoftname)) == NULL) {
 806                         cryptodebug("out of memory.");
 807                         free_mechlist(pmech);
 808                         goto fail_out;
 809                 }
 810                 pent_soft->suplist = pmech;
 811                 pent_soft->sup_count = get_mech_count(pmech);
 812 
 813                 if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {






 814                         goto fail_out;
 815                 }
 816         }
 817 
 818         free(psoftlist_kernel);
 819         psoftlist_kernel = NULL;
 820 
 821         *ppdevlist = tmp_pdev;
 822         *ppsoftlist = tmp_psoft;
 823 
 824         return (SUCCESS);
 825 
 826 fail_out:
 827         if (pent_dev != NULL)
 828                 free_entry(pent_dev);
 829         if (pent_soft != NULL)
 830                 free_entry(pent_soft);
 831 
 832         free_entrylist(tmp_pdev);
 833         free_entrylist(tmp_psoft);
 834 
 835         if (pdevlist_kernel != NULL)
 836                 free(pdevlist_kernel);
 837         if (psoftlist_kernel != NULL)
 838                 free(psoftlist_kernel);
 839 
 840         return (FAILURE);
 841 }
 842 
 843 /*
 844  * Return configuration information for a kernel provider from kcf.conf.
 845  * For kernel software providers return a enabled list and disabled list.
 846  * For kernel hardware providers return just a disabled list.
 847  *
 848  * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
 849  * If NULL, this function calls get_kcfconf_info() internally.
 850  */
 851 entry_t *
 852 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
 853 {


 854         entry_t         *pent = NULL;
 855         boolean_t       memory_allocated = B_FALSE;
 856 
 857         if ((phardlist == NULL) || (psoftlist == NULL)) {
 858                 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
 859                         return (NULL);
 860                 }
 861                 memory_allocated = B_TRUE;
 862         }
 863 
 864         if (is_device(provname)) {
 865                 pent = getent(provname, phardlist);
 866         } else {
 867                 pent = getent(provname, psoftlist);
 868         }
 869 
 870         if (memory_allocated) {
 871                 free_entrylist(phardlist);
 872                 free_entrylist(psoftlist);
 873         }
 874 
 875         return (pent);
 876 }
 877 
 878 /*
 879  * Print out the provider name and the mechanism list.
 880  */
 881 void
 882 print_mechlist(char *provname, mechlist_t *pmechlist)
 883 {
 884         mechlist_t *ptr = NULL;
 885 
 886         if (provname == NULL) {
 887                 return;
 888         }
 889 
 890         (void) printf("%s: ", provname);
 891         if (pmechlist == NULL) {
 892                 (void) printf(gettext("No mechanisms presented.\n"));
 893                 return;
 894         }
 895 
 896         ptr = pmechlist;
 897         while (ptr != NULL) {
 898                 (void) printf("%s", ptr->name);
 899                 ptr = ptr->next;
 900                 if (ptr == NULL) {
 901                         (void) printf("\n");
 902                 } else {
 903                         (void) printf(",");
 904                 }
 905         }
 906 }
 907 
 908 
 909 /*
 910  * Update the kcf.conf file based on the update mode:
 911  * - If update_mode is MODIFY_MODE, modify the entry with the same name.
 912  *   If not found, append a new entry to the kcf.conf file.
 913  * - If update_mode is DELETE_MODE, delete the entry with the same name.
 914  * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.

 915  */
 916 int
 917 update_kcfconf(entry_t *pent, int update_mode)
 918 {
 919         boolean_t       add_it = B_FALSE;
 920         boolean_t       delete_it = B_FALSE;

 921         boolean_t       found_entry = B_FALSE;
 922         FILE            *pfile = NULL;
 923         FILE            *pfile_tmp = NULL;
 924         char            buffer[BUFSIZ];
 925         char            buffer2[BUFSIZ];

 926         char            tmpfile_name[MAXPATHLEN];
 927         char            *name;

 928         char            *new_str = NULL;

 929         int             rc = SUCCESS;
 930 

 931         if (pent == NULL) {
 932                 cryptoerror(LOG_STDERR, gettext("internal error."));
 933                 return (FAILURE);
 934         }
 935 
 936         /* Check the update_mode */
 937         switch (update_mode) {
 938         case ADD_MODE:
 939                 add_it = B_TRUE;
 940                 /* FALLTHROUGH */
 941         case MODIFY_MODE:
 942                 /* Convert the entry a string to add to kcf.conf  */




 943                 if ((new_str = ent2str(pent)) == NULL) {
 944                         return (FAILURE);
 945                 }
 946                 break;
 947         case DELETE_MODE:
 948                 delete_it = B_TRUE;
 949                 break;
 950         default:
 951                 cryptoerror(LOG_STDERR, gettext("internal error."));
 952                 return (FAILURE);
 953         }
 954 

 955         /* Open the kcf.conf file */
 956         if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 957                 err = errno;
 958                 cryptoerror(LOG_STDERR,
 959                     gettext("failed to update the configuration - %s"),
 960                     strerror(err));
 961                 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
 962                 return (FAILURE);
 963         }
 964 
 965         /* Lock the kcf.conf file */
 966         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 967                 err = errno;
 968                 cryptoerror(LOG_STDERR,
 969                     gettext("failed to update the configuration - %s"),
 970                     strerror(err));
 971                 (void) fclose(pfile);
 972                 return (FAILURE);
 973         }
 974 


 983                     gettext("failed to create a temporary file - %s"),
 984                     strerror(err));
 985                 (void) fclose(pfile);
 986                 return (FAILURE);
 987         }
 988 
 989         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 990                 err = errno;
 991                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 992                     tmpfile_name, strerror(err));
 993                 (void) fclose(pfile);
 994                 return (FAILURE);
 995         }
 996 
 997         /*
 998          * Loop thru the entire kcf.conf file, insert, modify or delete
 999          * an entry.
1000          */
1001         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1002                 if (add_it) {

1003                         if (fputs(buffer, pfile_tmp) == EOF) {
1004                                 err = errno;
1005                                 cryptoerror(LOG_STDERR, gettext(
1006                                     "failed to write to a temp file: %s."),
1007                                     strerror(err));
1008                                 rc = FAILURE;
1009                                 break;
1010                         }
1011 


















1012                 } else { /* modify or delete */
1013                         found_entry = B_FALSE;
1014 
1015                         if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1016                             buffer[0] == '\n'|| buffer[0] == '\t')) {
1017                                 /*
1018                                  * Get the provider name from this line and
1019                                  * check if this is the entry to be updated
1020                                  * or deleted. Note: can not use "buffer"
1021                                  * directly because strtok will change its
1022                                  * value.
1023                                  */
1024                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
1025                                 if ((name = strtok(buffer2, SEP_COLON)) ==
1026                                     NULL) {
1027                                         rc = FAILURE;
1028                                         break;
1029                                 }
1030 
1031                                 if (strcmp(pent->name, name) == 0) {
1032                                         found_entry = B_TRUE;
1033                                 }
1034                         }
1035 
1036                         if (found_entry && !delete_it) {
1037                                 /*
1038                                  * This is the entry to be updated; get the
1039                                  * updated string and place into buffer.
1040                                  */
1041                                 (void) strlcpy(buffer, new_str, BUFSIZ);
1042                                 free(new_str);




1043                         }

1044 
1045                         if (!(found_entry && delete_it)) {
1046                                 /* This is the entry to be updated/reserved */
1047                                 if (fputs(buffer, pfile_tmp) == EOF) {
1048                                         err = errno;
1049                                         cryptoerror(LOG_STDERR, gettext(
1050                                             "failed to write to a temp file: "
1051                                             "%s."), strerror(err));
1052                                         rc = FAILURE;
1053                                         break;
1054                                 }
1055                         }
1056                 }
1057         }
1058 
1059         if ((!delete_it) && (rc != FAILURE)) {
1060                 if (add_it || !found_entry) {
1061                         /* append new entry to end of file */
1062                         if (fputs(new_str, pfile_tmp) == EOF) {










1063                                 err = errno;
1064                                 cryptoerror(LOG_STDERR, gettext(
1065                                     "failed to write to a temp file: %s."),
1066                                     strerror(err));
1067                                 rc = FAILURE;
1068                         }
1069                         free(new_str);
1070                 }
1071         }
1072 
1073         (void) fclose(pfile);
1074         if (fclose(pfile_tmp) != 0) {
1075                 err = errno;
1076                 cryptoerror(LOG_STDERR,
1077                     gettext("failed to close %s: %s"), tmpfile_name,
1078                     strerror(err));
1079                 return (FAILURE);
1080         }
1081 
1082         /* Copy the temporary file to the kcf.conf file */
1083         if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1084                 err = errno;
1085                 cryptoerror(LOG_STDERR,
1086                     gettext("failed to update the configuration - %s"),
1087                     strerror(err));
1088                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1089                     _PATH_KCF_CONF, strerror(err));
1090                 rc = FAILURE;
1091         } else if (chmod(_PATH_KCF_CONF,


1106                 cryptoerror(LOG_STDERR, gettext(
1107                     "(Warning) failed to remove %s: %s"),
1108                     tmpfile_name, strerror(err));
1109         }
1110 
1111         return (rc);
1112 }
1113 
1114 
1115 /*
1116  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1117  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1118  * dislist argument.  The "infolist" argument contains the mechanism list
1119  * supported by this provider.
1120  */
1121 int
1122 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1123 mechlist_t *dislist)
1124 {
1125         entry_t         *pent;
1126         mechlist_t      *plist = NULL;
1127         mechlist_t      *phead = NULL;
1128         mechlist_t      *pmech = NULL;
1129         int             rc = SUCCESS;
1130 
1131         pent = *ppent;
1132         if (pent == NULL) {
1133                 return (FAILURE);
1134         }
1135 
1136         if (allflag) {
1137                 free_mechlist(pent->dislist);
1138                 pent->dis_count = get_mech_count(infolist);
1139                 if (!(pent->dislist = dup_mechlist(infolist))) {
1140                         return (FAILURE);
1141                 } else {
1142                         return (SUCCESS);
1143                 }
1144         }
1145 
1146         /*
1147          * Not disable all. Now loop thru the mechanisms specified in the
1148          * dislist.  If the mechanism is not supported by the provider,


1211                         cnt++;
1212                 }
1213         }
1214 
1215         /* Only one entry is present */
1216         if (cnt == 0)
1217                 *pmechlist = NULL;
1218 
1219         return (mech_present);
1220 }
1221 
1222 
1223 
1224 /*
1225  * Print out the mechanism policy for a kernel provider that has an entry
1226  * in the kcf.conf file.
1227  *
1228  * The flag has_random is set to B_TRUE if the provider does random
1229  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1230  * has some mechanisms.
1231  *
1232  * If pent is NULL, the provider doesn't have a kcf.conf entry.
1233  */
1234 void
1235 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1236     boolean_t has_mechs)
1237 {
1238         mechlist_t      *ptr = NULL;
1239         boolean_t       rnd_disabled = B_FALSE;
1240 
1241         if (pent != NULL) {



1242                 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1243                 ptr = pent->dislist;
1244         }
1245 
1246         (void) printf("%s:", provname);
1247 
1248         if (has_mechs == B_TRUE) {
1249                 /*
1250                  * TRANSLATION_NOTE
1251                  * This code block may need to be modified a bit to avoid
1252                  * constructing the text message on the fly.
1253                  */
1254                 (void) printf(gettext(" all mechanisms are enabled"));
1255                 if (ptr != NULL)
1256                         (void) printf(gettext(", except "));
1257                 while (ptr != NULL) {
1258                         (void) printf("%s", ptr->name);
1259                         ptr = ptr->next;
1260                         if (ptr != NULL)
1261                                 (void) printf(",");
1262                 }
1263                 if (ptr == NULL)
1264                         (void) printf(".");
1265         }
1266 
1267         /*
1268          * TRANSLATION_NOTE
1269          * "random" is a keyword and not to be translated.
1270          */
1271         if (rnd_disabled)
1272                 (void) printf(gettext(" %s is disabled."), "random");
1273         else if (has_random)
1274                 (void) printf(gettext(" %s is enabled."), "random");
1275         (void) printf("\n");
1276 }
1277 
1278 
1279 /*
1280  * Check if a kernel software provider is in the kernel.
1281  *
1282  * Parameters:
1283  * provname             Provider name
1284  * psoftlist_kernel     Optional software provider list.  If NULL, it will be
1285  *                      obtained from get_soft_list().
1286  * in_kernel            Set to B_TRUE if device is in the kernel, else B_FALSE
1287  */
1288 int
1289 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1290     boolean_t *in_kernel)
1291 {

1292         char            *ptr;
1293         int             i;
1294         boolean_t       psoftlist_allocated = B_FALSE;
1295 
1296         if (provname == NULL) {
1297                 cryptoerror(LOG_STDERR, gettext("internal error."));
1298                 return (FAILURE);
1299         }
1300 
1301         if (psoftlist_kernel == NULL) {
1302                 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1303                         cryptodebug("failed to get the software provider list"
1304                         " from kernel.");
1305                         return (FAILURE);
1306                 }
1307                 psoftlist_allocated = B_TRUE;
1308         }
1309 
1310         *in_kernel = B_FALSE;
1311         ptr = psoftlist_kernel->sl_soft_names;
1312         for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1313                 if (strcmp(provname, ptr) == 0) {
1314                         *in_kernel = B_TRUE;
1315                         break;
1316                 }
1317                 ptr = ptr + strlen(ptr) + 1;
1318         }
1319 
1320         if (psoftlist_allocated)
1321                 free(psoftlist_kernel);
1322 
1323         return (SUCCESS);
1324 }
1325 
1326 
1327 /*
1328  * Check if a kernel hardware provider is in the kernel.
1329  *
1330  * Parameters:
1331  * provname     Provider name
1332  * pdevlist     Optional Hardware Crypto Device List.  If NULL, it will be
1333  *              obtained from get_dev_list().
1334  * in_kernel    Set to B_TRUE if device is in the kernel, otherwise B_FALSE
1335  */
1336 int
1337 check_kernel_for_hard(char *provname,
1338     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1339 {

1340         char            devname[MAXNAMELEN];
1341         int             inst_num;
1342         int             i;
1343         boolean_t       dev_list_allocated = B_FALSE;
1344 
1345         if (provname == NULL) {
1346                 cryptoerror(LOG_STDERR, gettext("internal error."));
1347                 return (FAILURE);
1348         }
1349 
1350         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1351                 return (FAILURE);
1352         }
1353 
1354         if (pdevlist == NULL) {
1355                 if (get_dev_list(&pdevlist) == FAILURE) {
1356                         cryptoerror(LOG_STDERR, gettext("internal error."));
1357                         return (FAILURE);
1358                 }
1359                 dev_list_allocated = B_TRUE;
1360         }
1361 
1362         *in_kernel = B_FALSE;
1363         for (i = 0; i < pdevlist->dl_dev_count; i++) {
1364                 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1365                     (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1366                         *in_kernel = B_TRUE;
1367                         break;
1368                 }
1369         }
1370 
1371         if (dev_list_allocated)
1372                 free(pdevlist);
1373 
1374         return (SUCCESS);
1375 }