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 2009 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 
  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(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                 pent->suplist = phead = pmech;
 219         } else if (disflag) {
 220                 pent->dislist = phead = pmech;
 221         }
 222 
 223         count = 1;
 224         while (next_token) {
 225                 if (next_token = strtok(NULL, SEP_COMMA)) {
 226                         if ((pmech = create_mech(next_token)) == NULL) {
 227                                 rc = FAILURE;
 228                                 break;
 229                         }
 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          */
 574         ptr = mlist;
 575         while (ptr != NULL) {
 576                 found = B_FALSE;
 577                 phead = pcur =  pent->dislist;
 578                 while (!found && pcur) {
 579                         if (strcmp(pcur->name, ptr->name) == 0) {
 580                                 found = B_TRUE;
 581                         } else {
 582                                 phead = pcur;
 583                                 pcur = pcur->next;
 584                         }
 585                 }
 586 
 587                 if (found) {
 588                         if (phead == pcur) {
 589                                 pent->dislist = pent->dislist->next;
 590                                 free(pcur);
 591                         } else {
 592                                 phead->next = pcur->next;
 593                                 free(pcur);
 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       this_entry_matches = B_FALSE;
 922         boolean_t       found_entry = B_FALSE;
 923         FILE            *pfile = NULL;
 924         FILE            *pfile_tmp = NULL;
 925         char            buffer[BUFSIZ];
 926         char            buffer2[BUFSIZ];
 927         char            tmpfile_name[MAXPATHLEN];
 928         char            *name;
 929         char            *new_str = NULL;
 930         int             rc = SUCCESS;
 931 
 932         if (pent == NULL) {
 933                 cryptoerror(LOG_STDERR, gettext("internal error."));
 934                 return (FAILURE);
 935         }
 936 
 937         /* Check the update_mode */
 938         switch (update_mode) {
 939         case ADD_MODE:
 940                 add_it = B_TRUE;
 941                 /* FALLTHROUGH */
 942         case MODIFY_MODE:
 943                 /* Convert the entry a string to add to kcf.conf  */
 944                 if ((new_str = ent2str(pent)) == NULL) {
 945                         return (FAILURE);
 946                 }
 947                 break;
 948         case DELETE_MODE:
 949                 delete_it = B_TRUE;
 950                 break;
 951         default:
 952                 cryptoerror(LOG_STDERR, gettext("internal error."));
 953                 return (FAILURE);
 954         }
 955 
 956         /* Open the kcf.conf file */
 957         if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 958                 err = errno;
 959                 cryptoerror(LOG_STDERR,
 960                     gettext("failed to update the configuration - %s"),
 961                     strerror(err));
 962                 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
 963                 return (FAILURE);
 964         }
 965 
 966         /* Lock the kcf.conf file */
 967         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 968                 err = errno;
 969                 cryptoerror(LOG_STDERR,
 970                     gettext("failed to update the configuration - %s"),
 971                     strerror(err));
 972                 (void) fclose(pfile);
 973                 return (FAILURE);
 974         }
 975 
 976         /*
 977          * Create a temporary file in the /etc/crypto directory to save
 978          * updated configuration file first.
 979          */
 980         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
 981         if (mkstemp(tmpfile_name) == -1) {
 982                 err = errno;
 983                 cryptoerror(LOG_STDERR,
 984                     gettext("failed to create a temporary file - %s"),
 985                     strerror(err));
 986                 (void) fclose(pfile);
 987                 return (FAILURE);
 988         }
 989 
 990         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 991                 err = errno;
 992                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 993                     tmpfile_name, strerror(err));
 994                 (void) fclose(pfile);
 995                 return (FAILURE);
 996         }
 997 
 998         /*
 999          * Loop thru the entire kcf.conf file, insert, modify or delete
1000          * an entry.
1001          */
1002         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1003                 if (add_it) {
1004                         if (fputs(buffer, pfile_tmp) == EOF) {
1005                                 err = errno;
1006                                 cryptoerror(LOG_STDERR, gettext(
1007                                     "failed to write to a temp file: %s."),
1008                                     strerror(err));
1009                                 rc = FAILURE;
1010                                 break;
1011                         }
1012 
1013                 } else { /* modify or delete */
1014                         this_entry_matches = B_FALSE;
1015 
1016                         if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1017                             buffer[0] == '\n'|| buffer[0] == '\t')) {
1018                                 /*
1019                                  * Get the provider name from this line and
1020                                  * check if this is the entry to be updated
1021                                  * or deleted. Note: can not use "buffer"
1022                                  * directly because strtok will change its
1023                                  * value.
1024                                  */
1025                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
1026                                 if ((name = strtok(buffer2, SEP_COLON)) ==
1027                                     NULL) {
1028                                         rc = FAILURE;
1029                                         break;
1030                                 }
1031 
1032                                 if (strcmp(pent->name, name) == 0) {
1033                                         this_entry_matches = B_TRUE;
1034                                         found_entry = B_TRUE;
1035                                 }
1036                         }
1037 
1038 
1039                         if (!this_entry_matches || !delete_it) {
1040                                 /* write this entry */
1041                                 if (this_entry_matches) {
1042                                         /*
1043                                          * Modify this entry: get the
1044                                          * updated string and place into buffer.
1045                                          */
1046                                         (void) strlcpy(buffer, new_str, BUFSIZ);
1047                                         free(new_str);
1048                                 }
1049                                 /* write the (unchanged or modified) entry */
1050                                 if (fputs(buffer, pfile_tmp) == EOF) {
1051                                         err = errno;
1052                                         cryptoerror(LOG_STDERR, gettext(
1053                                             "failed to write to a temp file: "
1054                                             "%s."), strerror(err));
1055                                         rc = FAILURE;
1056                                         break;
1057                                 }
1058                         }
1059                 }
1060         }
1061 
1062         if ((!delete_it) && (rc != FAILURE)) {
1063                 if (add_it || !found_entry) {
1064                         /* append new entry to end of file */
1065                         if (fputs(new_str, pfile_tmp) == EOF) {
1066                                 err = errno;
1067                                 cryptoerror(LOG_STDERR, gettext(
1068                                     "failed to write to a temp file: %s."),
1069                                     strerror(err));
1070                                 rc = FAILURE;
1071                         }
1072                         free(new_str);
1073                 }
1074         }
1075 
1076         (void) fclose(pfile);
1077         if (fclose(pfile_tmp) != 0) {
1078                 err = errno;
1079                 cryptoerror(LOG_STDERR,
1080                     gettext("failed to close %s: %s"), tmpfile_name,
1081                     strerror(err));
1082                 return (FAILURE);
1083         }
1084 
1085         /* Copy the temporary file to the kcf.conf file */
1086         if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1087                 err = errno;
1088                 cryptoerror(LOG_STDERR,
1089                     gettext("failed to update the configuration - %s"),
1090                     strerror(err));
1091                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1092                     _PATH_KCF_CONF, strerror(err));
1093                 rc = FAILURE;
1094         } else if (chmod(_PATH_KCF_CONF,
1095             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1096                 err = errno;
1097                 cryptoerror(LOG_STDERR,
1098                     gettext("failed to update the configuration - %s"),
1099                     strerror(err));
1100                 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1101                     strerror(err));
1102                 rc = FAILURE;
1103         } else {
1104                 rc = SUCCESS;
1105         }
1106 
1107         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1108                 err = errno;
1109                 cryptoerror(LOG_STDERR, gettext(
1110                     "(Warning) failed to remove %s: %s"),
1111                     tmpfile_name, strerror(err));
1112         }
1113 
1114         return (rc);
1115 }
1116 
1117 
1118 /*
1119  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1120  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1121  * dislist argument.  The "infolist" argument contains the mechanism list
1122  * supported by this provider.
1123  */
1124 int
1125 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1126 mechlist_t *dislist)
1127 {
1128         entry_t         *pent;
1129         mechlist_t      *plist = NULL;
1130         mechlist_t      *phead = NULL;
1131         mechlist_t      *pmech = NULL;
1132         int             rc = SUCCESS;
1133 
1134         pent = *ppent;
1135         if (pent == NULL) {
1136                 return (FAILURE);
1137         }
1138 
1139         if (allflag) {
1140                 free_mechlist(pent->dislist);
1141                 pent->dis_count = get_mech_count(infolist);
1142                 if (!(pent->dislist = dup_mechlist(infolist))) {
1143                         return (FAILURE);
1144                 } else {
1145                         return (SUCCESS);
1146                 }
1147         }
1148 
1149         /*
1150          * Not disable all. Now loop thru the mechanisms specified in the
1151          * dislist.  If the mechanism is not supported by the provider,
1152          * ignore it with a warning.  If the mechanism is disabled already,
1153          * do nothing. Otherwise, prepend it to the beginning of the disabled
1154          * list of the provider.
1155          */
1156         plist = dislist;
1157         while (plist != NULL) {
1158                 if (!is_in_list(plist->name, infolist)) {
1159                         cryptoerror(LOG_STDERR, gettext("(Warning) "
1160                             "%1$s is not a valid mechanism for %2$s."),
1161                             plist->name, pent->name);
1162                 } else if (!is_in_list(plist->name, pent->dislist)) {
1163                         /* Add this mechanism into the disabled list */
1164                         if ((pmech = create_mech(plist->name)) == NULL) {
1165                                 rc = FAILURE;
1166                                 break;
1167                         }
1168 
1169                         if (pent->dislist == NULL) {
1170                                 pent->dislist = pmech;
1171                         } else {
1172                                 phead = pent->dislist;
1173                                 pent->dislist = pmech;
1174                                 pmech->next = phead;
1175                         }
1176                         pent->dis_count++;
1177                 }
1178                 plist = plist->next;
1179         }
1180 
1181         return (rc);
1182 }
1183 
1184 /*
1185  * Remove the mechanism passed, specified by mech, from the list of
1186  * mechanisms, if present in the list. Else, do nothing.
1187  *
1188  * Returns B_TRUE if mechanism is present in the list.
1189  */
1190 boolean_t
1191 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1192 {
1193         int             cnt = 0;
1194         mechlist_t      *ptr, *pptr;
1195         boolean_t       mech_present = B_FALSE;
1196 
1197         ptr = pptr = *pmechlist;
1198 
1199         while (ptr != NULL) {
1200                 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1201                         mech_present = B_TRUE;
1202                         if (ptr == *pmechlist) {
1203                                 pptr = *pmechlist = ptr->next;
1204                                 free(ptr);
1205                                 ptr = pptr;
1206                         } else {
1207                                 pptr->next = ptr->next;
1208                                 free(ptr);
1209                                 ptr = pptr->next;
1210                         }
1211                 } else {
1212                         pptr = ptr;
1213                         ptr = ptr->next;
1214                         cnt++;
1215                 }
1216         }
1217 
1218         /* Only one entry is present */
1219         if (cnt == 0)
1220                 *pmechlist = NULL;
1221 
1222         return (mech_present);
1223 }
1224 
1225 
1226 
1227 /*
1228  * Print out the mechanism policy for a kernel provider that has an entry
1229  * in the kcf.conf file.
1230  *
1231  * The flag has_random is set to B_TRUE if the provider does random
1232  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1233  * has some mechanisms.
1234  *
1235  * If pent is NULL, the provider doesn't have a kcf.conf entry.
1236  */
1237 void
1238 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1239     boolean_t has_mechs)
1240 {
1241         mechlist_t      *ptr = NULL;
1242         boolean_t       rnd_disabled = B_FALSE;
1243 
1244         if (pent != NULL) {
1245                 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1246                 ptr = pent->dislist;
1247         }
1248 
1249         (void) printf("%s:", provname);
1250 
1251         if (has_mechs == B_TRUE) {
1252                 /*
1253                  * TRANSLATION_NOTE
1254                  * This code block may need to be modified a bit to avoid
1255                  * constructing the text message on the fly.
1256                  */
1257                 (void) printf(gettext(" all mechanisms are enabled"));
1258                 if (ptr != NULL)
1259                         (void) printf(gettext(", except "));
1260                 while (ptr != NULL) {
1261                         (void) printf("%s", ptr->name);
1262                         ptr = ptr->next;
1263                         if (ptr != NULL)
1264                                 (void) printf(",");
1265                 }
1266                 if (ptr == NULL)
1267                         (void) printf(".");
1268         }
1269 
1270         /*
1271          * TRANSLATION_NOTE
1272          * "random" is a keyword and not to be translated.
1273          */
1274         if (rnd_disabled)
1275                 (void) printf(gettext(" %s is disabled."), "random");
1276         else if (has_random)
1277                 (void) printf(gettext(" %s is enabled."), "random");
1278         (void) printf("\n");
1279 }
1280 
1281 
1282 /*
1283  * Check if a kernel software provider is in the kernel.
1284  *
1285  * Parameters:
1286  * provname             Provider name
1287  * psoftlist_kernel     Optional software provider list.  If NULL, it will be
1288  *                      obtained from get_soft_list().
1289  * in_kernel            Set to B_TRUE if device is in the kernel, else B_FALSE
1290  */
1291 int
1292 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1293     boolean_t *in_kernel)
1294 {
1295         char            *ptr;
1296         int             i;
1297         boolean_t       psoftlist_allocated = B_FALSE;
1298 
1299         if (provname == NULL) {
1300                 cryptoerror(LOG_STDERR, gettext("internal error."));
1301                 return (FAILURE);
1302         }
1303 
1304         if (psoftlist_kernel == NULL) {
1305                 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1306                         cryptodebug("failed to get the software provider list"
1307                         " from kernel.");
1308                         return (FAILURE);
1309                 }
1310                 psoftlist_allocated = B_TRUE;
1311         }
1312 
1313         *in_kernel = B_FALSE;
1314         ptr = psoftlist_kernel->sl_soft_names;
1315         for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1316                 if (strcmp(provname, ptr) == 0) {
1317                         *in_kernel = B_TRUE;
1318                         break;
1319                 }
1320                 ptr = ptr + strlen(ptr) + 1;
1321         }
1322 
1323         if (psoftlist_allocated)
1324                 free(psoftlist_kernel);
1325 
1326         return (SUCCESS);
1327 }
1328 
1329 
1330 /*
1331  * Check if a kernel hardware provider is in the kernel.
1332  *
1333  * Parameters:
1334  * provname     Provider name
1335  * pdevlist     Optional Hardware Crypto Device List.  If NULL, it will be
1336  *              obtained from get_dev_list().
1337  * in_kernel    Set to B_TRUE if device is in the kernel, otherwise B_FALSE
1338  */
1339 int
1340 check_kernel_for_hard(char *provname,
1341     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1342 {
1343         char            devname[MAXNAMELEN];
1344         int             inst_num;
1345         int             i;
1346         boolean_t       dev_list_allocated = B_FALSE;
1347 
1348         if (provname == NULL) {
1349                 cryptoerror(LOG_STDERR, gettext("internal error."));
1350                 return (FAILURE);
1351         }
1352 
1353         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1354                 return (FAILURE);
1355         }
1356 
1357         if (pdevlist == NULL) {
1358                 if (get_dev_list(&pdevlist) == FAILURE) {
1359                         cryptoerror(LOG_STDERR, gettext("internal error."));
1360                         return (FAILURE);
1361                 }
1362                 dev_list_allocated = B_TRUE;
1363         }
1364 
1365         *in_kernel = B_FALSE;
1366         for (i = 0; i < pdevlist->dl_dev_count; i++) {
1367                 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1368                     (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1369                         *in_kernel = B_TRUE;
1370                         break;
1371                 }
1372         }
1373 
1374         if (dev_list_allocated)
1375                 free(pdevlist);
1376 
1377         return (SUCCESS);
1378 }