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