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