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