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