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 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "@(#)adm_uef.c  1.12    06/11/02 SMI"
  27 
  28 #include <cryptoutil.h>
  29 #include <fcntl.h>
  30 #include <libintl.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <strings.h>
  34 #include <unistd.h>
  35 #include <errno.h>
  36 #include <dlfcn.h>
  37 #include <link.h>
  38 #include <sys/types.h>
  39 #include <sys/stat.h>
  40 #include <security/cryptoki.h>
  41 #include "cryptoadm.h"
  42 
  43 #define HDR1 "                                     P\n"
  44 #define HDR2 "                         S     V  K  a     U  D\n"
  45 #define HDR3 "                         i     e  e  i     n  e\n"
  46 #define HDR4 "                      S  g  V  r  y  r  W  w  r\n"
  47 #define HDR5 "             E  D  D  i  n  e  i  G  G  r  r  i\n"
  48 #define HDR6 "          H  n  e  i  g  +  r  +  e  e  a  a  v  E\n"
  49 #define HDR7 "min  max  W  c  c  g  n  R  i  R  n  n  p  p  e  C\n"
  50 
  51 
  52 static int err; /* To store errno which may be overwritten by gettext() */
  53 static boolean_t is_in_policylist(midstr_t, umechlist_t *);
  54 static char *uent2str(uentry_t *);
  55 static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR);
  56 
  57 static void display_slot_flags(CK_FLAGS flags)
  58 {
  59         (void) printf(gettext("Slot Flags: "));
  60         if (flags & CKF_TOKEN_PRESENT)
  61                 (void) printf("CKF_TOKEN_PRESENT ");
  62         if (flags & CKF_REMOVABLE_DEVICE)
  63                 (void) printf("CKF_REMOVABLE_DEVICE ");
  64         if (flags & CKF_HW_SLOT)
  65                 (void) printf("CKF_HW_SLOT ");
  66         (void) printf("\n");
  67 }
  68 
  69 void
  70 display_token_flags(CK_FLAGS flags)
  71 {
  72         (void) printf(gettext("Flags: "));
  73         if (flags & CKF_RNG)
  74                 (void) printf("CKF_RNG ");
  75         if (flags & CKF_WRITE_PROTECTED)
  76                 (void) printf("CKF_WRITE_PROTECTED ");
  77         if (flags & CKF_LOGIN_REQUIRED)
  78                 (void) printf("CKF_LOGIN_REQUIRED ");
  79         if (flags & CKF_USER_PIN_INITIALIZED)
  80                 (void) printf("CKF_USER_PIN_INITIALIZED ");
  81         if (flags & CKF_RESTORE_KEY_NOT_NEEDED)
  82                 (void) printf("CKF_RESTORE_KEY_NOT_NEEDED ");
  83         if (flags & CKF_CLOCK_ON_TOKEN)
  84                 (void) printf("CKF_CLOCK_ON_TOKEN ");
  85         if (flags & CKF_PROTECTED_AUTHENTICATION_PATH)
  86                 (void) printf("CKF_PROTECTED_AUTHENTICATION_PATH ");
  87         if (flags & CKF_DUAL_CRYPTO_OPERATIONS)
  88                 (void) printf("CKF_DUAL_CRYPTO_OPERATIONS ");
  89         if (flags & CKF_TOKEN_INITIALIZED)
  90                 (void) printf("CKF_TOKEN_INITIALIZED ");
  91         if (flags & CKF_SECONDARY_AUTHENTICATION)
  92                 (void) printf("CKF_SECONDARY_AUTHENTICATION ");
  93         if (flags & CKF_USER_PIN_COUNT_LOW)
  94                 (void) printf("CKF_USER_PIN_COUNT_LOW ");
  95         if (flags & CKF_USER_PIN_FINAL_TRY)
  96                 (void) printf("CKF_USER_PIN_FINAL_TRY ");
  97         if (flags & CKF_USER_PIN_LOCKED)
  98                 (void) printf("CKF_USER_PIN_LOCKED ");
  99         if (flags & CKF_USER_PIN_TO_BE_CHANGED)
 100                 (void) printf("CKF_USER_PIN_TO_BE_CHANGED ");
 101         if (flags & CKF_SO_PIN_COUNT_LOW)
 102                 (void) printf("CKF_SO_PIN_COUNT_LOW ");
 103         if (flags & CKF_SO_PIN_FINAL_TRY)
 104                 (void) printf("CKF_SO_PIN_FINAL_TRY ");
 105         if (flags & CKF_SO_PIN_LOCKED)
 106                 (void) printf("CKF_SO_PIN_LOCKED ");
 107         if (flags & CKF_SO_PIN_TO_BE_CHANGED)
 108                 (void) printf("CKF_SO_PIN_TO_BE_CHANGED ");
 109         if (flags & CKF_SO_PIN_TO_BE_CHANGED)
 110                 (void) printf("CKF_SO_PIN_TO_BE_CHANGED ");
 111         (void) printf("\n");
 112 }
 113 
 114 void
 115 display_mech_info(CK_MECHANISM_INFO *mechInfo)
 116 {
 117         CK_FLAGS ec_flags = CKF_EC_F_P | CKF_EC_F_2M | CKF_EC_ECPARAMETERS |
 118                 CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS;
 119 
 120         (void) printf("%-4ld %-4ld ", mechInfo->ulMinKeySize,
 121                 mechInfo->ulMaxKeySize);
 122         (void) printf("%s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s  "
 123                 "%s  %s",
 124                 (mechInfo->flags & CKF_HW) ? "X" : ".",
 125                 (mechInfo->flags & CKF_ENCRYPT) ? "X" : ".",
 126                 (mechInfo->flags & CKF_DECRYPT) ? "X" : ".",
 127                 (mechInfo->flags & CKF_DIGEST) ? "X" : ".",
 128                 (mechInfo->flags & CKF_SIGN) ? "X" : ".",
 129                 (mechInfo->flags & CKF_SIGN_RECOVER) ? "X" : ".",
 130                 (mechInfo->flags & CKF_VERIFY) ? "X" : ".",
 131                 (mechInfo->flags & CKF_VERIFY_RECOVER) ? "X" : ".",
 132                 (mechInfo->flags & CKF_GENERATE) ? "X" : ".",
 133                 (mechInfo->flags & CKF_GENERATE_KEY_PAIR) ? "X" : ".",
 134                 (mechInfo->flags & CKF_WRAP) ? "X" : ".",
 135                 (mechInfo->flags & CKF_UNWRAP) ? "X" : ".",
 136                 (mechInfo->flags & CKF_DERIVE) ? "X" : ".",
 137                 (mechInfo->flags & ec_flags) ? "X" : ".");
 138 }
 139 
 140 /*
 141  * Converts the provided list of mechanism names in their string format to
 142  * their corrsponding PKCS#11 mechanism IDs.
 143  *
 144  * The list of mechanism names to be converted is provided in the
 145  * "mlist" argument.  The list of converted mechanism IDs is returned
 146  * in the "pmech_list" argument.
 147  *
 148  * This function is called by list_metaslot_info() and
 149  * list_mechlist_for_lib() functions.
 150  */
 151 int
 152 convert_mechlist(CK_MECHANISM_TYPE **pmech_list, CK_ULONG *mech_count,
 153     mechlist_t *mlist)
 154 {
 155         int i, n = 0;
 156         mechlist_t *p = mlist;
 157 
 158         while (p != NULL) {
 159                 p = p->next;
 160                 n++;
 161         }
 162 
 163         *pmech_list = malloc(n * sizeof (CK_MECHANISM_TYPE));
 164         if (pmech_list == NULL) {
 165                 cryptodebug("out of memory");
 166                 return (FAILURE);
 167         }
 168         p = mlist;
 169         for (i = 0; i < n; i++) {
 170                 if (pkcs11_str2mech(p->name, &(*pmech_list[i])) != CKR_OK) {
 171                         free(*pmech_list);
 172                         return (FAILURE);
 173                 }
 174                 p = p->next;
 175         }
 176         *mech_count = n;
 177         return (SUCCESS);
 178 }
 179 
 180 /*
 181  * Display the mechanism list for a user-level library
 182  */
 183 int
 184 list_mechlist_for_lib(char *libname, mechlist_t *mlist,
 185                 flag_val_t *rng_flag, boolean_t no_warn,
 186                 boolean_t verbose, boolean_t show_mechs)
 187 {
 188         CK_RV   rv = CKR_OK;
 189         CK_RV   (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
 190         CK_FUNCTION_LIST_PTR    prov_funcs; /* Provider's function list */
 191         CK_SLOT_ID_PTR          prov_slots = NULL; /* Provider's slot list */
 192         CK_MECHANISM_TYPE_PTR   pmech_list; /* mechanism list for a slot */
 193         CK_SLOT_INFO    slotinfo;
 194         CK_ULONG        slot_count;
 195         CK_ULONG        mech_count;
 196         uentry_t        *puent = NULL;
 197         boolean_t lib_initialized = B_FALSE;
 198         void    *dldesc = NULL;
 199         char    *dl_error;
 200         char    *mech_name;
 201         char    *isa;
 202         char    libpath[MAXPATHLEN];
 203         char    buf[MAXPATHLEN];
 204         int     i, j;
 205         int     rc = SUCCESS;
 206 
 207         if (libname == NULL) {
 208                 /* should not happen */
 209                 cryptoerror(LOG_STDERR, gettext("internal error."));
 210                 cryptodebug("list_mechlist_for_lib() - libname is NULL.");
 211                 return (FAILURE);
 212         }
 213 
 214         /* Check if the library is in the pkcs11.conf file */
 215         if ((puent = getent_uef(libname)) == NULL) {
 216                 cryptoerror(LOG_STDERR,
 217                     gettext("%s does not exist."), libname);
 218                 return (FAILURE);
 219         }
 220         free_uentry(puent);
 221 
 222         /* Remove $ISA from the library name */
 223         if (strlcpy(buf, libname, sizeof (buf)) >= sizeof (buf)) {
 224                 (void) printf(gettext("%s: the provider name is too long."),
 225                     libname);
 226                 return (FAILURE);
 227         }
 228 
 229         if ((isa = strstr(buf, PKCS11_ISA)) != NULL) {
 230                 *isa = '\000';
 231                 isa += strlen(PKCS11_ISA);
 232                 (void) snprintf(libpath, MAXPATHLEN, "%s%s%s", buf, "/", isa);
 233         } else {
 234                 (void) strlcpy(libpath, libname, sizeof (libpath));
 235         }
 236 
 237         /* Open the provider */
 238         dldesc = dlopen(libpath, RTLD_NOW);
 239         if (dldesc == NULL) {
 240                 dl_error = dlerror();
 241                 cryptodebug("Cannot load PKCS#11 library %s.  dlerror: %s",
 242                     libname, dl_error != NULL ? dl_error : "Unknown");
 243                 rc = FAILURE;
 244                 goto clean_exit;
 245         }
 246 
 247         /* Get the pointer to provider's C_GetFunctionList() */
 248         Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
 249         if (Tmp_C_GetFunctionList == NULL) {
 250                 cryptodebug("Cannot get the address of the C_GetFunctionList "
 251                     "from %s", libname);
 252                 rc = FAILURE;
 253                 goto clean_exit;
 254         }
 255 
 256         /* Get the provider's function list */
 257         rv = Tmp_C_GetFunctionList(&prov_funcs);
 258         if (rv != CKR_OK) {
 259                 cryptodebug("failed to call C_GetFunctionList from %s",
 260                     libname);
 261                 rc = FAILURE;
 262                 goto clean_exit;
 263         }
 264 
 265         /* Initialize this provider */
 266         rv = prov_funcs->C_Initialize(NULL_PTR);
 267         if (rv != CKR_OK) {
 268                 cryptodebug("failed to call C_Initialize from %s, "
 269                     "return code = %d", libname, rv);
 270                 rc = FAILURE;
 271                 goto clean_exit;
 272         } else {
 273                 lib_initialized = B_TRUE;
 274         }
 275 
 276         /*
 277          * Find out how many slots this provider has, call with tokenPresent
 278          * set to FALSE so all potential slots are returned.
 279          */
 280         rv = prov_funcs->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
 281         if (rv != CKR_OK) {
 282                 cryptodebug("failed to get the slotlist from %s.", libname);
 283                 rc = FAILURE;
 284                 goto clean_exit;
 285         } else if (slot_count == 0) {
 286                 if (!no_warn)
 287                         (void) printf(gettext("%s: no slots presented.\n"),
 288                                 libname);
 289                 rc = SUCCESS;
 290                 goto clean_exit;
 291         }
 292 
 293         /* Allocate memory for the slot list */
 294         prov_slots = malloc(slot_count * sizeof (CK_SLOT_ID));
 295         if (prov_slots == NULL) {
 296                 cryptodebug("out of memory.");
 297                 rc = FAILURE;
 298                 goto clean_exit;
 299         }
 300 
 301         /* Get the slot list from provider */
 302         rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &slot_count);
 303         if (rv != CKR_OK) {
 304                 cryptodebug("failed to call C_GetSlotList() from %s.",
 305                     libname);
 306                 rc = FAILURE;
 307                 goto clean_exit;
 308         }
 309 
 310         if (verbose) {
 311                 (void) printf(gettext("Number of slots: %d\n"), slot_count);
 312         }
 313 
 314         /* Get the mechanism list for each slot */
 315         for (i = 0; i < slot_count; i++) {
 316                 if (verbose)
 317                         /*
 318                          * TRANSLATION_NOTE:
 319                          * In some languages, the # symbol should be
 320                          * converted to "no", an "n" followed by a
 321                          * superscript "o"..
 322                          */
 323                         (void) printf(gettext("\nSlot #%d\n"), i+1);
 324 
 325                 if ((rng_flag != NULL) && (*rng_flag == NO_RNG)) {
 326                         if (check_random(prov_slots[i], prov_funcs)) {
 327                                 *rng_flag = HAS_RNG;
 328                                 rc = SUCCESS;
 329                                 goto clean_exit;
 330                         } else
 331                                 continue;
 332                 }
 333 
 334                 rv = prov_funcs->C_GetSlotInfo(prov_slots[i], &slotinfo);
 335                 if (rv != CKR_OK) {
 336                         cryptodebug("failed to get slotinfo from %s", libname);
 337                         rc = FAILURE;
 338                         break;
 339                 }
 340                 if (verbose) {
 341                         CK_TOKEN_INFO tokeninfo;
 342 
 343                         (void) printf(gettext("Description: %.64s\n"
 344                                 "Manufacturer: %.32s\n"
 345                                 "PKCS#11 Version: %d.%d\n"),
 346                                 slotinfo.slotDescription,
 347                                 slotinfo.manufacturerID,
 348                                 prov_funcs->version.major,
 349                                 prov_funcs->version.minor);
 350 
 351                         (void) printf(gettext("Hardware Version: %d.%d\n"
 352                                 "Firmware Version: %d.%d\n"),
 353                                 slotinfo.hardwareVersion.major,
 354                                 slotinfo.hardwareVersion.minor,
 355                                 slotinfo.firmwareVersion.major,
 356                                 slotinfo.firmwareVersion.minor);
 357 
 358                         (void) printf(gettext("Token Present: %s\n"),
 359                                 (slotinfo.flags & CKF_TOKEN_PRESENT ?
 360                                 gettext("True") : gettext("False")));
 361 
 362                         display_slot_flags(slotinfo.flags);
 363 
 364                         rv = prov_funcs->C_GetTokenInfo(prov_slots[i],
 365                                 &tokeninfo);
 366                         if (rv != CKR_OK) {
 367                                 cryptodebug("Failed to get "
 368                                         "token info from %s", libname);
 369                                 rc = FAILURE;
 370                                 break;
 371                         }
 372 
 373                         (void) printf(gettext("Token Label: %.32s\n"
 374                                 "Manufacturer ID: %.32s\n"
 375                                 "Model: %.16s\n"
 376                                 "Serial Number: %.16s\n"
 377                                 "Hardware Version: %d.%d\n"
 378                                 "Firmware Version: %d.%d\n"
 379                                 "UTC Time: %.16s\n"
 380                                 "PIN Length: %d-%d\n"),
 381                                 tokeninfo.label,
 382                                 tokeninfo.manufacturerID,
 383                                 tokeninfo.model,
 384                                 tokeninfo.serialNumber,
 385                                 tokeninfo.hardwareVersion.major,
 386                                 tokeninfo.hardwareVersion.minor,
 387                                 tokeninfo.firmwareVersion.major,
 388                                 tokeninfo.firmwareVersion.minor,
 389                                 tokeninfo.utcTime,
 390                                 tokeninfo.ulMinPinLen,
 391                                 tokeninfo.ulMaxPinLen);
 392 
 393                         display_token_flags(tokeninfo.flags);
 394                 }
 395 
 396                 if (mlist == NULL) {
 397                         rv = prov_funcs->C_GetMechanismList(prov_slots[i],
 398                                 NULL_PTR, &mech_count);
 399                         if (rv != CKR_OK) {
 400                                 cryptodebug(
 401                                         "failed to call C_GetMechanismList() "
 402                                         "from %s.", libname);
 403                                 rc = FAILURE;
 404                                 break;
 405                         }
 406 
 407                         if (mech_count == 0) {
 408                                 /* no mechanisms in this slot */
 409                                 continue;
 410                         }
 411 
 412                         pmech_list = malloc(mech_count *
 413                                         sizeof (CK_MECHANISM_TYPE));
 414                         if (pmech_list == NULL) {
 415                                 cryptodebug("out of memory");
 416                                 rc = FAILURE;
 417                                 break;
 418                         }
 419 
 420                         /* Get the actual mechanism list */
 421                         rv = prov_funcs->C_GetMechanismList(prov_slots[i],
 422                                 pmech_list, &mech_count);
 423                         if (rv != CKR_OK) {
 424                                 cryptodebug(
 425                                         "failed to call C_GetMechanismList() "
 426                                         "from %s.", libname);
 427                                 (void) free(pmech_list);
 428                                 rc = FAILURE;
 429                                 break;
 430                         }
 431                 } else  {
 432                         /* use the mechanism list passed in */
 433                         rc = convert_mechlist(&pmech_list, &mech_count, mlist);
 434                         if (rc != SUCCESS) {
 435                                 goto clean_exit;
 436                         }
 437                 }
 438                 if (show_mechs)
 439                         (void) printf(gettext("Mechanisms:\n"));
 440 
 441                 if (verbose && show_mechs) {
 442                         display_verbose_mech_header();
 443                 }
 444                 /*
 445                  * Merge the current mechanism list into the returning
 446                  * mechanism list.
 447                  */
 448                 for (j = 0; show_mechs && j < mech_count; j++) {
 449                         mech_name = pkcs11_mech2str(pmech_list[j]);
 450                         (void) printf("%-29s", mech_name);
 451                         if (verbose) {
 452                                 CK_MECHANISM_INFO mech_info;
 453                                 rv = prov_funcs->C_GetMechanismInfo(
 454                                     prov_slots[i], pmech_list[j], &mech_info);
 455                                 if (rv != CKR_OK) {
 456                                         cryptodebug(
 457                                             "failed to call "
 458                                             "C_GetMechanismInfo() from %s.",
 459                                             libname);
 460                                         (void) free(pmech_list);
 461                                         rc = FAILURE;
 462                                         break;
 463                                 }
 464                                 display_mech_info(&mech_info);
 465                         }
 466                         (void) printf("\n");
 467                 }
 468                 (void) free(pmech_list);
 469                 if (rc == FAILURE) {
 470                         break;
 471                 }
 472         }
 473 
 474         if (rng_flag != NULL || rc == FAILURE) {
 475                 goto clean_exit;
 476         }
 477 
 478 clean_exit:
 479 
 480         if (rc == FAILURE) {
 481                 (void) printf(gettext(
 482                     "%s: failed to retrieve the mechanism list.\n"), libname);
 483         }
 484 
 485         if (lib_initialized) {
 486                 (void) prov_funcs->C_Finalize(NULL_PTR);
 487         }
 488 
 489         if (dldesc != NULL) {
 490                 (void) dlclose(dldesc);
 491         }
 492 
 493         if (prov_slots != NULL) {
 494                 (void) free(prov_slots);
 495         }
 496 
 497         return (rc);
 498 }
 499 
 500 
 501 /*
 502  * Display the mechanism policy for a user-level library
 503  */
 504 int
 505 list_policy_for_lib(char *libname)
 506 {
 507         uentry_t *puent = NULL;
 508         int rc;
 509 
 510         if (libname == NULL) {
 511                 /* should not happen */
 512                 cryptoerror(LOG_STDERR, gettext("internal error."));
 513                 cryptodebug("list_policy_for_lib() - libname is NULL.");
 514                 return (FAILURE);
 515         }
 516 
 517         /* Get the library entry from the pkcs11.conf file */
 518         if ((puent = getent_uef(libname)) == NULL) {
 519                 cryptoerror(LOG_STDERR,
 520                     gettext("%s does not exist."), libname);
 521                 return (FAILURE);
 522         }
 523 
 524         /* Print the policy for this library */
 525         rc = print_uef_policy(puent);
 526         free_uentry(puent);
 527 
 528         return (rc);
 529 }
 530 
 531 
 532 /*
 533  * Disable mechanisms for a user-level library
 534  */
 535 int
 536 disable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
 537     mechlist_t *marglist)
 538 {
 539         uentry_t        *puent;
 540         int     rc;
 541 
 542         if (libname == NULL) {
 543                 /* should not happen */
 544                 cryptoerror(LOG_STDERR, gettext("internal error."));
 545                 cryptodebug("disable_uef_lib() - libname is NULL.");
 546                 return (FAILURE);
 547         }
 548 
 549         /* Get the provider entry from the pkcs11.conf file */
 550         if ((puent = getent_uef(libname)) == NULL) {
 551                 cryptoerror(LOG_STDERR,
 552                     gettext("%s does not exist."), libname);
 553                 return (FAILURE);
 554         }
 555 
 556         /*
 557          * Update the mechanism policy of this library entry, based on
 558          * the current policy mode of the library and the mechanisms specified
 559          * in CLI.
 560          */
 561         if (allflag) {
 562                 /*
 563                  * If disabling all, just need to clean up the policylist and
 564                  * set the flag_enabledlist flag to be B_TRUE.
 565                  */
 566                 free_umechlist(puent->policylist);
 567                 puent->policylist = NULL;
 568                 puent->count = 0;
 569                 puent->flag_enabledlist = B_TRUE;
 570                 rc = SUCCESS;
 571         } else if (marglist != NULL) {
 572                 if (puent->flag_enabledlist == B_TRUE) {
 573                         /*
 574                          * The current default policy mode of this library
 575                          * is "all are disabled, except ...", so if a
 576                          * specified mechanism is in the exception list
 577                          * (the policylist), delete it from the policylist.
 578                          */
 579                         rc = update_policylist(puent, marglist, DELETE_MODE);
 580                 } else {
 581                         /*
 582                          * The current default policy mode of this library
 583                          * is "all are enabled", so if a specified mechanism
 584                          * is not in the exception list (policylist), add
 585                          * it into the policylist.
 586                          */
 587                         rc = update_policylist(puent, marglist, ADD_MODE);
 588                 }
 589         } else if (!rndflag) {
 590                 /* should not happen */
 591                 cryptoerror(LOG_STDERR, gettext("internal error."));
 592                 cryptodebug("disable_uef_lib() - wrong arguments.");
 593                 return (FAILURE);
 594         }
 595 
 596         if (rndflag)
 597                 puent->flag_norandom = B_TRUE;
 598 
 599         if (rc == FAILURE) {
 600                 free_uentry(puent);
 601                 return (FAILURE);
 602         }
 603 
 604         /* Update the pkcs11.conf file with the updated entry */
 605         rc = update_pkcs11conf(puent);
 606         free_uentry(puent);
 607         return (rc);
 608 }
 609 
 610 
 611 /*
 612  * Enable disabled mechanisms for a user-level library.
 613  */
 614 int
 615 enable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
 616     mechlist_t *marglist)
 617 {
 618         uentry_t        *puent;
 619         int     rc = SUCCESS;
 620 
 621         if (libname == NULL) {
 622                 /* should not happen */
 623                 cryptoerror(LOG_STDERR, gettext("internal error."));
 624                 cryptodebug("enable_uef_lib() - libname is NULL.");
 625                 return (FAILURE);
 626         }
 627 
 628         /* Get the provider entry from the pkcs11.conf file */
 629         if ((puent = getent_uef(libname)) == NULL) {
 630                 cryptoerror(LOG_STDERR,
 631                     gettext("%s does not exist."), libname);
 632                 return (FAILURE);
 633         }
 634 
 635         /*
 636          * Update the mechanism policy of this library entry, based on
 637          * the current policy mode of the library and the mechanisms
 638          * specified in CLI.
 639          */
 640         if (allflag) {
 641                 /*
 642                  * If enabling all, what needs to be done are cleaning up the
 643                  * policylist and setting the "flag_enabledlist" flag to
 644                  * B_FALSE.
 645                  */
 646                 free_umechlist(puent->policylist);
 647                 puent->policylist = NULL;
 648                 puent->count = 0;
 649                 puent->flag_enabledlist = B_FALSE;
 650                 rc = SUCCESS;
 651         } else if (marglist != NULL) {
 652                 if (puent->flag_enabledlist == B_TRUE) {
 653                         /*
 654                          * The current default policy mode of this library
 655                          * is "all are disabled, except ...", so if a
 656                          * specified mechanism is not in the exception list
 657                          * (policylist), add it.
 658                          */
 659                         rc = update_policylist(puent, marglist, ADD_MODE);
 660                 } else {
 661                         /*
 662                          * The current default policy mode of this library
 663                          * is "all are enabled, except", so if a specified
 664                          * mechanism is in the exception list (policylist),
 665                          * delete it.
 666                          */
 667                         rc = update_policylist(puent, marglist, DELETE_MODE);
 668                 }
 669         } else if (!rndflag) {
 670                 /* should not come here */
 671                 cryptoerror(LOG_STDERR, gettext("internal error."));
 672                 cryptodebug("enable_uef_lib() - wrong arguments.");
 673                 return (FAILURE);
 674         }
 675 
 676         if (rndflag)
 677                 puent->flag_norandom = B_FALSE;
 678 
 679         if (rc == FAILURE) {
 680                 free_uentry(puent);
 681                 return (FAILURE);
 682         }
 683 
 684         /* Update the pkcs11.conf file with the updated entry */
 685         rc = update_pkcs11conf(puent);
 686         free_uentry(puent);
 687         return (rc);
 688 }
 689 
 690 
 691 /*
 692  * Install a user-level library.
 693  */
 694 int
 695 install_uef_lib(char *libname)
 696 {
 697         uentry_t        *puent;
 698         struct stat     statbuf;
 699         boolean_t       found;
 700         FILE    *pfile;
 701         FILE    *pfile_tmp;
 702         char    tmpfile_name[MAXPATHLEN];
 703         char    libpath[MAXPATHLEN];
 704         char    libbuf[MAXPATHLEN];
 705         char    *isa;
 706         char    buffer[BUFSIZ];
 707         char    *ptr;
 708         int     found_count;
 709         int     rc = SUCCESS;
 710 
 711 
 712         if (libname == NULL) {
 713                 /* should not happen */
 714                 cryptoerror(LOG_STDERR, gettext("internal error."));
 715                 cryptodebug("install_uef_lib() - libname is NULL.");
 716                 return (FAILURE);
 717         }
 718 
 719         /* Check if the provider already exists in the framework */
 720         if ((puent = getent_uef(libname)) != NULL) {
 721                 cryptoerror(LOG_STDERR, gettext("%s exists already."),
 722                     libname);
 723                 free_uentry(puent);
 724                 return (FAILURE);
 725         }
 726 
 727         /*
 728          * Check if the library exists in the system. if $ISA is in the
 729          * path, only check the 32bit version.
 730          */
 731         if (strlcpy(libbuf, libname, MAXPATHLEN) >= MAXPATHLEN) {
 732                 cryptoerror(LOG_STDERR,
 733                     gettext("the provider name is too long - %s"), libname);
 734                 return (FAILURE);
 735         }
 736 
 737         if ((isa = strstr(libbuf, PKCS11_ISA)) != NULL) {
 738                 *isa = '\000';
 739                 isa += strlen(PKCS11_ISA);
 740                 (void) snprintf(libpath, sizeof (libpath), "%s%s%s", libbuf,
 741                     "/", isa);
 742         } else {
 743                 (void) strlcpy(libpath, libname, sizeof (libpath));
 744         }
 745 
 746         /* Check if it is same as the framework library */
 747         if (strcmp(libpath, UEF_FRAME_LIB) == 0) {
 748                 cryptoerror(LOG_STDERR, gettext(
 749                     "The framework library %s can not be installed."),
 750                     libname);
 751                 return (FAILURE);
 752         }
 753 
 754         if (stat(libpath, &statbuf) != 0) {
 755                 cryptoerror(LOG_STDERR, gettext("%s not found"), libname);
 756                 return (FAILURE);
 757         }
 758 
 759         /* Need to add "\n" to libname for adding into the config file */
 760         if (strlcat(libname, "\n", MAXPATHLEN) >= MAXPATHLEN) {
 761                 cryptoerror(LOG_STDERR, gettext(
 762                     "can not install %s; the name is too long."), libname);
 763                 return (FAILURE);
 764         }
 765 
 766         if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
 767                 err = errno;
 768                 cryptoerror(LOG_STDERR,
 769                     gettext("failed to update the configuration - %s"),
 770                     strerror(err));
 771                 cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
 772                 return (FAILURE);
 773         }
 774 
 775         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 776                 err = errno;
 777                 cryptoerror(LOG_STDERR,
 778                     gettext("failed to lock the configuration - %s"),
 779                     strerror(err));
 780                 (void) fclose(pfile);
 781                 return (FAILURE);
 782         }
 783 
 784         /*
 785          * Create a temporary file in the /etc/crypto directory.
 786          */
 787         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
 788         if (mkstemp(tmpfile_name) == -1) {
 789                 err = errno;
 790                 cryptoerror(LOG_STDERR,
 791                     gettext("failed to create a temporary file - %s"),
 792                     strerror(err));
 793                 (void) fclose(pfile);
 794                 return (FAILURE);
 795         }
 796 
 797         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 798                 err = errno;
 799                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 800                     tmpfile_name, strerror(err));
 801                 (void) fclose(pfile);
 802                 return (FAILURE);
 803         }
 804 
 805         /*
 806          * Loop thru the config file. If the file was reserved within a
 807          * package bracket, just uncomment it.  Other wise, append it at
 808          * the end.  The resulting file will be saved in the temp file first.
 809          */
 810         found_count = 0;
 811         rc = SUCCESS;
 812         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 813                 found = B_FALSE;
 814                 if (buffer[0] == '#') {
 815                         ptr = buffer;
 816                         ptr++;
 817                         if (strcmp(libname, ptr) == 0) {
 818                                 found = B_TRUE;
 819                                 found_count++;
 820                         }
 821                 }
 822 
 823                 if (found == B_FALSE) {
 824                         if (fputs(buffer, pfile_tmp) == EOF) {
 825                                 rc = FAILURE;
 826                         }
 827                 } else {
 828                         if (found_count == 1) {
 829                                 if (fputs(ptr, pfile_tmp) == EOF) {
 830                                         rc = FAILURE;
 831                                 }
 832                         } else {
 833                                 /*
 834                                  * Found a second entry with #libname.
 835                                  * Should not happen. The pkcs11.conf file
 836                                  * is corrupted. Give a warning and skip
 837                                  * this entry.
 838                                  */
 839                                 cryptoerror(LOG_STDERR, gettext(
 840                                     "(Warning) Found an additional reserved "
 841                                     "entry for %s."), libname);
 842                         }
 843                 }
 844 
 845                 if (rc == FAILURE) {
 846                         break;
 847                 }
 848         }
 849 
 850         if (rc == FAILURE) {
 851                 cryptoerror(LOG_STDERR, gettext("write error."));
 852                 (void) fclose(pfile);
 853                 (void) fclose(pfile_tmp);
 854                 if (unlink(tmpfile_name) != 0) {
 855                         err = errno;
 856                         cryptoerror(LOG_STDERR, gettext(
 857                             "(Warning) failed to remove %s: %s"), tmpfile_name,
 858                             strerror(err));
 859                 }
 860                 return (FAILURE);
 861         }
 862 
 863         if (found_count == 0) {
 864                 /*
 865                  * This libname was not in package before, append it to the
 866                  * end of the temp file.
 867                  */
 868                 if (fputs(libname, pfile_tmp) == EOF) {
 869                         err = errno;
 870                         cryptoerror(LOG_STDERR, gettext(
 871                             "failed to write to %s: %s"), tmpfile_name,
 872                             strerror(err));
 873                         (void) fclose(pfile);
 874                         (void) fclose(pfile_tmp);
 875                         if (unlink(tmpfile_name) != 0) {
 876                                 err = errno;
 877                                 cryptoerror(LOG_STDERR, gettext(
 878                                     "(Warning) failed to remove %s: %s"),
 879                                     tmpfile_name, strerror(err));
 880                         }
 881                         return (FAILURE);
 882                 }
 883         }
 884 
 885         (void) fclose(pfile);
 886         if (fclose(pfile_tmp) != 0) {
 887                 err = errno;
 888                 cryptoerror(LOG_STDERR,
 889                     gettext("failed to close %s: %s"), tmpfile_name,
 890                     strerror(err));
 891                 return (FAILURE);
 892         }
 893 
 894         if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
 895                 err = errno;
 896                 cryptoerror(LOG_STDERR,
 897                     gettext("failed to update the configuration - %s"),
 898                     strerror(err));
 899                 cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
 900                     _PATH_PKCS11_CONF, strerror(err));
 901                 rc = FAILURE;
 902         } else if (chmod(_PATH_PKCS11_CONF,
 903             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
 904                 err = errno;
 905                 cryptoerror(LOG_STDERR,
 906                     gettext("failed to update the configuration - %s"),
 907                     strerror(err));
 908                 cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
 909                     strerror(err));
 910                 rc = FAILURE;
 911         } else {
 912                 rc = SUCCESS;
 913         }
 914 
 915         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
 916                 err = errno;
 917                 cryptoerror(LOG_STDERR, gettext(
 918                     "(Warning) failed to remove %s: %s"), tmpfile_name,
 919                     strerror(err));
 920         }
 921 
 922         return (rc);
 923 }
 924 
 925 
 926 /*
 927  * Uninstall a user-level library.
 928  */
 929 int
 930 uninstall_uef_lib(char *libname)
 931 {
 932         uentry_t        *puent;
 933         FILE    *pfile;
 934         FILE    *pfile_tmp;
 935         char    buffer[BUFSIZ];
 936         char    buffer2[BUFSIZ];
 937         char    tmpfile_name[MAXPATHLEN];
 938         char    *name;
 939         boolean_t       found;
 940         boolean_t       in_package;
 941         int     len;
 942         int     rc = SUCCESS;
 943 
 944         if (libname == NULL) {
 945                 /* should not happen */
 946                 cryptoerror(LOG_STDERR, gettext("internal error."));
 947                 cryptodebug("uninstall_uef_lib() - libname is NULL.");
 948                 return (FAILURE);
 949         }
 950 
 951         /* Check if the provider exists */
 952         if ((puent = getent_uef(libname)) == NULL) {
 953                 cryptoerror(LOG_STDERR,
 954                     gettext("%s does not exist."), libname);
 955                 return (FAILURE);
 956         }
 957         free_uentry(puent);
 958 
 959         /*  Open the pkcs11.conf file and lock it */
 960         if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
 961                 err = errno;
 962                 cryptoerror(LOG_STDERR,
 963                     gettext("failed to update the configuration - %s"),
 964                     strerror(err));
 965                 cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
 966                 return (FAILURE);
 967         }
 968 
 969         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
 970                 err = errno;
 971                 cryptoerror(LOG_STDERR,
 972                     gettext("failed to lock the configuration - %s"),
 973                     strerror(err));
 974                 (void) fclose(pfile);
 975                 return (FAILURE);
 976         }
 977 
 978         /*
 979          * Create a temporary file in the /etc/crypto directory to save
 980          * the new configuration file first.
 981          */
 982         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
 983         if (mkstemp(tmpfile_name) == -1) {
 984                 err = errno;
 985                 cryptoerror(LOG_STDERR,
 986                     gettext("failed to create a temporary file - %s"),
 987                     strerror(err));
 988                 (void) fclose(pfile);
 989                 return (FAILURE);
 990         }
 991 
 992         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
 993                 err = errno;
 994                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
 995                     tmpfile_name, strerror(err));
 996                 if (unlink(tmpfile_name) != 0) {
 997                         err = errno;
 998                         cryptoerror(LOG_STDERR, gettext(
 999                             "(Warning) failed to remove %s: %s"),
1000                             tmpfile_name, strerror(err));
1001                 }
1002                 (void) fclose(pfile);
1003                 return (FAILURE);
1004         }
1005 
1006 
1007         /*
1008          * Loop thru the config file.  If the library to be uninstalled
1009          * is in a package, just comment it off.
1010          */
1011         in_package = B_FALSE;
1012         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1013                 found = B_FALSE;
1014                 if (!(buffer[0] == ' ' || buffer[0] == '\n' ||
1015                     buffer[0] == '\t')) {
1016                         if (strstr(buffer, " Start ") != NULL) {
1017                                 in_package = B_TRUE;
1018                         } else if (strstr(buffer, " End ") != NULL) {
1019                                 in_package = B_FALSE;
1020                         } else if (buffer[0] != '#') {
1021                                 (void) strlcpy(buffer2, buffer, BUFSIZ);
1022 
1023                                 /* get rid of trailing '\n' */
1024                                 len = strlen(buffer2);
1025                                 if (buffer2[len-1] == '\n') {
1026                                         len--;
1027                                 }
1028                                 buffer2[len] = '\0';
1029 
1030                                 if ((name = strtok(buffer2, SEP_COLON))
1031                                     == NULL) {
1032                                         rc = FAILURE;
1033                                         break;
1034                                 } else if (strcmp(libname, name) == 0) {
1035                                         found = B_TRUE;
1036                                 }
1037                         }
1038                 }
1039 
1040                 if (found) {
1041                         if (in_package) {
1042                                 (void) snprintf(buffer2, sizeof (buffer2),
1043                                     "%s%s%s", "#", libname, "\n");
1044                                 if (fputs(buffer2, pfile_tmp) == EOF) {
1045                                         rc = FAILURE;
1046                                 }
1047                         }
1048                 } else {
1049                         if (fputs(buffer, pfile_tmp) == EOF) {
1050                                 rc = FAILURE;
1051                         }
1052                 }
1053 
1054                 if (rc == FAILURE) {
1055                         break;
1056                 }
1057         }
1058 
1059         if (rc == FAILURE) {
1060                 cryptoerror(LOG_STDERR, gettext("write error."));
1061                 (void) fclose(pfile);
1062                 (void) fclose(pfile_tmp);
1063                 if (unlink(tmpfile_name) != 0) {
1064                         err = errno;
1065                         cryptoerror(LOG_STDERR, gettext(
1066                             "(Warning) failed to remove %s: %s"),
1067                             tmpfile_name, strerror(err));
1068                 }
1069                 return (FAILURE);
1070         }
1071 
1072         (void) fclose(pfile);
1073         if (fclose(pfile_tmp) != 0) {
1074                 err = errno;
1075                 cryptoerror(LOG_STDERR,
1076                     gettext("failed to close a temporary file - %s"),
1077                     strerror(err));
1078                 return (FAILURE);
1079         }
1080 
1081         /* Now update the real config file */
1082         if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1083                 err = errno;
1084                 cryptoerror(LOG_STDERR,
1085                     gettext("failed to update the configuration - %s"),
1086                     strerror(err));
1087                 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1088                     _PATH_PKCS11_CONF, strerror(err));
1089                 rc = FAILURE;
1090         } else if (chmod(_PATH_PKCS11_CONF,
1091             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1092                 err = errno;
1093                 cryptoerror(LOG_STDERR,
1094                     gettext("failed to update the configuration - %s"),
1095                     strerror(err));
1096                 cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1097                     strerror(err));
1098                 rc = FAILURE;
1099         } else {
1100                 rc = SUCCESS;
1101         }
1102 
1103         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1104                 err = errno;
1105                 cryptoerror(LOG_STDERR, gettext(
1106                     "(Warning) failed to remove %s: %s"),
1107                     tmpfile_name, strerror(err));
1108         }
1109 
1110         return (rc);
1111 }
1112 
1113 
1114 int
1115 display_policy(uentry_t *puent)
1116 {
1117         CK_MECHANISM_TYPE  mech_id;
1118         char *mech_name;
1119         umechlist_t *ptr;
1120 
1121         if (puent == NULL) {
1122                 return (SUCCESS);
1123         }
1124 
1125         if (puent->flag_enabledlist == B_FALSE) {
1126                 (void) printf(gettext("%s: all mechanisms are enabled"),
1127                     puent->name);
1128                 ptr = puent->policylist;
1129                 if (ptr == NULL) {
1130                         (void) printf(".");
1131                 } else {
1132                         (void) printf(gettext(", except "));
1133                         while (ptr != NULL) {
1134                                 mech_id = strtoul(ptr->name, NULL, 0);
1135                                 if (mech_id & CKO_VENDOR_DEFINED) {
1136                                         /* vendor defined mechanism */
1137                                         (void) printf("%s", ptr->name);
1138                                 } else {
1139                                         mech_name = pkcs11_mech2str(mech_id);
1140                                         if (mech_name == NULL) {
1141                                                 return (FAILURE);
1142                                         }
1143                                         (void) printf("%s", mech_name);
1144                                         free(mech_name);
1145                                 }
1146 
1147                                 ptr = ptr->next;
1148                                 if (ptr == NULL) {
1149                                         (void) printf(".");
1150                                 } else {
1151                                         (void) printf(",");
1152                                 }
1153                         }
1154                 }
1155         } else { /* puent->flag_enabledlist == B_TRUE */
1156                 (void) printf(gettext("%s: all mechanisms are disabled"),
1157                     puent->name);
1158                 ptr = puent->policylist;
1159                 if (ptr == NULL) {
1160                         (void) printf(".");
1161                 } else {
1162                         (void) printf(gettext(", except "));
1163                         while (ptr != NULL) {
1164                                 mech_id = strtoul(ptr->name, NULL, 0);
1165                                 if (mech_id & CKO_VENDOR_DEFINED) {
1166                                         /* vendor defined mechanism */
1167                                         (void) printf("%s", ptr->name);
1168                                 } else {
1169                                         mech_name = pkcs11_mech2str(mech_id);
1170                                         if (mech_name == NULL) {
1171                                                 return (FAILURE);
1172                                         }
1173                                         (void) printf("%s", mech_name);
1174                                         free(mech_name);
1175                                 }
1176                                 ptr = ptr->next;
1177                                 if (ptr == NULL) {
1178                                         (void) printf(".");
1179                                 } else {
1180                                         (void) printf(",");
1181                                 }
1182                         }
1183                 }
1184         }
1185         return (SUCCESS);
1186 }
1187 
1188 
1189 
1190 /*
1191  * Print out the mechanism policy for a user-level provider pointed by puent.
1192  */
1193 int
1194 print_uef_policy(uentry_t *puent)
1195 {
1196         flag_val_t rng_flag;
1197 
1198         if (puent == NULL) {
1199                 return (FAILURE);
1200         }
1201 
1202         rng_flag = NO_RNG;
1203         if (list_mechlist_for_lib(puent->name, NULL, &rng_flag, B_TRUE,
1204                 B_FALSE, B_FALSE) != SUCCESS) {
1205                 cryptoerror(LOG_STDERR,
1206                     gettext("%s internal error."), puent->name);
1207                 return (FAILURE);
1208         }
1209 
1210         if (display_policy(puent) != SUCCESS) {
1211                 goto failed_exit;
1212         }
1213 
1214 
1215         if (puent->flag_norandom == B_TRUE)
1216                 /*
1217                  * TRANSLATION_NOTE:
1218                  * "random" is a keyword and not to be translated.
1219                  */
1220                 (void) printf(gettext(" %s is disabled."), "random");
1221         else {
1222                 if (rng_flag == HAS_RNG)
1223                         /*
1224                          * TRANSLATION_NOTE:
1225                          * "random" is a keyword and not to be translated.
1226                          */
1227                         (void) printf(gettext(" %s is enabled."), "random");
1228         }
1229         (void) printf("\n");
1230 
1231         return (SUCCESS);
1232 
1233 failed_exit:
1234 
1235         (void) printf(gettext("\nout of memory.\n"));
1236         return (FAILURE);
1237 }
1238 
1239 
1240 /*
1241  * Check if the mechanism is in the mechanism list.
1242  */
1243 static boolean_t
1244 is_in_policylist(midstr_t mechname, umechlist_t *plist)
1245 {
1246         boolean_t found = B_FALSE;
1247 
1248         if (mechname == NULL) {
1249                 return (B_FALSE);
1250         }
1251 
1252         while (plist != NULL) {
1253                 if (strcmp(plist->name, mechname) == 0) {
1254                         found = B_TRUE;
1255                         break;
1256                 }
1257                 plist = plist->next;
1258         }
1259 
1260         return (found);
1261 }
1262 
1263 
1264 /*
1265  * Update the pkcs11.conf file with the updated entry.
1266  */
1267 int
1268 update_pkcs11conf(uentry_t *puent)
1269 {
1270         FILE    *pfile;
1271         FILE    *pfile_tmp;
1272         char buffer[BUFSIZ];
1273         char buffer2[BUFSIZ];
1274         char tmpfile_name[MAXPATHLEN];
1275         char *name;
1276         char *str;
1277         int len;
1278         int rc = SUCCESS;
1279         boolean_t found;
1280 
1281         if (puent == NULL) {
1282                 cryptoerror(LOG_STDERR, gettext("internal error."));
1283                 return (FAILURE);
1284         }
1285 
1286         /* Open the pkcs11.conf file */
1287         if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
1288                 err = errno;
1289                 cryptoerror(LOG_STDERR,
1290                     gettext("failed to update the configuration - %s"),
1291                     strerror(err));
1292                 cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
1293                 return (FAILURE);
1294         }
1295 
1296         /* Lock the pkcs11.conf file */
1297         if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
1298                 err = errno;
1299                 cryptoerror(LOG_STDERR,
1300                     gettext("failed to update the configuration - %s"),
1301                         strerror(err));
1302                 (void) fclose(pfile);
1303                 return (FAILURE);
1304         }
1305 
1306         /*
1307          * Create a temporary file in the /etc/crypto directory to save
1308          * updated configuration file first.
1309          */
1310         (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
1311         if (mkstemp(tmpfile_name) == -1) {
1312                 err = errno;
1313                 cryptoerror(LOG_STDERR,
1314                     gettext("failed to create a temporary file - %s"),
1315                     strerror(err));
1316                 (void) fclose(pfile);
1317                 return (FAILURE);
1318         }
1319 
1320         if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
1321                 err = errno;
1322                 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
1323                     tmpfile_name, strerror(err));
1324                 if (unlink(tmpfile_name) != 0) {
1325                         err = errno;
1326                         cryptoerror(LOG_STDERR, gettext(
1327                             "(Warning) failed to remove %s: %s"),
1328                             tmpfile_name, strerror(err));
1329                 }
1330                 (void) fclose(pfile);
1331                 return (FAILURE);
1332         }
1333 
1334 
1335         /*
1336          * Loop thru entire pkcs11.conf file, update the entry to be
1337          * updated and save the updated file to the temporary file first.
1338          */
1339         while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1340                 found = B_FALSE;
1341                 if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1342                     buffer[0] == '\n'|| buffer[0] == '\t')) {
1343                         /*
1344                          * Get the provider name from this line and check if
1345                          * this is the entry to be updated. Note: can not use
1346                          * "buffer" directly because strtok will change its
1347                          * value.
1348                          */
1349                         (void) strlcpy(buffer2, buffer, BUFSIZ);
1350 
1351                         /* get rid of trailing '\n' */
1352                         len = strlen(buffer2);
1353                         if (buffer2[len-1] == '\n') {
1354                                 len--;
1355                         }
1356                         buffer2[len] = '\0';
1357 
1358                         if ((name = strtok(buffer2, SEP_COLON)) == NULL) {
1359                                 rc = FAILURE;
1360                                 break;
1361                         } else if (strcmp(puent->name, name) == 0) {
1362                                 found = B_TRUE;
1363                         }
1364                 }
1365 
1366                 if (found) {
1367                         /*
1368                          * This is the entry to be modified, get the updated
1369                          * string.
1370                          */
1371                         if ((str = uent2str(puent)) == NULL) {
1372                                 rc = FAILURE;
1373                                 break;
1374                         } else {
1375                                 (void) strlcpy(buffer, str, BUFSIZ);
1376                                 free(str);
1377                         }
1378                 }
1379 
1380                 if (fputs(buffer, pfile_tmp) == EOF) {
1381                         err = errno;
1382                         cryptoerror(LOG_STDERR, gettext(
1383                             "failed to write to a temp file: %s."),
1384                             strerror(err));
1385                         rc = FAILURE;
1386                         break;
1387                 }
1388         }
1389 
1390         if (rc == FAILURE) {
1391                 (void) fclose(pfile);
1392                 (void) fclose(pfile_tmp);
1393                 if (unlink(tmpfile_name) != 0) {
1394                         err = errno;
1395                         cryptoerror(LOG_STDERR, gettext(
1396                             "(Warning) failed to remove %s: %s"),
1397                             tmpfile_name, strerror(err));
1398                 }
1399                 return (FAILURE);
1400         }
1401 
1402         (void) fclose(pfile);
1403         if (fclose(pfile_tmp) != 0) {
1404                 err = errno;
1405                 cryptoerror(LOG_STDERR,
1406                     gettext("failed to close %s: %s"), tmpfile_name,
1407                     strerror(err));
1408                 return (FAILURE);
1409         }
1410 
1411         /* Copy the temporary file to the pkcs11.conf file */
1412         if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1413                 err = errno;
1414                 cryptoerror(LOG_STDERR,
1415                     gettext("failed to update the configuration - %s"),
1416                     strerror(err));
1417                 cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
1418                     _PATH_PKCS11_CONF, strerror(err));
1419                 rc = FAILURE;
1420         } else if (chmod(_PATH_PKCS11_CONF,
1421             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1422                 err = errno;
1423                 cryptoerror(LOG_STDERR,
1424                     gettext("failed to update the configuration - %s"),
1425                     strerror(err));
1426                 cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1427                     strerror(err));
1428                 rc = FAILURE;
1429         } else {
1430                 rc = SUCCESS;
1431         }
1432 
1433         if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1434                 err = errno;
1435                 cryptoerror(LOG_STDERR, gettext(
1436                     "(Warning) failed to remove %s: %s"),
1437                     tmpfile_name, strerror(err));
1438         }
1439 
1440         return (rc);
1441 }
1442 
1443 
1444 /*
1445  * Convert an uentry to a character string
1446  */
1447 static char *
1448 uent2str(uentry_t *puent)
1449 {
1450         umechlist_t     *phead;
1451         boolean_t tok1_present = B_FALSE;
1452         char *buf;
1453         char blank_buf[128];
1454 
1455         if (puent == NULL) {
1456                 cryptoerror(LOG_STDERR, gettext("internal error."));
1457                 return (NULL);
1458         }
1459 
1460         buf = malloc(BUFSIZ);
1461         if (buf == NULL) {
1462                 cryptoerror(LOG_STDERR, gettext("out of memory."));
1463                 return (NULL);
1464         }
1465 
1466         /* convert the library name */
1467         if (strlcpy(buf, puent->name, BUFSIZ) >= BUFSIZ) {
1468                 free(buf);
1469                 return (NULL);
1470         }
1471 
1472 
1473         /* convert the enabledlist or the disabledlist */
1474         if (puent->flag_enabledlist == B_TRUE) {
1475                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1476                         free(buf);
1477                         return (NULL);
1478                 }
1479 
1480                 if (strlcat(buf, EF_ENABLED, BUFSIZ) >= BUFSIZ) {
1481                         free(buf);
1482                         return (NULL);
1483                 }
1484 
1485                 phead = puent->policylist;
1486                 while (phead != NULL) {
1487                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1488                                 free(buf);
1489                                 return (NULL);
1490                         }
1491 
1492                         phead = phead->next;
1493                         if (phead != NULL) {
1494                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
1495                                     >= BUFSIZ) {
1496                                         free(buf);
1497                                         return (NULL);
1498                                 }
1499                         }
1500                 }
1501                 tok1_present = B_TRUE;
1502         } else if (puent->policylist != NULL) {
1503                 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1504                         free(buf);
1505                         return (NULL);
1506                 }
1507 
1508                 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
1509                         free(buf);
1510                         return (NULL);
1511                 }
1512                 phead = puent->policylist;
1513                 while (phead != NULL) {
1514                         if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1515                                 free(buf);
1516                                 return (NULL);
1517                         }
1518 
1519                         phead = phead->next;
1520                         if (phead != NULL) {
1521                                 if (strlcat(buf, SEP_COMMA, BUFSIZ)
1522                                     >= BUFSIZ) {
1523                                         free(buf);
1524                                         return (NULL);
1525                                 }
1526                         }
1527                 }
1528                 tok1_present = B_TRUE;
1529         }
1530 
1531         if (puent->flag_norandom == B_TRUE) {
1532                 if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1533                     BUFSIZ) >= BUFSIZ) {
1534                         free(buf);
1535                         return (NULL);
1536                 }
1537 
1538                 if (strlcat(buf, EF_NORANDOM, BUFSIZ) >= BUFSIZ) {
1539                         free(buf);
1540                         return (NULL);
1541                 }
1542         }
1543 
1544         if (strcmp(puent->name, METASLOT_KEYWORD) == 0) {
1545 
1546                 /* write the metaslot_status= value */
1547                 if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1548                     BUFSIZ) >= BUFSIZ) {
1549                         free(buf);
1550                         return (NULL);
1551                 }
1552 
1553                 if (strlcat(buf, METASLOT_STATUS, BUFSIZ) >= BUFSIZ) {
1554                         free(buf);
1555                         return (NULL);
1556                 }
1557 
1558                 if (puent->flag_metaslot_enabled) {
1559                         if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1560                                 free(buf);
1561                                 return (NULL);
1562                         }
1563                 } else {
1564                         if (strlcat(buf, METASLOT_DISABLED, BUFSIZ)
1565                             >= BUFSIZ) {
1566                                 free(buf);
1567                                 return (NULL);
1568                         }
1569                 }
1570 
1571                 if (!tok1_present) {
1572                         tok1_present = B_TRUE;
1573                 }
1574 
1575                 if (strlcat(buf, SEP_SEMICOLON, BUFSIZ) >= BUFSIZ) {
1576                         free(buf);
1577                         return (NULL);
1578                 }
1579 
1580                 if (strlcat(buf, METASLOT_AUTO_KEY_MIGRATE, BUFSIZ) >= BUFSIZ) {
1581                         free(buf);
1582                         return (NULL);
1583                 }
1584 
1585                 if (puent->flag_metaslot_auto_key_migrate) {
1586                         if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1587                                 free(buf);
1588                                 return (NULL);
1589                         }
1590                 } else {
1591                         if (strlcat(buf, METASLOT_DISABLED, BUFSIZ) >= BUFSIZ) {
1592                                 free(buf);
1593                                 return (NULL);
1594                         }
1595                 }
1596 
1597                 bzero(blank_buf, sizeof (blank_buf));
1598 
1599                 /* write metaslot_token= if specified */
1600                 if (memcmp(puent->metaslot_ks_token, blank_buf,
1601                     TOKEN_LABEL_SIZE) != 0) {
1602                         /* write the metaslot_status= value */
1603                         if (strlcat(buf, (tok1_present ?
1604                             SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1605                                 free(buf);
1606                                 return (NULL);
1607                         }
1608 
1609                         if (strlcat(buf, METASLOT_TOKEN, BUFSIZ) >= BUFSIZ) {
1610                                 free(buf);
1611                                 return (NULL);
1612                         }
1613 
1614                         if (strlcat(buf,
1615                             (const char *)puent->metaslot_ks_token, BUFSIZ)
1616                             >= BUFSIZ) {
1617                                 free(buf);
1618                                 return (NULL);
1619                         }
1620                 }
1621 
1622                 /* write metaslot_slot= if specified */
1623                 if (memcmp(puent->metaslot_ks_slot, blank_buf,
1624                     SLOT_DESCRIPTION_SIZE) != 0) {
1625                         /* write the metaslot_status= value */
1626                         if (strlcat(buf, (tok1_present ?
1627                             SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1628                                 free(buf);
1629                                 return (NULL);
1630                         }
1631 
1632                         if (strlcat(buf, METASLOT_SLOT, BUFSIZ) >= BUFSIZ) {
1633                                 free(buf);
1634                                 return (NULL);
1635                         }
1636 
1637                         if (strlcat(buf,
1638                             (const char *)puent->metaslot_ks_slot, BUFSIZ)
1639                             >= BUFSIZ) {
1640                                 free(buf);
1641                                 return (NULL);
1642                         }
1643                 }
1644         }
1645 
1646         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
1647                 free(buf);
1648                 return (NULL);
1649         }
1650 
1651         return (buf);
1652 }
1653 
1654 
1655 /*
1656  * This function updates the default policy mode and the policy exception list
1657  * for a user-level provider based on the mechanism specified in the disable
1658  * or enable subcommand and the update mode.   This function is called by the
1659  * enable_uef_lib() or disable_uef_lib().
1660  */
1661 int
1662 update_policylist(uentry_t *puent, mechlist_t *marglist, int update_mode)
1663 {
1664         CK_MECHANISM_TYPE mech_type;
1665         midstr_t        midname;
1666         umechlist_t     *phead;
1667         umechlist_t     *pcur;
1668         umechlist_t     *pumech;
1669         boolean_t       found;
1670         int     rc = SUCCESS;
1671 
1672         if ((puent == NULL) || (marglist == NULL)) {
1673                 /* should not happen */
1674                 cryptoerror(LOG_STDERR, gettext("internal error."));
1675                 cryptodebug("update_policylist()- puent or marglist is NULL.");
1676                 return (FAILURE);
1677         }
1678 
1679         if ((update_mode != ADD_MODE) && (update_mode != DELETE_MODE)) {
1680                 /* should not happen */
1681                 cryptoerror(LOG_STDERR, gettext("internal error."));
1682                 cryptodebug("update_policylist() - update_mode is incorrect.");
1683                 return (FAILURE);
1684         }
1685 
1686         /*
1687          * For each mechanism operand, get its mechanism type first.
1688          * If fails to get the mechanism type, the mechanism operand must be
1689          * invalid, gives an warning and ignore it. Otherwise,
1690          * - convert the mechanism type to the internal representation (hex)
1691          *   in the pkcs11.conf file
1692          * - If update_mode == DELETE_MODE,
1693          *      If the mechanism is in the policy list, delete it.
1694          *      If the mechanism is not in the policy list, do nothing.
1695          * - If update_mode == ADD_MODE,
1696          *      If the mechanism is not in the policy list, add it.
1697          *      If the mechanism is in the policy list already, do nothing.
1698          */
1699         while (marglist) {
1700                 if (pkcs11_str2mech(marglist->name, &mech_type) != CKR_OK) {
1701                         /*
1702                          * This mechanism is not a valid PKCS11 mechanism,
1703                          * give warning and ignore it.
1704                          */
1705                         cryptoerror(LOG_STDERR, gettext(
1706                             "(Warning) %s is not a valid PKCS#11 mechanism."),
1707                             marglist->name);
1708                         rc = FAILURE;
1709                 } else {
1710                         (void) snprintf(midname, sizeof (midname), "%#010x",
1711                             (int)mech_type);
1712                         if (update_mode == DELETE_MODE) {
1713                                 found = B_FALSE;
1714                                 phead = pcur = puent->policylist;
1715                                 while (!found && pcur) {
1716                                         if (strcmp(pcur->name, midname) == 0) {
1717                                                 found = B_TRUE;
1718                                         } else {
1719                                                 phead = pcur;
1720                                                 pcur = pcur->next;
1721                                         }
1722                                 }
1723 
1724                                 if (found) {
1725                                         if (phead == pcur) {
1726                                                 puent->policylist =
1727                                                     puent->policylist->next;
1728                                                 free(pcur);
1729                                         } else {
1730                                                 phead->next = pcur->next;
1731                                                 free(pcur);
1732                                         }
1733                                         puent->count--;
1734                                         if (puent->count == 0) {
1735                                                 puent->policylist = NULL;
1736                                         }
1737                                 }
1738                         } else if (update_mode == ADD_MODE) {
1739                                 if (!is_in_policylist(midname,
1740                                     puent->policylist)) {
1741                                         pumech = create_umech(midname);
1742                                         if (pumech == NULL) {
1743                                                 rc = FAILURE;
1744                                                 break;
1745                                         }
1746                                         phead = puent->policylist;
1747                                         puent->policylist = pumech;
1748                                         pumech->next = phead;
1749                                         puent->count++;
1750                                 }
1751                         }
1752                 }
1753                 marglist = marglist->next;
1754         }
1755 
1756         return (rc);
1757 }
1758 
1759 /*
1760  * Open a session to the given slot and check if we can do
1761  * random numbers by asking for one byte.
1762  */
1763 static boolean_t
1764 check_random(CK_SLOT_ID slot_id, CK_FUNCTION_LIST_PTR prov_funcs)
1765 {
1766         CK_RV rv;
1767         CK_SESSION_HANDLE hSession;
1768         CK_BYTE test_byte;
1769         CK_BYTE_PTR test_byte_ptr = &test_byte;
1770 
1771         rv = prov_funcs->C_OpenSession(slot_id, CKF_SERIAL_SESSION,
1772             NULL_PTR, NULL, &hSession);
1773         if (rv != CKR_OK)
1774                 return (B_FALSE);
1775 
1776         /* We care only about the return value */
1777         rv = prov_funcs->C_GenerateRandom(hSession, test_byte_ptr,
1778             sizeof (test_byte));
1779         (void) prov_funcs->C_CloseSession(hSession);
1780 
1781         /*
1782          * These checks are purely to determine whether the slot can do
1783          * random numbers. So, we don't check whether the routine
1784          * succeeds. The reason we check for CKR_RANDOM_NO_RNG also is that
1785          * this error effectively means CKR_FUNCTION_NOT_SUPPORTED.
1786          */
1787         if (rv != CKR_FUNCTION_NOT_SUPPORTED && rv != CKR_RANDOM_NO_RNG)
1788                 return (B_TRUE);
1789         else
1790                 return (B_FALSE);
1791 }
1792 
1793 void
1794 display_verbose_mech_header()
1795 {
1796         (void) printf("%28s %s", " ", HDR1);
1797         (void) printf("%28s %s", " ", HDR2);
1798         (void) printf("%28s %s", " ", HDR3);
1799         (void) printf("%28s %s", " ", HDR4);
1800         (void) printf("%28s %s", " ", HDR5);
1801         (void) printf("%28s %s", " ", HDR6);
1802         (void) printf("%-28.28s %s", gettext("mechanism name"), HDR7);
1803         /*
1804          * TRANSLATION_NOTE:
1805          * Strictly for appearance's sake, the first header line should be
1806          * as long as the length of the translated text above.  The format
1807          * lengths should all match too.
1808          */
1809         (void) printf("%28s ---- ---- "
1810             "-  -  -  -  -  -  -  -  -  -  -  -  -  -\n",
1811             gettext("----------------------------"));
1812 }