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