Print this page
4853 illumos-gate is not lint-clean when built with openssl 1.0
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.lib/wanboot/p12split/p12split.c
+++ new/usr/src/cmd/cmd-inet/usr.lib/wanboot/p12split/p12split.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, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 #include <stdio.h>
30 28 #include <libintl.h>
31 29 #include <locale.h>
32 30 #include <sys/types.h>
33 31 #include <sys/stat.h>
34 32 #include <sys/wanboot_impl.h>
35 33 #include <unistd.h>
36 34 #include <string.h>
37 35 #include <libinetutil.h>
38 36 #include <wanbootutil.h>
39 37
40 38 #include <openssl/crypto.h>
41 39 #include <openssl/buffer.h>
42 40 #include <openssl/bio.h>
43 41 #include <openssl/err.h>
44 42 #include <openssl/x509.h>
45 43 #include <openssl/x509v3.h>
46 44 #include <openssl/pkcs12.h>
47 45 #include <openssl/evp.h>
48 46 #include <p12aux.h>
49 47
50 48 static boolean_t verbose = B_FALSE; /* When nonzero, do in verbose mode */
51 49
52 50 /* The following match/cert values require PKCS12 */
53 51 static int matchty; /* Type of matching do to on input */
54 52 static char *k_matchval; /* localkeyid value to match */
55 53 static uint_t k_len; /* length of k_matchval */
56 54
57 55 #define IO_KEYFILE 1 /* Have a separate key file or data */
58 56 #define IO_CERTFILE 2 /* Have a separate cert file or data */
59 57 #define IO_TRUSTFILE 4 /* Have a separate trustanchor file */
60 58
61 59 static char *input = NULL; /* Consolidated input file */
62 60 static char *key_out = NULL; /* Key file to be output */
63 61 static char *cert_out = NULL; /* Cert file to be output */
64 62 static char *trust_out = NULL; /* Trust anchor file to be output */
65 63 static uint_t outfiles; /* What files are there for output */
66 64 static char *progname;
67 65
68 66 /* Returns from time_check */
69 67 typedef enum {
70 68 CHK_TIME_OK = 0, /* Cert in effect and not expired */
71 69 CHK_TIME_BEFORE_BAD, /* not_before field is invalid */
72 70 CHK_TIME_AFTER_BAD, /* not_after field is invalid */
73 71 CHK_TIME_IS_BEFORE, /* Cert not yet in force */
74 72 CHK_TIME_HAS_EXPIRED /* Cert has expired */
75 73 } time_errs_t;
76 74
77 75 static int parse_keyid(const char *);
78 76 static int do_certs(void);
79 77 static int read_files(STACK_OF(X509) **, X509 **, EVP_PKEY **);
80 78 static void check_certs(STACK_OF(X509) *, X509 **);
81 79 static time_errs_t time_check_print(X509 *);
82 80 static time_errs_t time_check(X509 *);
83 81 static int write_files(STACK_OF(X509) *, X509 *, EVP_PKEY *);
84 82 static int get_ifile(char *, char *, EVP_PKEY **, X509 **, STACK_OF(X509) **);
85 83 static int do_ofile(char *, EVP_PKEY *, X509 *, STACK_OF(X509) *);
86 84 static void usage(void);
87 85 static const char *cryptoerr(void);
88 86
89 87 int
90 88 main(int argc, char **argv)
91 89 {
92 90 int i;
93 91
94 92 /*
95 93 * Do the necessary magic for localization support.
96 94 */
97 95 (void) setlocale(LC_ALL, "");
98 96 #if !defined(TEXT_DOMAIN)
99 97 #define TEXT_DOMAIN "SYS_TEST"
100 98 #endif
101 99 (void) textdomain(TEXT_DOMAIN);
102 100
103 101 progname = strrchr(argv[0], '/');
104 102 if (progname != NULL)
105 103 progname++;
106 104 else
107 105 progname = argv[0];
108 106
109 107 wbku_errinit(progname);
110 108
111 109 matchty = DO_FIRST_PAIR;
112 110 while ((i = getopt(argc, argv, "vc:i:k:l:t:")) != -1) {
113 111 switch (i) {
114 112 case 'v':
115 113 verbose = B_TRUE;
116 114 break;
117 115
118 116 case 'l':
119 117 if (parse_keyid(optarg) < 0)
120 118 return (EXIT_FAILURE);
121 119 matchty = DO_FIND_KEYID;
122 120 break;
123 121
124 122 case 'c':
125 123 cert_out = optarg;
126 124 outfiles |= IO_CERTFILE;
127 125 break;
128 126
129 127 case 'k':
130 128 key_out = optarg;
131 129 outfiles |= IO_KEYFILE;
132 130 break;
133 131
134 132 case 't':
135 133 trust_out = optarg;
136 134 outfiles |= IO_TRUSTFILE;
137 135 break;
138 136
139 137 case 'i':
140 138 input = optarg;
141 139 break;
142 140
143 141 default:
144 142 usage();
145 143 }
146 144 }
147 145
148 146 if (input == NULL) {
149 147 wbku_printerr("no input file specified\n");
150 148 usage();
151 149 }
152 150
153 151 /*
154 152 * Need output files.
155 153 */
156 154 if (outfiles == 0) {
157 155 wbku_printerr("at least one output file must be specified\n");
158 156 usage();
159 157 }
160 158
161 159 if (do_certs() < 0)
162 160 return (EXIT_FAILURE);
163 161
164 162 return (EXIT_SUCCESS);
165 163 }
166 164
167 165 static int
168 166 parse_keyid(const char *keystr)
169 167 {
170 168 const char *rp;
171 169 char *wp;
172 170 char *nkeystr;
173 171 uint_t nkeystrlen;
174 172
175 173 /*
176 174 * In the worst case, we'll need one additional character in our
177 175 * output string -- e.g. "A\0" -> "0A\0"
178 176 */
179 177 nkeystrlen = strlen(keystr) + 2;
180 178 k_len = (nkeystrlen + 1) / 2;
181 179 nkeystr = malloc(nkeystrlen);
182 180 k_matchval = malloc(k_len);
183 181 if (nkeystr == NULL || k_matchval == NULL) {
184 182 free(nkeystr);
185 183 free(k_matchval);
186 184 wbku_printerr("cannot allocate keyid");
187 185 return (-1);
188 186 }
189 187
190 188 /*
191 189 * For convenience, we allow the user to put spaces between each digit
192 190 * when entering it on the command line. As a result, we need to
193 191 * process it into a format that hexascii_to_octet() can handle. Note
194 192 * that we're careful to map strings like "AA B CC D" to "AA0BCC0D".
195 193 */
196 194 for (rp = keystr, wp = nkeystr; *rp != '\0'; rp++) {
197 195 if (*rp == ' ')
198 196 continue;
199 197
200 198 if (rp[1] == ' ' || rp[1] == '\0') {
201 199 *wp++ = '0'; /* one character sequence; prepend 0 */
202 200 *wp++ = *rp;
203 201 } else {
204 202 *wp++ = *rp++;
205 203 *wp++ = *rp;
206 204 }
207 205 }
208 206 *wp = '\0';
209 207
210 208 if (hexascii_to_octet(nkeystr, wp - nkeystr, k_matchval, &k_len) != 0) {
211 209 free(nkeystr);
212 210 free(k_matchval);
213 211 wbku_printerr("invalid keyid `%s'\n", keystr);
214 212 return (-1);
215 213 }
216 214
217 215 free(nkeystr);
218 216 return (0);
219 217 }
220 218
221 219 static int
222 220 do_certs(void)
223 221 {
224 222 char *bufp;
225 223 STACK_OF(X509) *ta_in = NULL;
226 224 EVP_PKEY *pkey_in = NULL;
227 225 X509 *xcert_in = NULL;
228 226
229 227 sunw_crypto_init();
230 228
231 229 if (read_files(&ta_in, &xcert_in, &pkey_in) < 0)
232 230 return (-1);
233 231
234 232 if (verbose) {
235 233 if (xcert_in != NULL) {
236 234 (void) printf(gettext("\nMain cert:\n"));
237 235
238 236 /*
239 237 * sunw_subject_attrs() returns a pointer to
240 238 * memory allocated on our behalf. The same
241 239 * behavior is exhibited by sunw_issuer_attrs().
242 240 */
243 241 bufp = sunw_subject_attrs(xcert_in, NULL, 0);
244 242 if (bufp != NULL) {
245 243 (void) printf(gettext(" Subject: %s\n"),
246 244 bufp);
247 245 OPENSSL_free(bufp);
248 246 }
249 247
250 248 bufp = sunw_issuer_attrs(xcert_in, NULL, 0);
251 249 if (bufp != NULL) {
252 250 (void) printf(gettext(" Issuer: %s\n"), bufp);
253 251 OPENSSL_free(bufp);
254 252 }
↓ open down ↓ |
216 lines elided |
↑ open up ↑ |
255 253
256 254 (void) sunw_print_times(stdout, PRNT_BOTH, NULL,
257 255 xcert_in);
258 256 }
259 257
260 258 if (ta_in != NULL) {
261 259 X509 *x;
262 260 int i;
263 261
264 262 for (i = 0; i < sk_X509_num(ta_in); i++) {
265 - /* LINTED */
266 263 x = sk_X509_value(ta_in, i);
267 264 (void) printf(
268 265 gettext("\nTrust Anchor cert %d:\n"), i);
269 266
270 267 /*
271 268 * sunw_subject_attrs() returns a pointer to
272 269 * memory allocated on our behalf. We get the
273 270 * same behavior from sunw_issuer_attrs().
274 271 */
275 272 bufp = sunw_subject_attrs(x, NULL, 0);
276 273 if (bufp != NULL) {
277 274 (void) printf(
278 275 gettext(" Subject: %s\n"), bufp);
279 276 OPENSSL_free(bufp);
280 277 }
281 278
282 279 bufp = sunw_issuer_attrs(x, NULL, 0);
283 280 if (bufp != NULL) {
284 281 (void) printf(
285 282 gettext(" Issuer: %s\n"), bufp);
286 283 OPENSSL_free(bufp);
287 284 }
288 285
289 286 (void) sunw_print_times(stdout, PRNT_BOTH,
290 287 NULL, x);
291 288 }
292 289 }
293 290 }
294 291
295 292 check_certs(ta_in, &xcert_in);
296 293 if (xcert_in != NULL && pkey_in != NULL) {
297 294 if (sunw_check_keys(xcert_in, pkey_in) == 0) {
298 295 wbku_printerr("warning: key and certificate do "
299 296 "not match\n");
300 297 }
301 298 }
302 299
303 300 return (write_files(ta_in, xcert_in, pkey_in));
304 301 }
305 302
306 303 static int
307 304 read_files(STACK_OF(X509) **t_in, X509 **c_in, EVP_PKEY **k_in)
308 305 {
309 306 char *i_pass;
310 307
311 308 i_pass = getpassphrase(gettext("Enter key password: "));
312 309
313 310 if (get_ifile(input, i_pass, k_in, c_in, t_in) < 0)
314 311 return (-1);
315 312
316 313 /*
317 314 * If we are only interested in getting a trust anchor, and if there
318 315 * is no trust anchor but is a regular cert, use it instead. Do this
319 316 * to handle the insanity with openssl, which requires a matching cert
320 317 * and key in order to write a PKCS12 file.
321 318 */
322 319 if (outfiles == IO_TRUSTFILE) {
323 320 if (c_in != NULL && *c_in != NULL && t_in != NULL) {
324 321 if (*t_in == NULL) {
325 322 if ((*t_in = sk_X509_new_null()) == NULL) {
326 323 wbku_printerr("out of memory\n");
327 324 return (-1);
328 325 }
329 326 }
330 327
331 328 if (sk_X509_num(*t_in) == 0) {
332 329 if (sk_X509_push(*t_in, *c_in) == 0) {
333 330 wbku_printerr("out of memory\n");
334 331 return (-1);
335 332 }
336 333 *c_in = NULL;
337 334 }
338 335 }
339 336 }
340 337
341 338 if ((outfiles & IO_KEYFILE) && *k_in == NULL) {
342 339 wbku_printerr("no matching key found\n");
343 340 return (-1);
344 341 }
345 342 if ((outfiles & IO_CERTFILE) && *c_in == NULL) {
346 343 wbku_printerr("no matching certificate found\n");
347 344 return (-1);
348 345 }
349 346 if ((outfiles & IO_TRUSTFILE) && *t_in == NULL) {
350 347 wbku_printerr("no matching trust anchor found\n");
351 348 return (-1);
352 349 }
353 350
354 351 return (0);
355 352 }
356 353
357 354 static void
358 355 check_certs(STACK_OF(X509) *ta_in, X509 **c_in)
359 356 {
360 357 X509 *curr;
361 358 time_errs_t ret;
362 359 int i;
363 360 int del_expired = (outfiles != 0);
364 361
365 362 if (c_in != NULL && *c_in != NULL) {
366 363 ret = time_check_print(*c_in);
367 364 if ((ret != CHK_TIME_OK && ret != CHK_TIME_IS_BEFORE) &&
368 365 del_expired) {
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
369 366 (void) fprintf(stderr, gettext(" Removing cert\n"));
370 367 X509_free(*c_in);
371 368 *c_in = NULL;
372 369 }
373 370 }
374 371
375 372 if (ta_in == NULL)
376 373 return;
377 374
378 375 for (i = 0; i < sk_X509_num(ta_in); ) {
379 - /* LINTED */
380 376 curr = sk_X509_value(ta_in, i);
381 377 ret = time_check_print(curr);
382 378 if ((ret != CHK_TIME_OK && ret != CHK_TIME_IS_BEFORE) &&
383 379 del_expired) {
384 380 (void) fprintf(stderr, gettext(" Removing cert\n"));
385 - /* LINTED */
386 381 curr = sk_X509_delete(ta_in, i);
387 382 X509_free(curr);
388 383 continue;
389 384 }
390 385 i++;
391 386 }
392 387 }
393 388
394 389 static time_errs_t
395 390 time_check_print(X509 *cert)
396 391 {
397 392 char buf[256];
398 393 int ret;
399 394
400 395 ret = time_check(cert);
401 396 if (ret == CHK_TIME_OK)
402 397 return (CHK_TIME_OK);
403 398
404 399 (void) fprintf(stderr, gettext(" Subject: %s"),
405 400 sunw_subject_attrs(cert, buf, sizeof (buf)));
406 401 (void) fprintf(stderr, gettext(" Issuer: %s"),
407 402 sunw_issuer_attrs(cert, buf, sizeof (buf)));
408 403
409 404 switch (ret) {
410 405 case CHK_TIME_BEFORE_BAD:
411 406 (void) fprintf(stderr,
412 407 gettext("\n Invalid cert 'not before' field\n"));
413 408 break;
414 409
415 410 case CHK_TIME_AFTER_BAD:
416 411 (void) fprintf(stderr,
417 412 gettext("\n Invalid cert 'not after' field\n"));
418 413 break;
419 414
420 415 case CHK_TIME_HAS_EXPIRED:
421 416 (void) sunw_print_times(stderr, PRNT_NOT_AFTER,
422 417 gettext("\n Cert has expired\n"), cert);
423 418 break;
424 419
425 420 case CHK_TIME_IS_BEFORE:
426 421 (void) sunw_print_times(stderr, PRNT_NOT_BEFORE,
427 422 gettext("\n Warning: cert not yet valid\n"), cert);
428 423 break;
429 424
430 425 default:
431 426 break;
432 427 }
433 428
434 429 return (ret);
435 430 }
436 431
437 432 static time_errs_t
438 433 time_check(X509 *cert)
439 434 {
440 435 int i;
441 436
442 437 i = X509_cmp_time(X509_get_notBefore(cert), NULL);
443 438 if (i == 0)
444 439 return (CHK_TIME_BEFORE_BAD);
445 440 if (i > 0)
446 441 return (CHK_TIME_IS_BEFORE);
447 442 /* After 'not before' time */
448 443
449 444 i = X509_cmp_time(X509_get_notAfter(cert), NULL);
450 445 if (i == 0)
451 446 return (CHK_TIME_AFTER_BAD);
452 447 if (i < 0)
453 448 return (CHK_TIME_HAS_EXPIRED);
454 449 return (CHK_TIME_OK);
455 450 }
456 451
457 452 static int
458 453 write_files(STACK_OF(X509) *t_out, X509 *c_out, EVP_PKEY *k_out)
459 454 {
460 455 if (key_out != NULL) {
461 456 if (verbose)
462 457 (void) printf(gettext("%s: writing key\n"), progname);
463 458 if (do_ofile(key_out, k_out, NULL, NULL) < 0)
464 459 return (-1);
465 460 }
466 461
467 462 if (cert_out != NULL) {
468 463 if (verbose)
469 464 (void) printf(gettext("%s: writing cert\n"), progname);
470 465 if (do_ofile(cert_out, NULL, c_out, NULL) < 0)
471 466 return (-1);
472 467 }
473 468
474 469 if (trust_out != NULL) {
475 470 if (verbose)
476 471 (void) printf(gettext("%s: writing trust\n"),
477 472 progname);
478 473 if (do_ofile(trust_out, NULL, NULL, t_out) < 0)
479 474 return (-1);
480 475 }
481 476
482 477 return (0);
483 478 }
484 479
485 480 static int
486 481 get_ifile(char *name, char *pass, EVP_PKEY **tmp_k, X509 **tmp_c,
487 482 STACK_OF(X509) **tmp_t)
488 483 {
489 484 PKCS12 *p12;
490 485 FILE *fp;
491 486 int ret;
492 487 struct stat sbuf;
493 488
494 489 if (stat(name, &sbuf) == 0 && !S_ISREG(sbuf.st_mode)) {
495 490 wbku_printerr("%s is not a regular file\n", name);
496 491 return (-1);
497 492 }
498 493
499 494 if ((fp = fopen(name, "r")) == NULL) {
500 495 wbku_printerr("cannot open input file %s", name);
501 496 return (-1);
502 497 }
503 498
504 499 p12 = d2i_PKCS12_fp(fp, NULL);
505 500 if (p12 == NULL) {
506 501 wbku_printerr("cannot read file %s: %s\n", name, cryptoerr());
507 502 (void) fclose(fp);
508 503 return (-1);
509 504 }
510 505 (void) fclose(fp);
511 506
512 507 ret = sunw_PKCS12_parse(p12, pass, matchty, k_matchval, k_len,
513 508 NULL, tmp_k, tmp_c, tmp_t);
514 509 if (ret <= 0) {
515 510 if (ret == 0)
516 511 wbku_printerr("cannot find matching cert and key\n");
517 512 else
518 513 wbku_printerr("cannot parse %s: %s\n", name,
519 514 cryptoerr());
520 515 PKCS12_free(p12);
521 516 return (-1);
522 517 }
523 518 return (0);
524 519 }
525 520
526 521 static int
527 522 do_ofile(char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ta)
528 523 {
529 524 STACK_OF(EVP_PKEY) *klist = NULL;
530 525 STACK_OF(X509) *clist = NULL;
531 526 PKCS12 *p12 = NULL;
532 527 int ret = 0;
533 528 FILE *fp;
534 529 struct stat sbuf;
535 530
536 531 if (stat(name, &sbuf) == 0 && !S_ISREG(sbuf.st_mode)) {
537 532 wbku_printerr("%s is not a regular file\n", name);
538 533 return (-1);
539 534 }
540 535
541 536 if ((fp = fopen(name, "w")) == NULL) {
542 537 wbku_printerr("cannot open output file %s", name);
543 538 return (-1);
544 539 }
545 540
546 541 if ((clist = sk_X509_new_null()) == NULL ||
547 542 (klist = sk_EVP_PKEY_new_null()) == NULL) {
548 543 wbku_printerr("out of memory\n");
549 544 ret = -1;
550 545 goto cleanup;
551 546 }
552 547
553 548 if (cert != NULL && sk_X509_push(clist, cert) == 0) {
554 549 wbku_printerr("out of memory\n");
555 550 ret = -1;
556 551 goto cleanup;
557 552 }
558 553
559 554 if (pkey != NULL && sk_EVP_PKEY_push(klist, pkey) == 0) {
560 555 wbku_printerr("out of memory\n");
561 556 ret = -1;
562 557 goto cleanup;
563 558 }
564 559
565 560 p12 = sunw_PKCS12_create(WANBOOT_PASSPHRASE, klist, clist, ta);
566 561 if (p12 == NULL) {
567 562 wbku_printerr("cannot create %s: %s\n", name, cryptoerr());
568 563 ret = -1;
569 564 goto cleanup;
570 565 }
571 566
572 567 if (i2d_PKCS12_fp(fp, p12) == 0) {
573 568 wbku_printerr("cannot write %s: %s\n", name, cryptoerr());
574 569 ret = -1;
575 570 goto cleanup;
576 571 }
577 572
578 573 cleanup:
↓ open down ↓ |
183 lines elided |
↑ open up ↑ |
579 574 (void) fclose(fp);
580 575 if (p12 != NULL)
581 576 PKCS12_free(p12);
582 577 /*
583 578 * Put the cert and pkey off of the stack so that they won't
584 579 * be freed two times. (If they get left in the stack then
585 580 * they will be freed with the stack.)
586 581 */
587 582 if (clist != NULL) {
588 583 if (cert != NULL && sk_X509_num(clist) == 1) {
589 - /* LINTED */
590 584 (void) sk_X509_delete(clist, 0);
591 585 }
592 586 sk_X509_pop_free(clist, X509_free);
593 587 }
594 588 if (klist != NULL) {
595 589 if (pkey != NULL && sk_EVP_PKEY_num(klist) == 1) {
596 - /* LINTED */
597 590 (void) sk_EVP_PKEY_delete(klist, 0);
598 591 }
599 592 sk_EVP_PKEY_pop_free(klist, sunw_evp_pkey_free);
600 593 }
601 594
602 595 return (ret);
603 596 }
604 597
605 598 static void
606 599 usage(void)
607 600 {
608 601 (void) fprintf(stderr,
609 602 gettext("usage:\n"
610 603 " %s -i <file> -c <file> -k <file> -t <file> [-l <keyid> -v]\n"
611 604 "\n"),
612 605 progname);
613 606 (void) fprintf(stderr,
614 607 gettext(" where:\n"
615 608 " -i - input file to be split into component parts and put in\n"
616 609 " files given by -c, -k and -t\n"
617 610 " -c - output file for the client certificate\n"
618 611 " -k - output file for the client private key\n"
619 612 " -t - output file for the remaining certificates (assumed\n"
620 613 " to be trust anchors)\n"
621 614 "\n Files are assumed to be pkcs12-format files.\n\n"
622 615 " -v - verbose\n"
623 616 " -l - value of 'localkeyid' attribute in client cert and\n"
624 617 " private key to be selected from the input file.\n\n"));
625 618 exit(EXIT_FAILURE);
626 619 }
627 620
628 621 /*
629 622 * Return a pointer to a static buffer that contains a listing of crypto
630 623 * errors. We presume that the user doesn't want more than 8KB of error
631 624 * messages :-)
632 625 */
633 626 static const char *
634 627 cryptoerr(void)
635 628 {
636 629 static char errbuf[8192];
637 630 ulong_t err;
638 631 const char *pfile;
639 632 int line;
640 633 unsigned int nerr = 0;
641 634
642 635 errbuf[0] = '\0';
643 636 while ((err = ERR_get_error_line(&pfile, &line)) != 0) {
644 637 if (++nerr > 1)
645 638 (void) strlcat(errbuf, "\n\t", sizeof (errbuf));
646 639
647 640 if (err == (ulong_t)-1) {
648 641 (void) strlcat(errbuf, strerror(errno),
649 642 sizeof (errbuf));
650 643 break;
651 644 }
652 645 (void) strlcat(errbuf, ERR_reason_error_string(err),
653 646 sizeof (errbuf));
654 647 }
655 648
656 649 return (errbuf);
657 650 }
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX