1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <strings.h>
  31 #include <time.h>
  32 #include <unistd.h>
  33 #include <locale.h>
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include "cryptoadm.h"
  37 
  38 static int err; /* To store errno which may be overwritten by gettext() */
  39 static int build_entrylist(entry_t *, entrylist_t **);
  40 static entry_t *dup_entry(entry_t *);
  41 static mechlist_t *dup_mechlist(mechlist_t *);
  42 static entry_t *getent(char *, entrylist_t *);
  43 static int interpret(char *, entry_t **);
  44 static int parse_dislist(char *, entry_t *);
  45 
  46 
  47 /*
  48  * Duplicate the mechanism list.  A null pointer is returned if the storage
  49  * space available is insufficient or the input argument is NULL.
  50  */
  51 static mechlist_t *
  52 dup_mechlist(mechlist_t *plist)
  53 {
  54         mechlist_t *pres = NULL;
  55         mechlist_t *pcur;
  56         mechlist_t *ptmp;
  57         int rc = SUCCESS;
  58 
  59         while (plist != NULL) {
  60                 if (!(ptmp = create_mech(plist->name))) {
  61                         rc = FAILURE;
  62                         break;
  63                 }
  64 
  65                 if (pres == NULL) {
  66                         pres = pcur = ptmp;
  67                 } else {
  68                         pcur->next = ptmp;
  69                         pcur = pcur->next;
  70                 }
  71                 plist = plist->next;
  72         }
  73 
  74         if (rc != SUCCESS) {
  75                 free_mechlist(pres);
  76                 return (NULL);
  77         }
  78 
  79         return (pres);
  80 }
  81 
  82 
  83 /*
  84  * Get the number of mechanisms in the mechanism list.
  85  */
  86 int
  87 get_mech_count(mechlist_t *plist)
  88 {
  89         int count = 0;
  90 
  91         while (plist != NULL) {
  92                 count++;
  93                 plist = plist->next;
  94         }
  95         return (count);
  96 }
  97 
  98 
  99 /*
 100  * Duplicate an entry.  A null pointer is returned if the storage space
 101  * available is insufficient or the input argument is NULL.
 102  */
 103 static entry_t *
 104 dup_entry(entry_t *pent1)
 105 {
 106         entry_t *pent2 = NULL;
 107 
 108         if (pent1 == NULL) {
 109                 return (NULL);
 110         }
 111 
 112         if ((pent2 = malloc(sizeof (entry_t))) == NULL) {
 113                 cryptodebug("out of memory.");
 114                 return (NULL);
 115         }
 116 
 117         (void) strlcpy(pent2->name, pent1->name, sizeof (pent2->name));
 118         pent2->sup_count = pent1->sup_count;
 119         pent2->dis_count = pent1->dis_count;
 120         pent2->suplist = NULL;
 121         pent2->dislist = NULL;
 122         if (pent1->suplist != NULL) {
 123                 pent2->suplist = dup_mechlist(pent1->suplist);
 124                 if (pent2->suplist == NULL) {
 125                         free_entry(pent2);
 126                         return (NULL);
 127                 }
 128         }
 129         if (pent1->dislist != NULL) {
 130                 pent2->dislist = dup_mechlist(pent1->dislist);
 131                 if (pent2->dislist == NULL) {
 132                         free_entry(pent2);
 133                         return (NULL);
 134                 }
 135         }
 136 
 137         return (pent2);
 138 }
 139 
 140 
 141 /*
 142  * This routine parses the disabledlist or the supportedlist of an entry
 143  * in the kcf.conf configuration file.
 144  *
 145  * Arguments:
 146  *      buf: an input argument which is a char string with the format of
 147  *           "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
 148  *      pent: the entry for the disabledlist.  This is an IN/OUT argument.
 149  *
 150  * Return value: SUCCESS or FAILURE.
 151  */
 152 static int
 153 parse_dislist(char *buf, entry_t *pent)
 154 {
 155         mechlist_t *pmech;
 156         mechlist_t *phead;
 157         char *next_token;
 158         char *value;
 159         int count;
 160         int supflag = B_FALSE;
 161         int disflag = B_FALSE;
 162         int rc = SUCCESS;
 163 
 164         if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
 165                 supflag = B_TRUE;
 166         } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
 167                 disflag = B_TRUE;
 168         } else {
 169                 /* should not come here */
 170                 return (FAILURE);
 171         }
 172 
 173         if (value = strpbrk(buf, SEP_EQUAL)) {
 174                 value++; /* get rid of = */
 175         } else {
 176                 cryptodebug("failed to parse the kcf.conf file.");
 177                 return (FAILURE);
 178         }
 179 
 180         if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
 181                 cryptodebug("failed to parse the kcf.conf file.");
 182                 return (FAILURE);
 183         }
 184 
 185         if ((pmech = create_mech(next_token)) == NULL) {
 186                 return (FAILURE);
 187         }
 188 
 189         if (supflag) {
 190                 pent->suplist = phead = pmech;
 191         } else if (disflag) {
 192                 pent->dislist = phead = pmech;
 193         }
 194 
 195         count = 1;
 196         while (next_token) {
 197                 if (next_token = strtok(NULL, SEP_COMMA)) {
 198                         if ((pmech = create_mech(next_token)) == NULL) {
 199                                 rc = FAILURE;
 200                                 break;
 201                         }
 202                         count++;
 203                         phead->next = pmech;
 204                         phead = phead->next;
 205                 }
 206         }
 207 
 208         if (rc == SUCCESS) {
 209                 if (supflag) {
 210                         pent->sup_count = count;
 211                 } else if (disflag) {
 212                         pent->dis_count = count;
 213                 }
 214         } else {
 215                 free_mechlist(phead);
 216         }
 217 
 218         return (rc);
 219 }
 220 
 221 
 222 
 223 /*
 224  * This routine converts a char string into an entry_t structure
 225  */
 226 static int
 227 interpret(char *buf, entry_t **ppent)
 228 {
 229         entry_t *pent;
 230         char *token1;
 231         char *token2;
 232         char *token3;
 233         int rc;
 234 
 235         if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
 236                 return (FAILURE);
 237         };
 238 
 239         pent = malloc(sizeof (entry_t));
 240         if (pent == NULL) {
 241                 cryptodebug("out of memory.");
 242                 return (FAILURE);
 243         }
 244         (void) strlcpy(pent->name, token1, sizeof (pent->name));
 245         pent->suplist = NULL;
 246         pent->dislist = NULL;
 247         pent->sup_count = 0;
 248         pent->dis_count = 0;
 249 
 250         if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 251                 /* The entry contains a provider name only */
 252                 free_entry(pent);
 253                 return (FAILURE);
 254         }
 255 
 256         /* need to get token3 first to satisfy nested strtok invocations */
 257         token3 = strtok(NULL, SEP_SEMICOLON);
 258 
 259         if (token2 && ((rc = parse_dislist(token2, pent)) != SUCCESS)) {
 260                 free_entry(pent);
 261                 return (rc);
 262         }
 263 
 264         if (token3 && ((rc = parse_dislist(token3, pent)) != SUCCESS)) {
 265                 free_entry(pent);
 266                 return (rc);
 267         }
 268 
 269         *ppent = pent;
 270         return (SUCCESS);
 271 }
 272 
 273 
 274 /*
 275  * Add an entry to the end of an entry list. If the entry list is NULL, will
 276  * create an entry list with the pent.
 277  */
 278 static int
 279 build_entrylist(entry_t *pent, entrylist_t **pplist)
 280 {
 281         entrylist_t *pentlist;
 282         entrylist_t *pcur;
 283 
 284         pentlist = malloc(sizeof (entrylist_t));
 285         if (pentlist == NULL) {
 286                 cryptodebug("out of memory.");
 287                 return (FAILURE);
 288         }
 289         pentlist->pent = pent;
 290         pentlist->next = NULL;
 291 
 292         if (*pplist) {
 293                 pcur = *pplist;
 294                 while (pcur->next != NULL)
 295                         pcur = pcur->next;
 296                 pcur->next = pentlist;
 297         } else { /* empty list */
 298                 *pplist = pentlist;
 299         }
 300 
 301         return (SUCCESS);
 302 }
 303 
 304 
 305 
 306 /*
 307  * Find the entry with the "provname" name from the entry list and duplicate
 308  * it.
 309  */
 310 static entry_t *
 311 getent(char *provname, entrylist_t *entrylist)
 312 {
 313         boolean_t       found = B_FALSE;
 314         entry_t         *pent1 = NULL;
 315 
 316         if ((provname == NULL) || (entrylist == NULL)) {
 317                 return (NULL);
 318         }
 319 
 320         while (!found && entrylist) {
 321                 if (strcmp(entrylist->pent->name, provname) == 0) {
 322                         found = B_TRUE;
 323                         pent1 = entrylist->pent;
 324                 } else {
 325                         entrylist = entrylist->next;
 326                 }
 327         }
 328 
 329         if (!found) {
 330                 return (NULL);
 331         }
 332 
 333         /* duplicate the entry to be returned */
 334         return (dup_entry(pent1));
 335 }
 336 
 337 
 338 
 339 void
 340 free_entry(entry_t  *pent)
 341 {
 342         if (pent == NULL) {
 343                 return;
 344         } else {
 345                 free_mechlist(pent->suplist);
 346                 free_mechlist(pent->dislist);
 347                 free(pent);
 348         }
 349 }
 350 
 351 
 352 void
 353 free_entrylist(entrylist_t *entrylist)
 354 {
 355         entrylist_t *pnext;
 356 
 357         while (entrylist != NULL) {
 358                 pnext = entrylist->next;
 359                 free_entry(entrylist->pent);
 360                 entrylist = pnext;
 361         }
 362 }
 363 
 364 
 365 /*
 366  * Convert an entry to a string.  This routine builds a string for the entry
 367  * to be inserted in the config file.  Based on the content of each entry,
 368  * the result string can be one of the 4 forms:
 369  *  - name
 370  *  - name:supportedlist=m1,m2,...,mj
 371  *  - name:disabledlist=m1,m2,...,mj
 372  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
 373  *
 374  * Note that the caller is responsible for freeing the returned string.
 375  */
 376 char *
 377 ent2str(entry_t *pent)
 378 {
 379         char    *buf;
 380         mechlist_t  *phead;
 381         boolean_t supflag = B_FALSE;
 382 
 383 
 384         if (pent == NULL) {
 385                 return (NULL);
 386         }
 387 
 388         if ((buf = malloc(BUFSIZ)) == NULL) {
 389                 return (NULL);
 390         }
 391 
 392         /* convert the provider name */
 393         if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
 394                 free(buf);
 395                 return (NULL);
 396         }
 397 
 398         /* convert the supported list if any */
 399         phead = pent->suplist;
 400         if (phead != NULL) {
 401                 supflag = B_TRUE;
 402 
 403                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
 404                         free(buf);
 405                         return (NULL);
 406                 }
 407 
 408                 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
 409                         free(buf);
 410                         return (NULL);
 411                 }
 412 
 413                 while (phead != NULL) {
 414                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
 415                                 free(buf);
 416                                 return (NULL);
 417                         }
 418 
 419                         phead = phead->next;
 420                         if (phead != NULL) {
 421                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 422                                     >= BUFSIZ) {
 423                                         free(buf);
 424                                         return (NULL);
 425                                 }
 426                         }
 427                 }
 428         }
 429 
 430         /* convert the disabled list if any */
 431         phead = pent->dislist;
 432         if (phead != NULL) {
 433                 if (supflag) {
 434                         if (strlcat(buf, ";disabledlist=", BUFSIZ) >= BUFSIZ) {
 435                                 free(buf);
 436                                 return (NULL);
 437                         }
 438                 } else {
 439                         if (strlcat(buf, ":disabledlist=", BUFSIZ) >= BUFSIZ) {
 440                                 free(buf);
 441                                 return (NULL);
 442                         }
 443                 }
 444 
 445                 while (phead != NULL) {
 446                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
 447                                 free(buf);
 448                                 return (NULL);
 449                         }
 450 
 451                         phead = phead->next;
 452                         if (phead != NULL) {
 453                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
 454                                     >= BUFSIZ) {
 455                                         free(buf);
 456                                         return (NULL);
 457                                 }
 458                         }
 459                 }
 460         }
 461 
 462         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
 463                 free(buf);
 464                 return (NULL);
 465         }
 466 
 467         return (buf);
 468 }
 469 
 470 
 471 /*
 472  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
 473  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
 474  * argument "mlist".  The result will be stored in ppent also.
 475  */
 476 int
 477 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
 478 {
 479         entry_t *pent;
 480         mechlist_t *phead; /* the current and resulting disabled list */
 481         mechlist_t *ptr;
 482         mechlist_t *pcur;
 483         boolean_t found;
 484 
 485         pent = *ppent;
 486         if (pent == NULL) {
 487                 return (FAILURE);
 488         }
 489 
 490         if (allflag) {
 491                 free_mechlist(pent->dislist);
 492                 pent->dis_count = 0;
 493                 pent->dislist = NULL;
 494                 return (SUCCESS);
 495         }
 496 
 497         /*
 498          * for each mechanism in the to-be-enabled mechanism list,
 499          * -    check if it is in the current disabled list
 500          * -    if found, delete it from the disabled list
 501          *      otherwise, give a warning.
 502          */
 503         ptr = mlist;
 504         while (ptr != NULL) {
 505                 found = B_FALSE;
 506                 phead = pcur =  pent->dislist;
 507                 while (!found && pcur) {
 508                         if (strcmp(pcur->name, ptr->name) == 0) {
 509                                 found = B_TRUE;
 510                         } else {
 511                                 phead = pcur;
 512                                 pcur = pcur->next;
 513                         }
 514                 }
 515 
 516                 if (found) {
 517                         if (phead == pcur) {
 518                                 pent->dislist = pent->dislist->next;
 519                                 free(pcur);
 520                         } else {
 521                                 phead->next = pcur->next;
 522                                 free(pcur);
 523                         }
 524                         pent->dis_count--;
 525                 } else {
 526                         cryptoerror(LOG_STDERR, gettext(
 527                             "(Warning) %1$s is either enabled already or not "
 528                             "a valid mechanism for %2$s"), ptr->name,
 529                             pent->name);
 530                 }
 531                 ptr = ptr->next;
 532         }
 533 
 534         if (pent->dis_count == 0) {
 535                 pent->dislist = NULL;
 536         }
 537 
 538         return (SUCCESS);
 539 
 540 }
 541 
 542 
 543 boolean_t
 544 is_device(char *path)
 545 {
 546         if (strchr(path, SEP_SLASH) != NULL) {
 547                 return (B_TRUE);
 548         } else {
 549                 return (B_FALSE);
 550         }
 551 }
 552 
 553 /*
 554  * Split a hardware provider name with the "name/inst_num" format into
 555  * a name and a number.
 556  */
 557 int
 558 split_hw_provname(char *provname, char *pname, int *inst_num)
 559 {
 560         char    name[MAXNAMELEN];
 561         char    *inst_str;
 562 
 563         if (provname == NULL) {
 564                 return (FAILURE);
 565         }
 566 
 567         (void) strlcpy(name, provname, MAXNAMELEN);
 568         if (strtok(name, "/") == NULL) {
 569                 return (FAILURE);
 570         }
 571 
 572         if ((inst_str = strtok(NULL, "/")) == NULL) {
 573                 return (FAILURE);
 574         }
 575 
 576         (void) strlcpy(pname, name, MAXNAMELEN);
 577         *inst_num = atoi(inst_str);
 578 
 579         return (SUCCESS);
 580 }
 581 
 582 
 583 /*
 584  * Retrieve information from kcf.conf and build a device entry list and
 585  * a software entry list
 586  */
 587 int
 588 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 589 {
 590         FILE *pfile;
 591         char buffer[BUFSIZ];
 592         int len;
 593         entry_t *pent = NULL;
 594         int rc = SUCCESS;
 595 
 596         if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
 597                 cryptodebug("failed to open the kcf.conf file for read only");
 598                 return (FAILURE);
 599         }
 600 
 601         *ppdevlist = NULL;
 602         *ppsoftlist = NULL;
 603         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 604                 if (buffer[0] == '#' || buffer[0] == ' ' ||
 605                     buffer[0] == '\n'|| buffer[0] == '\t') {
 606                         continue;   /* ignore comment lines */
 607                 }
 608 
 609                 len = strlen(buffer);
 610                 if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
 611                         len--;
 612                 }
 613                 buffer[len] = '\0';
 614 
 615                 if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
 616                         if (is_device(pent->name)) {
 617                                 rc = build_entrylist(pent, ppdevlist);
 618                         } else {
 619                                 rc = build_entrylist(pent, ppsoftlist);
 620                         }
 621                 } else {
 622                         cryptoerror(LOG_STDERR, gettext(
 623                             "failed to parse configuration."));
 624                 }
 625 
 626                 if (rc != SUCCESS) {
 627                         free_entrylist(*ppdevlist);
 628                         free_entrylist(*ppsoftlist);
 629                         free_entry(pent);
 630                         break;
 631                 }
 632         }
 633 
 634         (void) fclose(pfile);
 635         return (rc);
 636 }
 637 
 638 /*
 639  * Retrieve information from admin device and build a device entry list and
 640  * a software entry list.  This is used where there is no kcf.conf, e.g.
 641  * non-global zone.
 642  */
 643 int
 644 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 645 {
 646         crypto_get_dev_list_t *pdevlist_kernel = NULL;
 647         crypto_get_soft_list_t *psoftlist_kernel = NULL;
 648         char *devname;
 649         int inst_num;
 650         int mcount;
 651         mechlist_t *pmech;
 652         entry_t *pent = NULL;
 653         int i;
 654         char *psoftname;
 655         entrylist_t *tmp_pdev = NULL;
 656         entrylist_t *tmp_psoft = NULL;
 657 
 658         if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 659                 cryptodebug("failed to get hardware provider list from kernel");
 660                 return (FAILURE);
 661         }
 662 
 663         for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
 664                 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
 665                 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
 666                 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
 667 
 668                 pmech = NULL;
 669                 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
 670                     SUCCESS) {
 671                         cryptodebug(
 672                             "failed to retrieve the mechanism list for %s/%d.",
 673                             devname, inst_num);
 674                         goto fail_out;
 675                 }
 676 
 677                 if ((pent = malloc(sizeof (entry_t))) == NULL) {
 678                         cryptodebug("out of memory.");
 679                         free_mechlist(pmech);
 680                         goto fail_out;
 681                 }
 682 
 683                 (void) strlcpy(pent->name, devname, MAXNAMELEN);
 684                 pent->suplist = pmech;
 685                 pent->sup_count = mcount;
 686                 pent->dislist = NULL;
 687                 pent->dis_count = 0;
 688 
 689                 if (build_entrylist(pent, &tmp_pdev) != SUCCESS) {
 690                         goto fail_out;
 691                 }
 692 
 693                 /* because incorporated in tmp_pdev */
 694                 pent = NULL;
 695         }
 696 
 697         free(pdevlist_kernel);
 698         pdevlist_kernel = NULL;
 699 
 700         if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
 701                 cryptodebug("failed to get software provider list from kernel");
 702                 goto fail_out;
 703         }
 704 
 705         for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
 706             i < psoftlist_kernel->sl_soft_count;
 707             i++, psoftname = psoftname + strlen(psoftname) + 1) {
 708                 pmech = NULL;
 709                 if (get_soft_info(psoftname, &pmech) != SUCCESS) {
 710                         cryptodebug(
 711                             "failed to retrieve the mechanism list for %s.",
 712                             psoftname);
 713                         goto fail_out;
 714                 }
 715 
 716                 if ((pent = malloc(sizeof (entry_t))) == NULL) {
 717                         cryptodebug("out of memory.");
 718                         free_mechlist(pmech);
 719                         goto fail_out;
 720                 }
 721 
 722                 (void) strlcpy(pent->name, psoftname, MAXNAMELEN);
 723                 pent->suplist = pmech;
 724                 pent->sup_count = get_mech_count(pmech);
 725                 pent->dislist = NULL;
 726                 pent->dis_count = 0;
 727 
 728                 if (build_entrylist(pent, &tmp_psoft) != SUCCESS) {
 729                         goto fail_out;
 730                 }
 731         }
 732 
 733         free(psoftlist_kernel);
 734         psoftlist_kernel = NULL;
 735 
 736         *ppdevlist = tmp_pdev;
 737         *ppsoftlist = tmp_psoft;
 738 
 739         return (SUCCESS);
 740 
 741 fail_out:
 742         if (pent != NULL)
 743                 free_entry(pent);
 744 
 745         free_entrylist(tmp_pdev);
 746         free_entrylist(tmp_psoft);
 747 
 748         if (pdevlist_kernel != NULL)
 749                 free(pdevlist_kernel);
 750         if (psoftlist_kernel != NULL)
 751                 free(psoftlist_kernel);
 752 
 753         return (FAILURE);
 754 }
 755 
 756 /*
 757  * Find the entry in the "kcf.conf" file with "provname" as the provider name.
 758  * Return the entry if found, otherwise return NULL.
 759  */
 760 entry_t *
 761 getent_kef(char *provname)
 762 {
 763         entrylist_t *pdevlist = NULL;
 764         entrylist_t *psoftlist = NULL;
 765         entry_t *pent = NULL;
 766 
 767         if (get_kcfconf_info(&pdevlist, &psoftlist) != SUCCESS) {
 768                 return (NULL);
 769         }
 770 
 771         if (is_device(provname)) {
 772                 pent = getent(provname, pdevlist);
 773         } else {
 774                 pent = getent(provname, psoftlist);
 775         }
 776 
 777         free_entrylist(pdevlist);
 778         free_entrylist(psoftlist);
 779 
 780         return (pent);
 781 }
 782 
 783 /*
 784  * Print out the provider name and the mechanism list.
 785  */
 786 void
 787 print_mechlist(char *provname, mechlist_t *pmechlist)
 788 {
 789         mechlist_t *ptr;
 790 
 791         if (provname == NULL) {
 792                 return;
 793         }
 794 
 795         (void) printf("%s: ", provname);
 796         if (pmechlist == NULL) {
 797                 (void) printf(gettext("No mechanisms presented.\n"));
 798                 return;
 799         }
 800 
 801         ptr = pmechlist;
 802         while (ptr != NULL) {
 803                 (void) printf("%s", ptr->name);
 804                 ptr = ptr->next;
 805                 if (ptr == NULL) {
 806                         (void) printf("\n");
 807                 } else {
 808                         (void) printf(",");
 809                 }
 810         }
 811 }
 812 
 813 
 814 /*
 815  * Update the kcf.conf file based on the specified entry and the update mode.
 816  * - If update_mode is MODIFY_MODE or DELETE_MODE, the entry with the same
 817  *   provider name will be modified or deleted.
 818  * - If update_mode is ADD_MODE, this must be a hardware provider without
 819  *   an entry in the kcf.conf file yet.  Need to locate its driver package
 820  *   bracket and insert an entry into the bracket.
 821  */
 822 int
 823 update_kcfconf(entry_t *pent, int update_mode)
 824 {
 825         boolean_t       add_it = B_FALSE;
 826         boolean_t       delete_it = B_FALSE;
 827         boolean_t       found_package = B_FALSE;
 828         boolean_t       found_entry = B_FALSE;
 829         FILE    *pfile;
 830         FILE    *pfile_tmp;
 831         char    buffer[BUFSIZ];
 832         char    buffer2[BUFSIZ];
 833         char    devname[MAXNAMELEN];
 834         char    tmpfile_name[MAXPATHLEN];
 835         char    *name;
 836         char    *str;
 837         char    *new_str = NULL;
 838         int     inst_num;
 839         int rc = SUCCESS;
 840 
 841 
 842         if (pent == NULL) {
 843                 cryptoerror(LOG_STDERR, gettext("internal error."));
 844                 return (FAILURE);
 845         }
 846 
 847         /* Check the update_mode */
 848         if (update_mode == ADD_MODE) {
 849                 add_it = B_TRUE;
 850                 /* Get the hardware provider name first */
 851                 if (split_hw_provname(pent->name, devname, &inst_num) ==
 852                     FAILURE) {
 853                         return (FAILURE);
 854                 }
 855 
 856                 /* Convert the entry to be a string  */
 857                 if ((new_str = ent2str(pent)) == NULL) {
 858                         return (FAILURE);
 859                 }
 860         } else if (update_mode == DELETE_MODE) {
 861                 delete_it = B_TRUE;
 862         } else if (update_mode != MODIFY_MODE) {
 863                 cryptoerror(LOG_STDERR, gettext("internal error."));
 864                 return (FAILURE);
 865         }
 866 
 867 
 868         /* Open the kcf.conf file */
 869         if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 870                 err = errno;
 871                 cryptoerror(LOG_STDERR,
 872                     gettext("failed to update the configuration - %s"),
 873                     strerror(err));
 874                 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
 875                 return (FAILURE);
 876         }
 877 
 878         /* Lock the kcf.conf file */
 879         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 880                 err = errno;
 881                 cryptoerror(LOG_STDERR,
 882                     gettext("failed to update the configuration - %s"),
 883                         strerror(err));
 884                 (void) fclose(pfile);
 885                 return (FAILURE);
 886         }
 887 
 888         /*
 889          * Create a temporary file in the /etc/crypto directory to save
 890          * updated configuration file first.
 891          */
 892         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
 893         if (mkstemp(tmpfile_name) == -1) {
 894                 err = errno;
 895                 cryptoerror(LOG_STDERR,
 896                     gettext("failed to create a temporary file - %s"),
 897                     strerror(err));
 898                 (void) fclose(pfile);
 899                 return (FAILURE);
 900         }
 901 
 902         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 903                 err = errno;
 904                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 905                     tmpfile_name, strerror(err));
 906                 (void) fclose(pfile);
 907                 return (FAILURE);
 908         }
 909 
 910         /*
 911          * Loop thru the entire kcf.conf file, insert, modify or delete
 912          * an entry.
 913          */
 914         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 915                 if (add_it) {
 916                         /* always keep the current line */
 917                         if (fputs(buffer, pfile_tmp) == EOF) {
 918                                 err = errno;
 919                                 cryptoerror(LOG_STDERR, gettext(
 920                                     "failed to write to a temp file: %s."),
 921                                     strerror(err));
 922                                 rc = FAILURE;
 923                                 break;
 924                         }
 925 
 926                         /*
 927                          * If the current position is the beginning of a driver
 928                          * package and if the driver name matches the hardware
 929                          * provider name, then we want to insert the entry
 930                          * here.
 931                          */
 932                         if ((strstr(buffer, HW_DRIVER_STRING) != NULL) &&
 933                             (strstr(buffer, devname) != NULL)) {
 934                                 found_package = B_TRUE;
 935                                 if (fputs(new_str, pfile_tmp) == EOF) {
 936                                         err = errno;
 937                                         cryptoerror(LOG_STDERR, gettext(
 938                                             "failed to write to a temp file: "
 939                                             "%s."), strerror(err));
 940                                         rc = FAILURE;
 941                                         break;
 942                                 }
 943                         }
 944                 } else { /* modify or delete */
 945                         found_entry = B_FALSE;
 946                         if (!(buffer[0] == '#' || buffer[0] == ' ' ||
 947                             buffer[0] == '\n'|| buffer[0] == '\t')) {
 948                                 /*
 949                                  * Get the provider name from this line and
 950                                  * check if this is the entry to be updated
 951                                  * or deleted. Note: can not use "buffer"
 952                                  * directly because strtok will change its
 953                                  * value.
 954                                  */
 955                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
 956                                 if ((name = strtok(buffer2, SEP_COLON)) ==
 957                                     NULL) {
 958                                         rc = FAILURE;
 959                                         break;
 960                                 }
 961 
 962                                 if (strcmp(pent->name, name) == 0) {
 963                                         found_entry = B_TRUE;
 964                                 }
 965                         }
 966 
 967                         if (found_entry && !delete_it) {
 968                                 /*
 969                                  * This is the entry to be updated; get the
 970                                  * updated string and place into buffer.
 971                                  */
 972                                 if ((str = ent2str(pent)) == NULL) {
 973                                         rc = FAILURE;
 974                                         break;
 975                                 } else {
 976                                         (void) strlcpy(buffer, str, BUFSIZ);
 977                                         free(str);
 978                                 }
 979                         }
 980 
 981                         if (!(found_entry && delete_it)) {
 982                                 /* This is the entry to be updated/reserved */
 983                                 if (fputs(buffer, pfile_tmp) == EOF) {
 984                                         err = errno;
 985                                         cryptoerror(LOG_STDERR, gettext(
 986                                             "failed to write to a temp file: "
 987                                             "%s."), strerror(err));
 988                                         rc = FAILURE;
 989                                         break;
 990                                 }
 991                         }
 992                 }
 993         }
 994 
 995         if (add_it) {
 996                 free(new_str);
 997         }
 998 
 999         if ((add_it && !found_package) || (rc == FAILURE)) {
1000                 if (add_it && !found_package) {
1001                         cryptoerror(LOG_STDERR,
1002                             gettext("failed to update configuration - no "
1003                             "driver package information."));
1004                 }
1005 
1006                 (void) fclose(pfile);
1007                 (void) fclose(pfile_tmp);
1008                 if (unlink(tmpfile_name) != 0) {
1009                         err = errno;
1010                         cryptoerror(LOG_STDERR, gettext(
1011                             "(Warning) failed to remove %s: %s"),
1012                             tmpfile_name, strerror(err));
1013                 }
1014                 return (FAILURE);
1015         }
1016 
1017         (void) fclose(pfile);
1018         if (fclose(pfile_tmp) != 0) {
1019                 err = errno;
1020                 cryptoerror(LOG_STDERR,
1021                     gettext("failed to close %s: %s"), tmpfile_name,
1022                     strerror(err));
1023                 return (FAILURE);
1024         }
1025 
1026         /* Copy the temporary file to the kcf.conf file */
1027         if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1028                 err = errno;
1029                 cryptoerror(LOG_STDERR,
1030                     gettext("failed to update the configuration - %s"),
1031                     strerror(err));
1032                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1033                     _PATH_KCF_CONF, strerror(err));
1034                 rc = FAILURE;
1035         } else if (chmod(_PATH_KCF_CONF,
1036             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1037                 err = errno;
1038                 cryptoerror(LOG_STDERR,
1039                     gettext("failed to update the configuration - %s"),
1040                     strerror(err));
1041                 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1042                     strerror(err));
1043                 rc = FAILURE;
1044         } else {
1045                 rc = SUCCESS;
1046         }
1047 
1048         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1049                 err = errno;
1050                 cryptoerror(LOG_STDERR, gettext(
1051                     "(Warning) failed to remove %s: %s"),
1052                     tmpfile_name, strerror(err));
1053         }
1054 
1055         return (rc);
1056 }
1057 
1058 
1059 /*
1060  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1061  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1062  * dislist argument.  The "infolist" argument contains the mechanism list
1063  * supported by this provider.
1064  */
1065 int
1066 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1067 mechlist_t *dislist)
1068 {
1069         entry_t *pent;
1070         mechlist_t *plist;
1071         mechlist_t *phead;
1072         mechlist_t *pmech;
1073         int rc = SUCCESS;
1074 
1075         pent = *ppent;
1076         if (pent == NULL) {
1077                 return (FAILURE);
1078         }
1079 
1080         if (allflag) {
1081                 free_mechlist(pent->dislist);
1082                 pent->dis_count = get_mech_count(infolist);
1083                 if (!(pent->dislist = dup_mechlist(infolist))) {
1084                         return (FAILURE);
1085                 } else {
1086                         return (SUCCESS);
1087                 }
1088         }
1089 
1090         /*
1091          * Not disable all. Now loop thru the mechanisms specified in the
1092          * dislist.  If the mechanism is not supported by the provider,
1093          * ignore it with a warning.  If the mechanism is disabled already,
1094          * do nothing. Otherwise, prepend it to the beginning of the disabled
1095          * list of the provider.
1096          */
1097         plist = dislist;
1098         while (plist != NULL) {
1099                 if (!is_in_list(plist->name, infolist)) {
1100                         cryptoerror(LOG_STDERR, gettext("(Warning) "
1101                             "%1$s is not a valid mechanism for %2$s."),
1102                             plist->name, pent->name);
1103                 } else if (!is_in_list(plist->name, pent->dislist)) {
1104                         /* Add this mechanism into the disabled list */
1105                         if ((pmech = create_mech(plist->name)) == NULL) {
1106                                 rc = FAILURE;
1107                                 break;
1108                         }
1109 
1110                         if (pent->dislist == NULL) {
1111                                 pent->dislist = pmech;
1112                         } else {
1113                                 phead = pent->dislist;
1114                                 pent->dislist = pmech;
1115                                 pmech->next = phead;
1116                         }
1117                         pent->dis_count++;
1118                 }
1119                 plist = plist->next;
1120         }
1121 
1122         return (rc);
1123 }
1124 
1125 /*
1126  * Remove the mechanism passed, specified by mech, from the list of
1127  * mechanisms, if present in the list. Else, do nothing.
1128  *
1129  * Returns B_TRUE if mechanism is present in the list.
1130  */
1131 boolean_t
1132 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1133 {
1134         int cnt = 0;
1135         mechlist_t *ptr, *pptr;
1136         boolean_t mech_present = B_FALSE;
1137 
1138         ptr = pptr = *pmechlist;
1139 
1140         while (ptr != NULL) {
1141                 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1142                         mech_present = B_TRUE;
1143                         if (ptr == *pmechlist) {
1144                                 pptr = *pmechlist = ptr->next;
1145                                 free(ptr);
1146                                 ptr = pptr;
1147                         } else {
1148                                 pptr->next = ptr->next;
1149                                 free(ptr);
1150                                 ptr = pptr->next;
1151                         }
1152                 } else {
1153                         pptr = ptr;
1154                         ptr = ptr->next;
1155                         cnt++;
1156                 }
1157         }
1158 
1159         /* Only one entry is present */
1160         if (cnt == 0)
1161                 *pmechlist = NULL;
1162 
1163         return (mech_present);
1164 }
1165 
1166 
1167 
1168 /*
1169  * Print out the mechanism policy for a kernel provider that has an entry
1170  * in the kcf.conf file.
1171  *
1172  * The flag has_random is set to B_TRUE if the provider does random
1173  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1174  * has some mechanisms.
1175  */
1176 void
1177 print_kef_policy(entry_t *pent, boolean_t has_random, boolean_t has_mechs)
1178 {
1179         mechlist_t *ptr;
1180         boolean_t rnd_disabled = B_FALSE;
1181 
1182         if (pent == NULL) {
1183                 return;
1184         }
1185 
1186         rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1187         ptr = pent->dislist;
1188 
1189         (void) printf("%s:", pent->name);
1190 
1191         if (has_mechs == B_TRUE) {
1192                 /*
1193                  * TRANSLATION_NOTE
1194                  * This code block may need to be modified a bit to avoid
1195                  * constructing the text message on the fly.
1196                  */
1197                 (void) printf(gettext(" all mechanisms are enabled"));
1198                 if (ptr != NULL)
1199                         (void) printf(gettext(", except "));
1200                 while (ptr != NULL) {
1201                         (void) printf("%s", ptr->name);
1202                         ptr = ptr->next;
1203                         if (ptr != NULL)
1204                                 (void) printf(",");
1205                 }
1206                 if (ptr == NULL)
1207                         (void) printf(".");
1208         }
1209 
1210         /*
1211          * TRANSLATION_NOTE
1212          * "random" is a keyword and not to be translated.
1213          */
1214         if (rnd_disabled)
1215                 (void) printf(gettext(" %s is disabled."), "random");
1216         else if (has_random)
1217                 (void) printf(gettext(" %s is enabled."), "random");
1218         (void) printf("\n");
1219 }
1220 
1221 /*
1222  * Check if a kernel software provider is in the kernel.
1223  */
1224 int
1225 check_active_for_soft(char *provname, boolean_t *is_active)
1226 {
1227         crypto_get_soft_list_t  *psoftlist_kernel = NULL;
1228         char    *ptr;
1229         int     i;
1230 
1231         if (provname == NULL) {
1232                 cryptoerror(LOG_STDERR, gettext("internal error."));
1233                 return (FAILURE);
1234         }
1235 
1236         if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1237                 cryptodebug("failed to get the software provider list from"
1238                     "kernel.");
1239                 return (FAILURE);
1240         }
1241 
1242         *is_active = B_FALSE;
1243         ptr = psoftlist_kernel->sl_soft_names;
1244         for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1245                 if (strcmp(provname, ptr) == 0) {
1246                         *is_active = B_TRUE;
1247                         break;
1248                 }
1249                 ptr = ptr + strlen(ptr) + 1;
1250         }
1251         free(psoftlist_kernel);
1252 
1253         return (SUCCESS);
1254 }
1255 
1256 
1257 /*
1258  * Check if a kernel hardware provider is in the kernel.
1259  */
1260 int
1261 check_active_for_hard(char *provname, boolean_t *is_active)
1262 {
1263         crypto_get_dev_list_t   *pdevlist = NULL;
1264         char    devname[MAXNAMELEN];
1265         int     inst_num;
1266         int     i;
1267 
1268         if (provname == NULL) {
1269                 cryptoerror(LOG_STDERR, gettext("internal error."));
1270                 return (FAILURE);
1271         }
1272 
1273         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1274                 return (FAILURE);
1275         }
1276 
1277         if (get_dev_list(&pdevlist) == FAILURE) {
1278                 cryptoerror(LOG_STDERR, gettext("internal error."));
1279                 return (FAILURE);
1280         }
1281 
1282         *is_active = B_FALSE;
1283         for (i = 0; i < pdevlist->dl_dev_count; i++) {
1284                 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1285                     (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1286                         *is_active = B_TRUE;
1287                         break;
1288                 }
1289         }
1290         free(pdevlist);
1291 
1292         return (SUCCESS);
1293 }