1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 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(const char *buf, entry_t *pent);
  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 
  66                 if (pres == NULL) {
  67                         pres = pcur = ptmp;
  68                 } else {
  69                         pcur->next = ptmp;
  70                         pcur = pcur->next;
  71                 }
  72                 plist = plist->next;
  73         }
  74 
  75         if (rc != SUCCESS) {
  76                 free_mechlist(pres);
  77                 return (NULL);
  78         }
  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(const 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.");
 205                 return (FAILURE);
 206         }
 207 
 208         if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
 209                 cryptodebug("failed to parse the kcf.conf file.");
 210                 return (FAILURE);
 211         }
 212 
 213         if ((pmech = create_mech(next_token)) == NULL) {
 214                 return (FAILURE);
 215         }
 216 
 217         if (supflag) {
 218                         if (pent->suplist != NULL) {
 219                                 cryptodebug("multiple supportedlist entries "
 220                                     "for a mechanism in file kcf.conf.");
 221                                 return (FAILURE);
 222                         } else {
 223                                 pent->suplist = phead = pmech;
 224                         }
 225         } else if (disflag) {
 226                         if (pent->dislist != NULL) {
 227                                 cryptodebug("multiple disabledlist entries "
 228                                     "for a mechanism in file kcf.conf.");
 229                                 return (FAILURE);
 230                         } else {
 231                                 pent->dislist = phead = pmech;
 232                         }
 233         }
 234 
 235         count = 1;
 236         while (next_token) {
 237                 if (next_token = strtok(NULL, SEP_COMMA)) {
 238                         if ((pmech = create_mech(next_token)) == NULL) {
 239                                 rc = FAILURE;
 240                                 break;
 241                         }
 242                         count++;
 243                         phead->next = pmech;
 244                         phead = phead->next;
 245                 }
 246         }
 247 
 248         if (rc == SUCCESS) {
 249                 if (supflag) {
 250                         pent->sup_count = count;
 251                 } else if (disflag) {
 252                         pent->dis_count = count;
 253                 }
 254         } else {
 255                 free_mechlist(phead);
 256         }
 257 
 258         return (rc);
 259 }
 260 
 261 
 262 /*
 263  * Convert a char string containing a line about a provider
 264  * from kcf.conf into an entry_t structure.
 265  *
 266  * Note: the input string, buf, may be modified by this function.
 267  *
 268  * See ent2str(), the reverse of this function, for the format of
 269  * kcf.conf lines.
 270  */
 271 static int
 272 interpret(char *buf, entry_t **ppent)
 273 {
 274         entry_t *pent = NULL;
 275         char    *token1;
 276         char    *token2;
 277         char    *token3;
 278         int     rc;
 279 
 280         /* Get provider name */
 281         if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
 282                 return (FAILURE);
 283         };
 284 
 285         pent = create_entry(token1);
 286         if (pent == NULL) {
 287                 cryptodebug("out of memory.");
 288                 return (FAILURE);
 289         }
 290 
 291         if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 292                 /* The entry contains a provider name only */
 293                 free_entry(pent);
 294                 return (FAILURE);
 295         }
 296 
 297         if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
 298                 pent->load = B_FALSE; /* cryptoadm unload */
 299                 token2 = strtok(NULL, SEP_SEMICOLON);
 300                 /*
 301                  * If token2 is NULL, the entry contains a
 302                  * provider name:unload only
 303                  */
 304         }
 305 
 306         if (token2 != NULL) {
 307                 /*
 308                  * Either supportedlist or disabledlist or both are present.
 309                  * Need to call strtok() to get token3 first, as function
 310                  * parse_sup_dis_list() makes strtok() calls on the
 311                  * token2 substring.
 312                  */
 313                 token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
 314 
 315                 /* parse supportedlist (or disabledlist if no supportedlist) */
 316                 if ((rc = parse_sup_dis_list(token2, pent)) != SUCCESS) {
 317                         free_entry(pent);
 318                         return (rc);
 319                 }
 320 
 321                 /* parse disabledlist (if there's a supportedlist) */
 322                 if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3,
 323                     pent)) != SUCCESS)) {
 324                         free_entry(pent);
 325                         return (rc);
 326                 }
 327         }
 328 
 329         *ppent = pent;
 330         return (SUCCESS);
 331 }
 332 
 333 
 334 /*
 335  * Add an entry about a provider from kcf.conf to the end of an entry list.
 336  * If the entry list pplist is NULL, create the linked list with pent as the
 337  * first element.
 338  */
 339 static int
 340 build_entrylist(entry_t *pent, entrylist_t **pplist)
 341 {
 342         entrylist_t     *pentlist;
 343         entrylist_t     *pcur = NULL;
 344 
 345         pentlist = malloc(sizeof (entrylist_t));
 346         if (pentlist == NULL) {
 347                 cryptodebug("out of memory.");
 348                 return (FAILURE);
 349         }
 350         pentlist->pent = pent;
 351         pentlist->next = NULL;
 352 
 353         if (*pplist) {
 354                 pcur = *pplist;
 355                 while (pcur->next != NULL)
 356                         pcur = pcur->next;
 357                 pcur->next = pentlist;
 358         } else { /* empty list */
 359                 *pplist = pentlist;
 360         }
 361 
 362         return (SUCCESS);
 363 }
 364 
 365 
 366 
 367 /*
 368  * Find the entry with the "provname" name from the entry list and duplicate
 369  * it.  Called by getent_kef().
 370  */
 371 static entry_t *
 372 getent(char *provname, entrylist_t *entrylist)
 373 {
 374         boolean_t       found = B_FALSE;
 375         entry_t         *pent1 = NULL;
 376 
 377         if ((provname == NULL) || (entrylist == NULL)) {
 378                 return (NULL);
 379         }
 380 
 381         while (!found && entrylist) {
 382                 if (strcmp(entrylist->pent->name, provname) == 0) {
 383                         found = B_TRUE;
 384                         pent1 = entrylist->pent;
 385                 } else {
 386                         entrylist = entrylist->next;
 387                 }
 388         }
 389 
 390         if (!found) {
 391                 return (NULL);
 392         }
 393 
 394         /* duplicate the entry to be returned */
 395         return (dup_entry(pent1));
 396 }
 397 
 398 
 399 /*
 400  * Free memory in entry_t.
 401  * That is, the supported and disabled lists for a provider
 402  * from kcf.conf.
 403  */
 404 void
 405 free_entry(entry_t  *pent)
 406 {
 407         if (pent == NULL) {
 408                 return;
 409         } else {
 410                 free_mechlist(pent->suplist);
 411                 free_mechlist(pent->dislist);
 412                 free(pent);
 413         }
 414 }
 415 
 416 
 417 /*
 418  * Free elements in a entrylist_t linked list,
 419  * which lists providers in kcf.conf.
 420  */
 421 void
 422 free_entrylist(entrylist_t *entrylist)
 423 {
 424         entrylist_t *pnext;
 425 
 426         while (entrylist != NULL) {
 427                 pnext = entrylist->next;
 428                 free_entry(entrylist->pent);
 429                 entrylist = pnext;
 430         }
 431 }
 432 
 433 
 434 /*
 435  * Convert an entry to a string.  This routine builds a string for the entry
 436  * to be inserted in the kcf.conf file.  Based on the content of each entry,
 437  * the result string can be one of these 7 forms:
 438  *  - name:supportedlist=m1,m2,...,mj
 439  *  - name:disabledlist=m1,m2,...,mj
 440  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 441  *
 442  *  - name:unload
 443  *  - name:unload;supportedlist=m1,m2,...,mj
 444  *  - name:unload;disabledlist=m1,m2,...,mj
 445  *  - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 446  *
 447  * Note that the caller is responsible for freeing the returned string
 448  * (with free_entry()).
 449  * See interpret() for the reverse of this function: converting a string
 450  * to an entry_t.
 451  */
 452 char *
 453 ent2str(entry_t *pent)
 454 {
 455         char            *buf;
 456         mechlist_t      *pcur = NULL;
 457         boolean_t       semicolon_separator = B_FALSE;
 458 
 459 
 460         if (pent == NULL) {
 461                 return (NULL);
 462         }
 463 
 464         if ((buf = malloc(BUFSIZ)) == NULL) {
 465                 return (NULL);
 466         }
 467 
 468         /* convert the provider name */
 469         if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
 470                 free(buf);
 471                 return (NULL);
 472         }
 473 
 474         if (!pent->load) { /* add "unload" keyword */
 475                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
 476                         free(buf);
 477                         return (NULL);
 478                 }
 479 
 480                 if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
 481                         free(buf);
 482                         return (NULL);
 483                 }
 484 
 485                 semicolon_separator = B_TRUE;
 486         }
 487 
 488         /* convert the supported list if any */
 489         pcur = pent->suplist;
 490         if (pcur != NULL) {
 491                 if (strlcat(buf,
 492                     semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
 493                     BUFSIZ) >= BUFSIZ) {
 494                         free(buf);
 495                         return (NULL);
 496                 }
 497 
 498                 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
 499                         free(buf);
 500                         return (NULL);
 501                 }
 502 
 503                 while (pcur != NULL) {
 504                         if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 505                                 free(buf);
 506                                 return (NULL);
 507                         }
 508 
 509                         pcur = pcur->next;
 510                         if (pcur != NULL) {
 511                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 512                                     >= BUFSIZ) {
 513                                         free(buf);
 514                                         return (NULL);
 515                                 }
 516                         }
 517                 }
 518                 semicolon_separator = B_TRUE;
 519         }
 520 
 521         /* convert the disabled list if any */
 522         pcur = pent->dislist;
 523         if (pcur != NULL) {
 524                 if (strlcat(buf,
 525                     semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
 526                     BUFSIZ) >= BUFSIZ) {
 527                         free(buf);
 528                         return (NULL);
 529                 }
 530 
 531                 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
 532                         free(buf);
 533                         return (NULL);
 534                 }
 535 
 536                 while (pcur != NULL) {
 537                         if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 538                                 free(buf);
 539                                 return (NULL);
 540                         }
 541 
 542                         pcur = pcur->next;
 543                         if (pcur != NULL) {
 544                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 545                                     >= BUFSIZ) {
 546                                         free(buf);
 547                                         return (NULL);
 548                                 }
 549                         }
 550                 }
 551                 semicolon_separator = B_TRUE;
 552         }
 553 
 554         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
 555                 free(buf);
 556                 return (NULL);
 557         }
 558 
 559         return (buf);
 560 }
 561 
 562 
 563 /*
 564  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
 565  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
 566  * argument "mlist".  The result will be stored in ppent also.
 567  */
 568 int
 569 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
 570 {
 571         entry_t         *pent;
 572         mechlist_t      *phead; /* the current and resulting disabled list */
 573         mechlist_t      *ptr = NULL;
 574         mechlist_t      *pcur = NULL;
 575         boolean_t       found;
 576 
 577         pent = *ppent;
 578         if (pent == NULL) {
 579                 return (FAILURE);
 580         }
 581 
 582         if (allflag) {
 583                 free_mechlist(pent->dislist);
 584                 pent->dis_count = 0;
 585                 pent->dislist = NULL;
 586                 return (SUCCESS);
 587         }
 588 
 589         /*
 590          * for each mechanism in the to-be-enabled mechanism list,
 591          * -    check if it is in the current disabled list
 592          * -    if found, delete it from the disabled list
 593          *      otherwise, give a warning.
 594          */
 595         ptr = mlist;
 596         while (ptr != NULL) {
 597                 found = B_FALSE;
 598                 phead = pcur =  pent->dislist;
 599                 while (!found && pcur) {
 600                         if (strcmp(pcur->name, ptr->name) == 0) {
 601                                 found = B_TRUE;
 602                         } else {
 603                                 phead = pcur;
 604                                 pcur = pcur->next;
 605                         }
 606                 }
 607 
 608                 if (found) {
 609                         if (phead == pcur) {
 610                                 pent->dislist = pent->dislist->next;
 611                                 free(pcur);
 612                         } else {
 613                                 phead->next = pcur->next;
 614                                 free(pcur);
 615                         }
 616                         pent->dis_count--;
 617                 } else {
 618                         cryptoerror(LOG_STDERR, gettext(
 619                             "(Warning) %1$s is either enabled already or not "
 620                             "a valid mechanism for %2$s"), ptr->name,
 621                             pent->name);
 622                 }
 623                 ptr = ptr->next;
 624         }
 625 
 626         if (pent->dis_count == 0) {
 627                 pent->dislist = NULL;
 628         }
 629 
 630         return (SUCCESS);
 631 
 632 }
 633 
 634 
 635 /*
 636  * Determine if the kernel provider name, path, is a device
 637  * (that is, it contains a slash character (e.g., "mca/0").
 638  * If so, it is a hardware provider; otherwise it is a software provider.
 639  */
 640 boolean_t
 641 is_device(char *path)
 642 {
 643         if (strchr(path, SEP_SLASH) != NULL) {
 644                 return (B_TRUE);
 645         } else {
 646                 return (B_FALSE);
 647         }
 648 }
 649 
 650 /*
 651  * Split a hardware provider name with the "name/inst_num" format into
 652  * a name and a number (e.g., split "mca/0" into "mca" instance 0).
 653  */
 654 int
 655 split_hw_provname(char *provname, char *pname, int *inst_num)
 656 {
 657         char    name[MAXNAMELEN];
 658         char    *inst_str;
 659 
 660         if (provname == NULL) {
 661                 return (FAILURE);
 662         }
 663 
 664         (void) strlcpy(name, provname, MAXNAMELEN);
 665         if (strtok(name, "/") == NULL) {
 666                 return (FAILURE);
 667         }
 668 
 669         if ((inst_str = strtok(NULL, "/")) == NULL) {
 670                 return (FAILURE);
 671         }
 672 
 673         (void) strlcpy(pname, name, MAXNAMELEN);
 674         *inst_num = atoi(inst_str);
 675 
 676         return (SUCCESS);
 677 }
 678 
 679 
 680 /*
 681  * Retrieve information from kcf.conf and build a hardware device entry list
 682  * and a software entry list of kernel crypto providers.
 683  *
 684  * This list is usually incomplete, as kernel crypto providers only have to
 685  * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
 686  * if the kernel provider module is not one of the default kernel providers.
 687  *
 688  * The kcf.conf file is available only in the global zone.
 689  */
 690 int
 691 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 692 {
 693         FILE    *pfile = NULL;
 694         char    buffer[BUFSIZ];
 695         int     len;
 696         entry_t *pent = NULL;
 697         int     rc = SUCCESS;
 698 
 699         if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
 700                 cryptodebug("failed to open the kcf.conf file for read only");
 701                 return (FAILURE);
 702         }
 703 
 704         *ppdevlist = NULL;
 705         *ppsoftlist = NULL;
 706         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 707                 if (buffer[0] == '#' || buffer[0] == ' ' ||
 708                     buffer[0] == '\n'|| buffer[0] == '\t') {
 709                         continue;   /* ignore comment lines */
 710                 }
 711 
 712                 len = strlen(buffer);
 713                 if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
 714                         len--;
 715                 }
 716                 buffer[len] = '\0';
 717 
 718                 if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
 719                         if (is_device(pent->name)) {
 720                                 rc = build_entrylist(pent, ppdevlist);
 721                         } else {
 722                                 rc = build_entrylist(pent, ppsoftlist);
 723                         }
 724                 } else {
 725                         cryptoerror(LOG_STDERR, gettext(
 726                             "failed to parse configuration."));
 727                 }
 728 
 729                 if (rc != SUCCESS) {
 730                         free_entrylist(*ppdevlist);
 731                         free_entrylist(*ppsoftlist);
 732                         free_entry(pent);
 733                         break;
 734                 }
 735         }
 736 
 737         (void) fclose(pfile);
 738         return (rc);
 739 }
 740 
 741 /*
 742  * Retrieve information from admin device and build a device entry list and
 743  * a software entry list.  This is used where there is no kcf.conf, e.g., the
 744  * non-global zone.
 745  */
 746 int
 747 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 748 {
 749         crypto_get_dev_list_t   *pdevlist_kernel = NULL;
 750         crypto_get_soft_list_t  *psoftlist_kernel = NULL;
 751         char                    *devname;
 752         int                     inst_num;
 753         int                     mcount;
 754         mechlist_t              *pmech = NULL;
 755         entry_t                 *pent_dev = NULL, *pent_soft = NULL;
 756         int                     i;
 757         char                    *psoftname;
 758         entrylist_t             *tmp_pdev = NULL;
 759         entrylist_t             *tmp_psoft = NULL;
 760         entrylist_t             *phardlist = NULL, *psoftlist = NULL;
 761 
 762         /*
 763          * Get hardware providers
 764          */
 765         if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 766                 cryptodebug("failed to get hardware provider list from kernel");
 767                 return (FAILURE);
 768         }
 769 
 770         for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
 771                 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
 772                 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
 773                 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
 774 
 775                 pmech = NULL;
 776                 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
 777                     SUCCESS) {
 778                         cryptodebug(
 779                             "failed to retrieve the mechanism list for %s/%d.",
 780                             devname, inst_num);
 781                         goto fail_out;
 782                 }
 783 
 784                 if ((pent_dev = create_entry(devname)) == NULL) {
 785                         cryptodebug("out of memory.");
 786                         free_mechlist(pmech);
 787                         goto fail_out;
 788                 }
 789                 pent_dev->suplist = pmech;
 790                 pent_dev->sup_count = mcount;
 791 
 792                 if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
 793                         goto fail_out;
 794                 }
 795         }
 796 
 797         free(pdevlist_kernel);
 798         pdevlist_kernel = NULL;
 799 
 800         /*
 801          * Get software providers
 802          */
 803         if (getzoneid() == GLOBAL_ZONEID) {
 804                 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
 805                         goto fail_out;
 806                 }
 807         }
 808 
 809         if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
 810                 cryptodebug("failed to get software provider list from kernel");
 811                 goto fail_out;
 812         }
 813 
 814         for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
 815             i < psoftlist_kernel->sl_soft_count;
 816             i++, psoftname = psoftname + strlen(psoftname) + 1) {
 817                 pmech = NULL;
 818                 if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) !=
 819                     SUCCESS) {
 820                         cryptodebug(
 821                             "failed to retrieve the mechanism list for %s.",
 822                             psoftname);
 823                         goto fail_out;
 824                 }
 825 
 826                 if ((pent_soft = create_entry(psoftname)) == NULL) {
 827                         cryptodebug("out of memory.");
 828                         free_mechlist(pmech);
 829                         goto fail_out;
 830                 }
 831                 pent_soft->suplist = pmech;
 832                 pent_soft->sup_count = get_mech_count(pmech);
 833 
 834                 if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
 835                         goto fail_out;
 836                 }
 837         }
 838 
 839         free(psoftlist_kernel);
 840         psoftlist_kernel = NULL;
 841 
 842         *ppdevlist = tmp_pdev;
 843         *ppsoftlist = tmp_psoft;
 844 
 845         return (SUCCESS);
 846 
 847 fail_out:
 848         if (pent_dev != NULL)
 849                 free_entry(pent_dev);
 850         if (pent_soft != NULL)
 851                 free_entry(pent_soft);
 852 
 853         free_entrylist(tmp_pdev);
 854         free_entrylist(tmp_psoft);
 855 
 856         if (pdevlist_kernel != NULL)
 857                 free(pdevlist_kernel);
 858         if (psoftlist_kernel != NULL)
 859                 free(psoftlist_kernel);
 860 
 861         return (FAILURE);
 862 }
 863 
 864 /*
 865  * Return configuration information for a kernel provider from kcf.conf.
 866  * For kernel software providers return a enabled list and disabled list.
 867  * For kernel hardware providers return just a disabled list.
 868  *
 869  * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
 870  * If NULL, this function calls get_kcfconf_info() internally.
 871  */
 872 entry_t *
 873 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
 874 {
 875         entry_t         *pent = NULL;
 876         boolean_t       memory_allocated = B_FALSE;
 877 
 878         if ((phardlist == NULL) || (psoftlist == NULL)) {
 879                 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
 880                         return (NULL);
 881                 }
 882                 memory_allocated = B_TRUE;
 883         }
 884 
 885         if (is_device(provname)) {
 886                 pent = getent(provname, phardlist);
 887         } else {
 888                 pent = getent(provname, psoftlist);
 889         }
 890 
 891         if (memory_allocated) {
 892                 free_entrylist(phardlist);
 893                 free_entrylist(psoftlist);
 894         }
 895 
 896         return (pent);
 897 }
 898 
 899 /*
 900  * Print out the provider name and the mechanism list.
 901  */
 902 void
 903 print_mechlist(char *provname, mechlist_t *pmechlist)
 904 {
 905         mechlist_t *ptr = NULL;
 906 
 907         if (provname == NULL) {
 908                 return;
 909         }
 910 
 911         (void) printf("%s: ", provname);
 912         if (pmechlist == NULL) {
 913                 (void) printf(gettext("No mechanisms presented.\n"));
 914                 return;
 915         }
 916 
 917         ptr = pmechlist;
 918         while (ptr != NULL) {
 919                 (void) printf("%s", ptr->name);
 920                 ptr = ptr->next;
 921                 if (ptr == NULL) {
 922                         (void) printf("\n");
 923                 } else {
 924                         (void) printf(",");
 925                 }
 926         }
 927 }
 928 
 929 
 930 /*
 931  * Update the kcf.conf file based on the update mode:
 932  * - If update_mode is MODIFY_MODE, modify the entry with the same name.
 933  *   If not found, append a new entry to the kcf.conf file.
 934  * - If update_mode is DELETE_MODE, delete the entry with the same name.
 935  * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.
 936  */
 937 int
 938 update_kcfconf(entry_t *pent, int update_mode)
 939 {
 940         boolean_t       add_it = B_FALSE;
 941         boolean_t       delete_it = B_FALSE;
 942         boolean_t       this_entry_matches = B_FALSE;
 943         boolean_t       found_entry = B_FALSE;
 944         FILE            *pfile = NULL;
 945         FILE            *pfile_tmp = NULL;
 946         char            buffer[BUFSIZ];
 947         char            buffer2[BUFSIZ];
 948         char            tmpfile_name[MAXPATHLEN];
 949         char            *name;
 950         char            *new_str = NULL;
 951         int             rc = SUCCESS;
 952 
 953         if (pent == NULL) {
 954                 cryptoerror(LOG_STDERR, gettext("internal error."));
 955                 return (FAILURE);
 956         }
 957 
 958         /* Check the update_mode */
 959         switch (update_mode) {
 960         case ADD_MODE:
 961                 add_it = B_TRUE;
 962                 /* FALLTHROUGH */
 963         case MODIFY_MODE:
 964                 /* Convert the entry a string to add to kcf.conf  */
 965                 if ((new_str = ent2str(pent)) == NULL) {
 966                         return (FAILURE);
 967                 }
 968                 break;
 969         case DELETE_MODE:
 970                 delete_it = B_TRUE;
 971                 break;
 972         default:
 973                 cryptoerror(LOG_STDERR, gettext("internal error."));
 974                 return (FAILURE);
 975         }
 976 
 977         /* Open the kcf.conf file */
 978         if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 979                 err = errno;
 980                 cryptoerror(LOG_STDERR,
 981                     gettext("failed to update the configuration - %s"),
 982                     strerror(err));
 983                 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
 984                 return (FAILURE);
 985         }
 986 
 987         /* Lock the kcf.conf file */
 988         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 989                 err = errno;
 990                 cryptoerror(LOG_STDERR,
 991                     gettext("failed to update the configuration - %s"),
 992                     strerror(err));
 993                 (void) fclose(pfile);
 994                 return (FAILURE);
 995         }
 996 
 997         /*
 998          * Create a temporary file in the /etc/crypto directory to save
 999          * updated configuration file first.
1000          */
1001         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
1002         if (mkstemp(tmpfile_name) == -1) {
1003                 err = errno;
1004                 cryptoerror(LOG_STDERR,
1005                     gettext("failed to create a temporary file - %s"),
1006                     strerror(err));
1007                 (void) fclose(pfile);
1008                 return (FAILURE);
1009         }
1010 
1011         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
1012                 err = errno;
1013                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
1014                     tmpfile_name, strerror(err));
1015                 (void) fclose(pfile);
1016                 return (FAILURE);
1017         }
1018 
1019         /*
1020          * Loop thru the entire kcf.conf file, insert, modify or delete
1021          * an entry.
1022          */
1023         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1024                 if (add_it) {
1025                         if (fputs(buffer, pfile_tmp) == EOF) {
1026                                 err = errno;
1027                                 cryptoerror(LOG_STDERR, gettext(
1028                                     "failed to write to a temp file: %s."),
1029                                     strerror(err));
1030                                 rc = FAILURE;
1031                                 break;
1032                         }
1033 
1034                 } else { /* modify or delete */
1035                         this_entry_matches = B_FALSE;
1036 
1037                         if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1038                             buffer[0] == '\n'|| buffer[0] == '\t')) {
1039                                 /*
1040                                  * Get the provider name from this line and
1041                                  * check if this is the entry to be updated
1042                                  * or deleted. Note: can not use "buffer"
1043                                  * directly because strtok will change its
1044                                  * value.
1045                                  */
1046                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
1047                                 if ((name = strtok(buffer2, SEP_COLON)) ==
1048                                     NULL) {
1049                                         rc = FAILURE;
1050                                         break;
1051                                 }
1052 
1053                                 if (strcmp(pent->name, name) == 0) {
1054                                         this_entry_matches = B_TRUE;
1055                                         found_entry = B_TRUE;
1056                                 }
1057                         }
1058 
1059 
1060                         if (!this_entry_matches || !delete_it) {
1061                                 /* write this entry */
1062                                 if (this_entry_matches) {
1063                                         /*
1064                                          * Modify this entry: get the
1065                                          * updated string and place into buffer.
1066                                          */
1067                                         (void) strlcpy(buffer, new_str, BUFSIZ);
1068                                         free(new_str);
1069                                 }
1070                                 /* write the (unchanged or modified) entry */
1071                                 if (fputs(buffer, pfile_tmp) == EOF) {
1072                                         err = errno;
1073                                         cryptoerror(LOG_STDERR, gettext(
1074                                             "failed to write to a temp file: "
1075                                             "%s."), strerror(err));
1076                                         rc = FAILURE;
1077                                         break;
1078                                 }
1079                         }
1080                 }
1081         }
1082 
1083         if ((!delete_it) && (rc != FAILURE)) {
1084                 if (add_it || !found_entry) {
1085                         /* append new entry to end of file */
1086                         if (fputs(new_str, pfile_tmp) == EOF) {
1087                                 err = errno;
1088                                 cryptoerror(LOG_STDERR, gettext(
1089                                     "failed to write to a temp file: %s."),
1090                                     strerror(err));
1091                                 rc = FAILURE;
1092                         }
1093                         free(new_str);
1094                 }
1095         }
1096 
1097         (void) fclose(pfile);
1098         if (fclose(pfile_tmp) != 0) {
1099                 err = errno;
1100                 cryptoerror(LOG_STDERR,
1101                     gettext("failed to close %s: %s"), tmpfile_name,
1102                     strerror(err));
1103                 return (FAILURE);
1104         }
1105 
1106         /* Copy the temporary file to the kcf.conf file */
1107         if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1108                 err = errno;
1109                 cryptoerror(LOG_STDERR,
1110                     gettext("failed to update the configuration - %s"),
1111                     strerror(err));
1112                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1113                     _PATH_KCF_CONF, strerror(err));
1114                 rc = FAILURE;
1115         } else if (chmod(_PATH_KCF_CONF,
1116             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1117                 err = errno;
1118                 cryptoerror(LOG_STDERR,
1119                     gettext("failed to update the configuration - %s"),
1120                     strerror(err));
1121                 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1122                     strerror(err));
1123                 rc = FAILURE;
1124         } else {
1125                 rc = SUCCESS;
1126         }
1127 
1128         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1129                 err = errno;
1130                 cryptoerror(LOG_STDERR, gettext(
1131                     "(Warning) failed to remove %s: %s"),
1132                     tmpfile_name, strerror(err));
1133         }
1134 
1135         return (rc);
1136 }
1137 
1138 
1139 /*
1140  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1141  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1142  * dislist argument.  The "infolist" argument contains the mechanism list
1143  * supported by this provider.
1144  */
1145 int
1146 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1147 mechlist_t *dislist)
1148 {
1149         entry_t         *pent;
1150         mechlist_t      *plist = NULL;
1151         mechlist_t      *phead = NULL;
1152         mechlist_t      *pmech = NULL;
1153         int             rc = SUCCESS;
1154 
1155         pent = *ppent;
1156         if (pent == NULL) {
1157                 return (FAILURE);
1158         }
1159 
1160         if (allflag) {
1161                 free_mechlist(pent->dislist);
1162                 pent->dis_count = get_mech_count(infolist);
1163                 if (!(pent->dislist = dup_mechlist(infolist))) {
1164                         return (FAILURE);
1165                 } else {
1166                         return (SUCCESS);
1167                 }
1168         }
1169 
1170         /*
1171          * Not disable all. Now loop thru the mechanisms specified in the
1172          * dislist.  If the mechanism is not supported by the provider,
1173          * ignore it with a warning.  If the mechanism is disabled already,
1174          * do nothing. Otherwise, prepend it to the beginning of the disabled
1175          * list of the provider.
1176          */
1177         plist = dislist;
1178         while (plist != NULL) {
1179                 if (!is_in_list(plist->name, infolist)) {
1180                         cryptoerror(LOG_STDERR, gettext("(Warning) "
1181                             "%1$s is not a valid mechanism for %2$s."),
1182                             plist->name, pent->name);
1183                 } else if (!is_in_list(plist->name, pent->dislist)) {
1184                         /* Add this mechanism into the disabled list */
1185                         if ((pmech = create_mech(plist->name)) == NULL) {
1186                                 rc = FAILURE;
1187                                 break;
1188                         }
1189 
1190                         if (pent->dislist == NULL) {
1191                                 pent->dislist = pmech;
1192                         } else {
1193                                 phead = pent->dislist;
1194                                 pent->dislist = pmech;
1195                                 pmech->next = phead;
1196                         }
1197                         pent->dis_count++;
1198                 }
1199                 plist = plist->next;
1200         }
1201 
1202         return (rc);
1203 }
1204 
1205 /*
1206  * Remove the mechanism passed, specified by mech, from the list of
1207  * mechanisms, if present in the list. Else, do nothing.
1208  *
1209  * Returns B_TRUE if mechanism is present in the list.
1210  */
1211 boolean_t
1212 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1213 {
1214         int             cnt = 0;
1215         mechlist_t      *ptr, *pptr;
1216         boolean_t       mech_present = B_FALSE;
1217 
1218         ptr = pptr = *pmechlist;
1219 
1220         while (ptr != NULL) {
1221                 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1222                         mech_present = B_TRUE;
1223                         if (ptr == *pmechlist) {
1224                                 pptr = *pmechlist = ptr->next;
1225                                 free(ptr);
1226                                 ptr = pptr;
1227                         } else {
1228                                 pptr->next = ptr->next;
1229                                 free(ptr);
1230                                 ptr = pptr->next;
1231                         }
1232                 } else {
1233                         pptr = ptr;
1234                         ptr = ptr->next;
1235                         cnt++;
1236                 }
1237         }
1238 
1239         /* Only one entry is present */
1240         if (cnt == 0)
1241                 *pmechlist = NULL;
1242 
1243         return (mech_present);
1244 }
1245 
1246 
1247 
1248 /*
1249  * Print out the mechanism policy for a kernel provider that has an entry
1250  * in the kcf.conf file.
1251  *
1252  * The flag has_random is set to B_TRUE if the provider does random
1253  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1254  * has some mechanisms.
1255  *
1256  * If pent is NULL, the provider doesn't have a kcf.conf entry.
1257  */
1258 void
1259 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1260     boolean_t has_mechs)
1261 {
1262         mechlist_t      *ptr = NULL;
1263         boolean_t       rnd_disabled = B_FALSE;
1264 
1265         if (pent != NULL) {
1266                 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1267                 ptr = pent->dislist;
1268         }
1269 
1270         (void) printf("%s:", provname);
1271 
1272         if (has_mechs == B_TRUE) {
1273                 /*
1274                  * TRANSLATION_NOTE
1275                  * This code block may need to be modified a bit to avoid
1276                  * constructing the text message on the fly.
1277                  */
1278                 (void) printf(gettext(" all mechanisms are enabled"));
1279                 if (ptr != NULL)
1280                         (void) printf(gettext(", except "));
1281                 while (ptr != NULL) {
1282                         (void) printf("%s", ptr->name);
1283                         ptr = ptr->next;
1284                         if (ptr != NULL)
1285                                 (void) printf(",");
1286                 }
1287                 if (ptr == NULL)
1288                         (void) printf(".");
1289         }
1290 
1291         /*
1292          * TRANSLATION_NOTE
1293          * "random" is a keyword and not to be translated.
1294          */
1295         if (rnd_disabled)
1296                 (void) printf(gettext(" %s is disabled."), "random");
1297         else if (has_random)
1298                 (void) printf(gettext(" %s is enabled."), "random");
1299         (void) printf("\n");
1300 }
1301 
1302 
1303 /*
1304  * Check if a kernel software provider is in the kernel.
1305  *
1306  * Parameters:
1307  * provname             Provider name
1308  * psoftlist_kernel     Optional software provider list.  If NULL, it will be
1309  *                      obtained from get_soft_list().
1310  * in_kernel            Set to B_TRUE if device is in the kernel, else B_FALSE
1311  */
1312 int
1313 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1314     boolean_t *in_kernel)
1315 {
1316         char            *ptr;
1317         int             i;
1318         boolean_t       psoftlist_allocated = B_FALSE;
1319 
1320         if (provname == NULL) {
1321                 cryptoerror(LOG_STDERR, gettext("internal error."));
1322                 return (FAILURE);
1323         }
1324 
1325         if (psoftlist_kernel == NULL) {
1326                 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1327                         cryptodebug("failed to get the software provider list"
1328                         " from kernel.");
1329                         return (FAILURE);
1330                 }
1331                 psoftlist_allocated = B_TRUE;
1332         }
1333 
1334         *in_kernel = B_FALSE;
1335         ptr = psoftlist_kernel->sl_soft_names;
1336         for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1337                 if (strcmp(provname, ptr) == 0) {
1338                         *in_kernel = B_TRUE;
1339                         break;
1340                 }
1341                 ptr = ptr + strlen(ptr) + 1;
1342         }
1343 
1344         if (psoftlist_allocated)
1345                 free(psoftlist_kernel);
1346 
1347         return (SUCCESS);
1348 }
1349 
1350 
1351 /*
1352  * Check if a kernel hardware provider is in the kernel.
1353  *
1354  * Parameters:
1355  * provname     Provider name
1356  * pdevlist     Optional Hardware Crypto Device List.  If NULL, it will be
1357  *              obtained from get_dev_list().
1358  * in_kernel    Set to B_TRUE if device is in the kernel, otherwise B_FALSE
1359  */
1360 int
1361 check_kernel_for_hard(char *provname,
1362     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1363 {
1364         char            devname[MAXNAMELEN];
1365         int             inst_num;
1366         int             i;
1367         boolean_t       dev_list_allocated = B_FALSE;
1368 
1369         if (provname == NULL) {
1370                 cryptoerror(LOG_STDERR, gettext("internal error."));
1371                 return (FAILURE);
1372         }
1373 
1374         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1375                 return (FAILURE);
1376         }
1377 
1378         if (pdevlist == NULL) {
1379                 if (get_dev_list(&pdevlist) == FAILURE) {
1380                         cryptoerror(LOG_STDERR, gettext("internal error."));
1381                         return (FAILURE);
1382                 }
1383                 dev_list_allocated = B_TRUE;
1384         }
1385 
1386         *in_kernel = B_FALSE;
1387         for (i = 0; i < pdevlist->dl_dev_count; i++) {
1388                 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1389                     (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1390                         *in_kernel = B_TRUE;
1391                         break;
1392                 }
1393         }
1394 
1395         if (dev_list_allocated)
1396                 free(pdevlist);
1397 
1398         return (SUCCESS);
1399 }