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