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