xref: /illumos-gate/usr/src/cmd/cmd-crypto/kmfcfg/modify.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <stdio.h>
28 #include <strings.h>
29 #include <ctype.h>
30 #include <libgen.h>
31 #include <libintl.h>
32 #include <errno.h>
33 #include <kmfapiP.h>
34 #include <cryptoutil.h>
35 #include <sys/stat.h>
36 #include <sys/param.h>
37 #include "util.h"
38 
39 #define	KC_IGNORE_DATE			0x0000001
40 #define	KC_IGNORE_UNKNOWN_EKUS		0x0000002
41 #define	KC_IGNORE_TRUST_ANCHOR		0x0000004
42 #define	KC_VALIDITY_ADJUSTTIME		0x0000008
43 #define	KC_TA_NAME			0x0000010
44 #define	KC_TA_SERIAL			0x0000020
45 #define	KC_OCSP_RESPONDER_URI		0x0000040
46 #define	KC_OCSP_PROXY			0x0000080
47 #define	KC_OCSP_URI_FROM_CERT		0x0000100
48 #define	KC_OCSP_RESP_LIFETIME		0x0000200
49 #define	KC_OCSP_IGNORE_RESP_SIGN 	0x0000400
50 #define	KC_OCSP_RESP_CERT_NAME		0x0000800
51 #define	KC_OCSP_RESP_CERT_SERIAL	0x0001000
52 #define	KC_OCSP_NONE			0x0002000
53 #define	KC_CRL_BASEFILENAME		0x0004000
54 #define	KC_CRL_DIRECTORY		0x0008000
55 #define	KC_CRL_GET_URI			0x0010000
56 #define	KC_CRL_PROXY			0x0020000
57 #define	KC_CRL_IGNORE_SIGN		0x0040000
58 #define	KC_CRL_IGNORE_DATE		0x0080000
59 #define	KC_CRL_NONE			0x0100000
60 #define	KC_KEYUSAGE			0x0200000
61 #define	KC_KEYUSAGE_NONE		0x0400000
62 #define	KC_EKUS				0x0800000
63 #define	KC_EKUS_NONE			0x1000000
64 
65 static int err; /* To store errno which may be overwritten by gettext() */
66 
67 
68 int
69 kc_modify_policy(int argc, char *argv[])
70 {
71 	KMF_RETURN	ret;
72 	int 		rv = KC_OK;
73 	int		opt;
74 	extern int	optind_av;
75 	extern char	*optarg_av;
76 	char		*filename = NULL;
77 	uint32_t	flags = 0;
78 	boolean_t	ocsp_none_opt = B_FALSE;
79 	boolean_t	crl_none_opt = B_FALSE;
80 	boolean_t	ku_none_opt = B_FALSE;
81 	boolean_t	eku_none_opt = B_FALSE;
82 	int		ocsp_set_attr = 0;
83 	int		crl_set_attr = 0;
84 	KMF_POLICY_RECORD oplc, plc;
85 
86 	(void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD));
87 	(void) memset(&oplc, 0, sizeof (KMF_POLICY_RECORD));
88 
89 	while ((opt = getopt_av(argc, argv,
90 	    "i:(dbfile)"
91 	    "p:(policy)"
92 	    "d:(ignore-date)"
93 	    "e:(ignore-unknown-eku)"
94 	    "a:(ignore-trust-anchor)"
95 	    "v:(validity-adjusttime)"
96 	    "t:(ta-name)"
97 	    "s:(ta-serial)"
98 	    "o:(ocsp-responder)"
99 	    "P:(ocsp-proxy)"
100 	    "r:(ocsp-use-cert-responder)"
101 	    "T:(ocsp-response-lifetime)"
102 	    "R:(ocsp-ignore-response-sign)"
103 	    "n:(ocsp-responder-cert-name)"
104 	    "A:(ocsp-responder-cert-serial)"
105 	    "y:(ocsp-none)"
106 	    "c:(crl-basefilename)"
107 	    "I:(crl-directory)"
108 	    "g:(crl-get-crl-uri)"
109 	    "X:(crl-proxy)"
110 	    "S:(crl-ignore-crl-sign)"
111 	    "D:(crl-ignore-crl-date)"
112 	    "z:(crl-none)"
113 	    "u:(keyusage)"
114 	    "Y:(keyusage-none)"
115 	    "E:(ekunames)"
116 	    "O:(ekuoids)"
117 	    "Z:(eku-none)")) != EOF) {
118 		switch (opt) {
119 			case 'i':
120 				filename = get_string(optarg_av, &rv);
121 				if (filename == NULL) {
122 					(void) fprintf(stderr,
123 					    gettext("Error dbfile input.\n"));
124 				}
125 				break;
126 			case 'p':
127 				plc.name = get_string(optarg_av, &rv);
128 				if (plc.name == NULL) {
129 					(void) fprintf(stderr,
130 					    gettext("Error policy name.\n"));
131 				}
132 				break;
133 			case 'd':
134 				plc.ignore_date = get_boolean(optarg_av);
135 				if (plc.ignore_date == -1) {
136 					(void) fprintf(stderr,
137 					    gettext("Error boolean input.\n"));
138 					rv = KC_ERR_USAGE;
139 				} else {
140 					flags |= KC_IGNORE_DATE;
141 				}
142 				break;
143 			case 'e':
144 				plc.ignore_unknown_ekus =
145 				    get_boolean(optarg_av);
146 				if (plc.ignore_unknown_ekus == -1) {
147 					(void) fprintf(stderr,
148 					    gettext("Error boolean input.\n"));
149 					rv = KC_ERR_USAGE;
150 				} else {
151 					flags |= KC_IGNORE_UNKNOWN_EKUS;
152 				}
153 				break;
154 			case 'a':
155 				plc.ignore_trust_anchor =
156 				    get_boolean(optarg_av);
157 				if (plc.ignore_trust_anchor == -1) {
158 					(void) fprintf(stderr,
159 					    gettext("Error boolean input.\n"));
160 					rv = KC_ERR_USAGE;
161 				} else {
162 					flags |= KC_IGNORE_TRUST_ANCHOR;
163 				}
164 				break;
165 			case 'v':
166 				plc.validity_adjusttime =
167 				    get_string(optarg_av, &rv);
168 				if (plc.validity_adjusttime == NULL) {
169 					(void) fprintf(stderr,
170 					    gettext("Error time input.\n"));
171 				} else {
172 					uint32_t adj;
173 					/* for syntax checking */
174 					if (str2lifetime(
175 					    plc.validity_adjusttime,
176 					    &adj) < 0) {
177 						(void) fprintf(stderr,
178 						    gettext("Error time "
179 						    "input.\n"));
180 						rv = KC_ERR_USAGE;
181 					} else {
182 						flags |= KC_VALIDITY_ADJUSTTIME;
183 					}
184 				}
185 				break;
186 			case 't':
187 				plc.ta_name = get_string(optarg_av, &rv);
188 				if (plc.ta_name == NULL) {
189 					(void) fprintf(stderr,
190 					    gettext("Error name input.\n"));
191 				} else {
192 					KMF_X509_NAME taDN;
193 					/* for syntax checking */
194 					if (kmf_dn_parser(plc.ta_name,
195 					    &taDN) != KMF_OK) {
196 						(void) fprintf(stderr,
197 						    gettext("Error name "
198 						    "input.\n"));
199 						rv = KC_ERR_USAGE;
200 					} else {
201 						kmf_free_dn(&taDN);
202 						flags |= KC_TA_NAME;
203 					}
204 				}
205 				break;
206 			case 's':
207 				plc.ta_serial = get_string(optarg_av, &rv);
208 				if (plc.ta_serial == NULL) {
209 					(void) fprintf(stderr,
210 					    gettext("Error serial input.\n"));
211 				} else {
212 					uchar_t *bytes = NULL;
213 					size_t bytelen;
214 
215 					ret = kmf_hexstr_to_bytes(
216 					    (uchar_t *)plc.ta_serial,
217 					    &bytes, &bytelen);
218 					if (ret != KMF_OK || bytes == NULL) {
219 						(void) fprintf(stderr,
220 						    gettext("serial number "
221 						    "must be specified as a "
222 						    "hex number "
223 						    "(ex: 0x0102030405"
224 						    "ffeeddee)\n"));
225 						rv = KC_ERR_USAGE;
226 						break;
227 					}
228 					if (bytes != NULL)
229 						free(bytes);
230 					flags |= KC_TA_SERIAL;
231 				}
232 				break;
233 			case 'o':
234 				plc.VAL_OCSP_RESPONDER_URI =
235 				    get_string(optarg_av, &rv);
236 				if (plc.VAL_OCSP_RESPONDER_URI == NULL) {
237 					(void) fprintf(stderr,
238 					    gettext("Error responder "
239 					    "input.\n"));
240 				} else {
241 					flags |= KC_OCSP_RESPONDER_URI;
242 					ocsp_set_attr++;
243 				}
244 				break;
245 			case 'P':
246 				plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv);
247 				if (plc.VAL_OCSP_PROXY == NULL) {
248 					(void) fprintf(stderr,
249 					    gettext("Error proxy input.\n"));
250 				} else {
251 					flags |= KC_OCSP_PROXY;
252 					ocsp_set_attr++;
253 				}
254 				break;
255 			case 'r':
256 				plc.VAL_OCSP_URI_FROM_CERT =
257 				    get_boolean(optarg_av);
258 				if (plc.VAL_OCSP_URI_FROM_CERT == -1) {
259 					(void) fprintf(stderr,
260 					    gettext("Error boolean input.\n"));
261 					rv = KC_ERR_USAGE;
262 				} else {
263 					flags |= KC_OCSP_URI_FROM_CERT;
264 					ocsp_set_attr++;
265 				}
266 				break;
267 			case 'T':
268 				plc.VAL_OCSP_RESP_LIFETIME =
269 				    get_string(optarg_av, &rv);
270 				if (plc.VAL_OCSP_RESP_LIFETIME == NULL) {
271 					(void) fprintf(stderr,
272 					    gettext("Error time input.\n"));
273 				} else {
274 					uint32_t adj;
275 					/* for syntax checking */
276 					if (str2lifetime(
277 					    plc.VAL_OCSP_RESP_LIFETIME,
278 					    &adj) < 0) {
279 						(void) fprintf(stderr,
280 						    gettext("Error time "
281 						    "input.\n"));
282 						rv = KC_ERR_USAGE;
283 					} else {
284 						flags |= KC_OCSP_RESP_LIFETIME;
285 						ocsp_set_attr++;
286 					}
287 				}
288 				break;
289 			case 'R':
290 				plc.VAL_OCSP_IGNORE_RESP_SIGN =
291 				    get_boolean(optarg_av);
292 				if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) {
293 					(void) fprintf(stderr,
294 					    gettext("Error boolean input.\n"));
295 					rv = KC_ERR_USAGE;
296 				} else {
297 					flags |= KC_OCSP_IGNORE_RESP_SIGN;
298 					ocsp_set_attr++;
299 				}
300 				break;
301 			case 'n':
302 				plc.VAL_OCSP_RESP_CERT_NAME =
303 				    get_string(optarg_av, &rv);
304 				if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) {
305 					(void) fprintf(stderr,
306 					    gettext("Error name input.\n"));
307 				} else {
308 					KMF_X509_NAME respDN;
309 					/* for syntax checking */
310 					if (kmf_dn_parser(
311 					    plc.VAL_OCSP_RESP_CERT_NAME,
312 					    &respDN) != KMF_OK) {
313 						(void) fprintf(stderr,
314 						    gettext("Error name "
315 						    "input.\n"));
316 						rv = KC_ERR_USAGE;
317 					} else {
318 						kmf_free_dn(&respDN);
319 						flags |= KC_OCSP_RESP_CERT_NAME;
320 						ocsp_set_attr++;
321 					}
322 				}
323 				break;
324 			case 'A':
325 				plc.VAL_OCSP_RESP_CERT_SERIAL =
326 				    get_string(optarg_av, &rv);
327 				if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) {
328 					(void) fprintf(stderr,
329 					    gettext("Error serial input.\n"));
330 				} else {
331 					uchar_t *bytes = NULL;
332 					size_t bytelen;
333 
334 					ret = kmf_hexstr_to_bytes((uchar_t *)
335 					    plc.VAL_OCSP_RESP_CERT_SERIAL,
336 					    &bytes, &bytelen);
337 					if (ret != KMF_OK || bytes == NULL) {
338 						(void) fprintf(stderr,
339 						    gettext("serial number "
340 						    "must be specified as a "
341 						    "hex number "
342 						    "(ex: 0x0102030405"
343 						    "ffeeddee)\n"));
344 						rv = KC_ERR_USAGE;
345 						break;
346 					}
347 					if (bytes != NULL)
348 						free(bytes);
349 					flags |= KC_OCSP_RESP_CERT_SERIAL;
350 					ocsp_set_attr++;
351 				}
352 				break;
353 			case 'y':
354 				ocsp_none_opt = get_boolean(optarg_av);
355 				if (ocsp_none_opt == -1) {
356 					(void) fprintf(stderr,
357 					    gettext("Error boolean input.\n"));
358 					rv = KC_ERR_USAGE;
359 				} else {
360 					flags |= KC_OCSP_NONE;
361 				}
362 				break;
363 			case 'c':
364 				plc.VAL_CRL_BASEFILENAME =
365 				    get_string(optarg_av, &rv);
366 				if (plc.VAL_CRL_BASEFILENAME == NULL) {
367 					(void) fprintf(stderr, gettext(
368 					    "Error basefilename input.\n"));
369 				} else {
370 					flags |= KC_CRL_BASEFILENAME;
371 					crl_set_attr++;
372 				}
373 				break;
374 			case 'I':
375 				plc.VAL_CRL_DIRECTORY =
376 				    get_string(optarg_av, &rv);
377 				if (plc.VAL_CRL_DIRECTORY == NULL) {
378 					(void) fprintf(stderr,
379 					    gettext("Error boolean input.\n"));
380 				} else {
381 					flags |= KC_CRL_DIRECTORY;
382 					crl_set_attr++;
383 				}
384 				break;
385 			case 'g':
386 				plc.VAL_CRL_GET_URI = get_boolean(optarg_av);
387 				if (plc.VAL_CRL_GET_URI == -1) {
388 					(void) fprintf(stderr,
389 					    gettext("Error boolean input.\n"));
390 					rv = KC_ERR_USAGE;
391 				} else {
392 					flags |= KC_CRL_GET_URI;
393 					crl_set_attr++;
394 				}
395 				break;
396 			case 'X':
397 				plc.VAL_CRL_PROXY = get_string(optarg_av, &rv);
398 				if (plc.VAL_CRL_PROXY == NULL) {
399 					(void) fprintf(stderr,
400 					    gettext("Error proxy input.\n"));
401 				} else {
402 					flags |= KC_CRL_PROXY;
403 					crl_set_attr++;
404 				}
405 				break;
406 			case 'S':
407 				plc.VAL_CRL_IGNORE_SIGN =
408 				    get_boolean(optarg_av);
409 				if (plc.VAL_CRL_IGNORE_SIGN == -1) {
410 					(void) fprintf(stderr,
411 					    gettext("Error boolean input.\n"));
412 					rv = KC_ERR_USAGE;
413 				} else {
414 					flags |= KC_CRL_IGNORE_SIGN;
415 					crl_set_attr++;
416 				}
417 				break;
418 			case 'D':
419 				plc.VAL_CRL_IGNORE_DATE =
420 				    get_boolean(optarg_av);
421 				if (plc.VAL_CRL_IGNORE_DATE == -1) {
422 					(void) fprintf(stderr,
423 					    gettext("Error boolean input.\n"));
424 					rv = KC_ERR_USAGE;
425 				} else {
426 					flags |= KC_CRL_IGNORE_DATE;
427 					crl_set_attr++;
428 				}
429 				break;
430 			case 'z':
431 				crl_none_opt = get_boolean(optarg_av);
432 				if (crl_none_opt == -1) {
433 					(void) fprintf(stderr,
434 					    gettext("Error boolean input.\n"));
435 					rv = KC_ERR_USAGE;
436 				} else {
437 					flags |= KC_CRL_NONE;
438 				}
439 				break;
440 			case 'u':
441 				plc.ku_bits = parseKUlist(optarg_av);
442 				if (plc.ku_bits == 0) {
443 					(void) fprintf(stderr, gettext(
444 					    "Error keyusage input.\n"));
445 					rv = KC_ERR_USAGE;
446 				} else {
447 					flags |= KC_KEYUSAGE;
448 				}
449 				break;
450 			case 'Y':
451 				ku_none_opt = get_boolean(optarg_av);
452 				if (ku_none_opt == -1) {
453 					(void) fprintf(stderr,
454 					    gettext("Error boolean input.\n"));
455 					rv = KC_ERR_USAGE;
456 				} else {
457 					flags |= KC_KEYUSAGE_NONE;
458 				}
459 				break;
460 			case 'E':
461 				if (parseEKUNames(optarg_av, &plc) != 0) {
462 					(void) fprintf(stderr,
463 					    gettext("Error EKU input.\n"));
464 					rv = KC_ERR_USAGE;
465 				} else {
466 					flags |= KC_EKUS;
467 				}
468 				break;
469 			case 'O':
470 				if (parseEKUOIDs(optarg_av, &plc) != 0) {
471 					(void) fprintf(stderr,
472 					    gettext("Error EKU OID input.\n"));
473 					rv = KC_ERR_USAGE;
474 				} else {
475 					flags |= KC_EKUS;
476 				}
477 				break;
478 			case 'Z':
479 				eku_none_opt = get_boolean(optarg_av);
480 				if (eku_none_opt == -1) {
481 					(void) fprintf(stderr,
482 					    gettext("Error boolean input.\n"));
483 					rv = KC_ERR_USAGE;
484 				} else {
485 					flags |= KC_EKUS_NONE;
486 				}
487 				break;
488 			default:
489 				(void) fprintf(stderr,
490 				    gettext("Error input option.\n"));
491 				rv = KC_ERR_USAGE;
492 				break;
493 		}
494 		if (rv != KC_OK)
495 			goto out;
496 	}
497 
498 	/* No additional args allowed. */
499 	argc -= optind_av;
500 	if (argc) {
501 		(void) fprintf(stderr,
502 		    gettext("Error input option\n"));
503 		rv = KC_ERR_USAGE;
504 		goto out;
505 	}
506 
507 	if (filename == NULL) {
508 		filename = strdup(KMF_DEFAULT_POLICY_FILE);
509 		if (filename == NULL) {
510 			rv = KC_ERR_MEMORY;
511 			goto out;
512 		}
513 	}
514 
515 	/*
516 	 * Must have a policy name. The policy name can not be default
517 	 * if using the default policy file.
518 	 */
519 	if (plc.name == NULL) {
520 		(void) fprintf(stderr,
521 		    gettext("You must specify a policy name.\n"));
522 		rv = KC_ERR_USAGE;
523 		goto out;
524 	} else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 &&
525 	    strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) {
526 		(void) fprintf(stderr,
527 		    gettext("Can not modify the default policy in the default "
528 		    "policy file.\n"));
529 		rv = KC_ERR_USAGE;
530 		goto out;
531 	}
532 
533 	/* Check the access permission of the policy DB */
534 	if (access(filename, W_OK) < 0) {
535 		int err = errno;
536 		(void) fprintf(stderr,
537 		    gettext("Cannot access \"%s\" for modify - %s\n"),
538 		    filename, strerror(err));
539 		rv = KC_ERR_ACCESS;
540 		goto out;
541 	}
542 
543 	/* Try to load the named policy from the DB */
544 	ret = kmf_get_policy(filename, plc.name, &oplc);
545 	if (ret != KMF_OK) {
546 		(void) fprintf(stderr,
547 		    gettext("Error loading policy \"%s\" from %s\n"), filename,
548 		    plc.name);
549 		return (KC_ERR_FIND_POLICY);
550 	}
551 
552 	/* Update the general policy attributes. */
553 	if (flags & KC_IGNORE_DATE)
554 		oplc.ignore_date = plc.ignore_date;
555 
556 	if (flags & KC_IGNORE_UNKNOWN_EKUS)
557 		oplc.ignore_unknown_ekus = plc.ignore_unknown_ekus;
558 
559 	if (flags & KC_IGNORE_TRUST_ANCHOR)
560 		oplc.ignore_trust_anchor = plc.ignore_trust_anchor;
561 
562 	if (flags & KC_VALIDITY_ADJUSTTIME) {
563 		if (oplc.validity_adjusttime)
564 			free(oplc.validity_adjusttime);
565 		oplc.validity_adjusttime =
566 		    plc.validity_adjusttime;
567 	}
568 
569 	if (flags & KC_TA_NAME) {
570 		if (oplc.ta_name)
571 			free(oplc.ta_name);
572 		oplc.ta_name = plc.ta_name;
573 	}
574 	if (flags & KC_TA_SERIAL) {
575 		if (oplc.ta_serial)
576 			free(oplc.ta_serial);
577 		oplc.ta_serial = plc.ta_serial;
578 	}
579 
580 	/* Update the OCSP policy */
581 	if (ocsp_none_opt == B_TRUE) {
582 		if (ocsp_set_attr > 0) {
583 			(void) fprintf(stderr,
584 			    gettext("Can not set ocsp-none=true and other "
585 			    "OCSP attributes at the same time.\n"));
586 			rv = KC_ERR_USAGE;
587 			goto out;
588 		}
589 
590 		/*
591 		 * If the original policy does not have OCSP checking,
592 		 * then we do not need to do anything.  If the original
593 		 * policy has the OCSP checking, then we need to release the
594 		 * space of OCSP attributes and turn the OCSP checking off.
595 		 */
596 		if (oplc.revocation & KMF_REVOCATION_METHOD_OCSP) {
597 			if (oplc.VAL_OCSP_BASIC.responderURI) {
598 				free(oplc.VAL_OCSP_BASIC.responderURI);
599 				oplc.VAL_OCSP_BASIC.responderURI = NULL;
600 			}
601 
602 			if (oplc.VAL_OCSP_BASIC.proxy) {
603 				free(oplc.VAL_OCSP_BASIC.proxy);
604 				oplc.VAL_OCSP_BASIC.proxy = NULL;
605 			}
606 
607 			if (oplc.VAL_OCSP_BASIC.response_lifetime) {
608 				free(oplc.VAL_OCSP_BASIC.response_lifetime);
609 				oplc.VAL_OCSP_BASIC.response_lifetime = NULL;
610 			}
611 
612 			if (flags & KC_OCSP_RESP_CERT_NAME) {
613 				free(oplc.VAL_OCSP_RESP_CERT.name);
614 				oplc.VAL_OCSP_RESP_CERT.name = NULL;
615 			}
616 
617 			if (flags & KC_OCSP_RESP_CERT_SERIAL) {
618 				free(oplc.VAL_OCSP_RESP_CERT.serial);
619 				oplc.VAL_OCSP_RESP_CERT.serial = NULL;
620 			}
621 
622 			/* Turn off the OCSP checking */
623 			oplc.revocation &= ~KMF_REVOCATION_METHOD_OCSP;
624 		}
625 
626 	} else {
627 		/*
628 		 * If the "ocsp-none" option is not set or is set to false,
629 		 * then we only need to do the modification if there is at
630 		 * least one OCSP attribute is specified.
631 		 */
632 		if (ocsp_set_attr > 0) {
633 			if (flags & KC_OCSP_RESPONDER_URI) {
634 				if (oplc.VAL_OCSP_RESPONDER_URI)
635 					free(oplc.VAL_OCSP_RESPONDER_URI);
636 				oplc.VAL_OCSP_RESPONDER_URI =
637 				    plc.VAL_OCSP_RESPONDER_URI;
638 			}
639 
640 			if (flags & KC_OCSP_PROXY) {
641 				if (oplc.VAL_OCSP_PROXY)
642 					free(oplc.VAL_OCSP_PROXY);
643 				oplc.VAL_OCSP_PROXY = plc.VAL_OCSP_PROXY;
644 			}
645 
646 			if (flags & KC_OCSP_URI_FROM_CERT)
647 				oplc.VAL_OCSP_URI_FROM_CERT =
648 				    plc.VAL_OCSP_URI_FROM_CERT;
649 
650 			if (flags & KC_OCSP_RESP_LIFETIME) {
651 				if (oplc.VAL_OCSP_RESP_LIFETIME)
652 					free(oplc.VAL_OCSP_RESP_LIFETIME);
653 				oplc.VAL_OCSP_RESP_LIFETIME =
654 				    plc.VAL_OCSP_RESP_LIFETIME;
655 			}
656 
657 			if (flags & KC_OCSP_IGNORE_RESP_SIGN)
658 				oplc.VAL_OCSP_IGNORE_RESP_SIGN =
659 				    plc.VAL_OCSP_IGNORE_RESP_SIGN;
660 
661 			if (flags & KC_OCSP_RESP_CERT_NAME) {
662 				if (oplc.VAL_OCSP_RESP_CERT_NAME)
663 					free(oplc.VAL_OCSP_RESP_CERT_NAME);
664 				oplc.VAL_OCSP_RESP_CERT_NAME =
665 				    plc.VAL_OCSP_RESP_CERT_NAME;
666 			}
667 
668 			if (flags & KC_OCSP_RESP_CERT_SERIAL) {
669 				if (oplc.VAL_OCSP_RESP_CERT_SERIAL)
670 					free(oplc.VAL_OCSP_RESP_CERT_SERIAL);
671 				oplc.VAL_OCSP_RESP_CERT_SERIAL =
672 				    plc.VAL_OCSP_RESP_CERT_SERIAL;
673 			}
674 
675 			if (oplc.VAL_OCSP_RESP_CERT_NAME != NULL &&
676 			    oplc.VAL_OCSP_RESP_CERT_SERIAL != NULL)
677 				oplc.VAL_OCSP.has_resp_cert = B_TRUE;
678 			else
679 				oplc.VAL_OCSP.has_resp_cert = B_FALSE;
680 
681 			/* Turn on the OCSP checking */
682 			oplc.revocation |= KMF_REVOCATION_METHOD_OCSP;
683 		}
684 	}
685 
686 	/* Update the CRL policy */
687 	if (crl_none_opt == B_TRUE) {
688 		if (crl_set_attr > 0) {
689 			(void) fprintf(stderr,
690 			    gettext("Can not set crl-none=true and other CRL "
691 			    "attributes at the same time.\n"));
692 			rv = KC_ERR_USAGE;
693 			goto out;
694 		}
695 
696 		/*
697 		 * If the original policy does not have CRL checking,
698 		 * then we do not need to do anything.  If the original
699 		 * policy has the CRL checking, then we need to release the
700 		 * space of CRL attributes and turn the CRL checking off.
701 		 */
702 		if (oplc.revocation & KMF_REVOCATION_METHOD_CRL) {
703 			if (oplc.VAL_CRL_BASEFILENAME) {
704 				free(oplc.VAL_CRL_BASEFILENAME);
705 				oplc.VAL_CRL_BASEFILENAME = NULL;
706 			}
707 
708 			if (oplc.VAL_CRL_DIRECTORY) {
709 				free(oplc.VAL_CRL_DIRECTORY);
710 				oplc.VAL_CRL_DIRECTORY = NULL;
711 			}
712 
713 			if (oplc.VAL_CRL_PROXY) {
714 				free(oplc.VAL_CRL_PROXY);
715 				oplc.VAL_CRL_PROXY = NULL;
716 			}
717 
718 			/* Turn off the CRL checking */
719 			oplc.revocation &= ~KMF_REVOCATION_METHOD_CRL;
720 		}
721 	} else {
722 		/*
723 		 * If the "ocsp-none" option is not set or is set to false,
724 		 * then we only need to do the modification if there is at
725 		 * least one CRL attribute is specified.
726 		 */
727 		if (crl_set_attr > 0) {
728 			if (flags & KC_CRL_BASEFILENAME) {
729 				if (oplc.VAL_CRL_BASEFILENAME)
730 					free(oplc.VAL_CRL_BASEFILENAME);
731 				oplc.VAL_CRL_BASEFILENAME =
732 				    plc.VAL_CRL_BASEFILENAME;
733 			}
734 
735 			if (flags & KC_CRL_DIRECTORY) {
736 				if (oplc.VAL_CRL_DIRECTORY)
737 					free(oplc.VAL_CRL_DIRECTORY);
738 				oplc.VAL_CRL_DIRECTORY = plc.VAL_CRL_DIRECTORY;
739 			}
740 
741 			if (flags & KC_CRL_GET_URI) {
742 				oplc.VAL_CRL_GET_URI = plc.VAL_CRL_GET_URI;
743 			}
744 
745 			if (flags & KC_CRL_PROXY) {
746 				if (oplc.VAL_CRL_PROXY)
747 					free(oplc.VAL_CRL_PROXY);
748 				oplc.VAL_CRL_PROXY = plc.VAL_CRL_PROXY;
749 			}
750 
751 			if (flags & KC_CRL_IGNORE_SIGN) {
752 				oplc.VAL_CRL_IGNORE_SIGN =
753 				    plc.VAL_CRL_IGNORE_SIGN;
754 			}
755 
756 			if (flags & KC_CRL_IGNORE_DATE) {
757 				oplc.VAL_CRL_IGNORE_DATE =
758 				    plc.VAL_CRL_IGNORE_DATE;
759 			}
760 
761 			/* Turn on the CRL checking */
762 			oplc.revocation |= KMF_REVOCATION_METHOD_CRL;
763 		}
764 	}
765 
766 	/* Update the Key Usage */
767 	if (ku_none_opt == B_TRUE) {
768 		if (flags & KC_KEYUSAGE) {
769 			(void) fprintf(stderr,
770 			    gettext("Can not set keyusage-none=true and "
771 			    "modify the keyusage value at the same time.\n"));
772 			rv = KC_ERR_USAGE;
773 			goto out;
774 		}
775 
776 		oplc.ku_bits = 0;
777 	} else {
778 		/*
779 		 * If the "keyusage-none" option is not set or is set to
780 		 * false, then we only need to do the modification if
781 		 * the keyusage value is specified.
782 		 */
783 		if (flags & KC_KEYUSAGE)
784 			oplc.ku_bits = plc.ku_bits;
785 	}
786 
787 
788 	/* Update the Extended Key Usage */
789 	if (eku_none_opt == B_TRUE) {
790 		if (flags & KC_EKUS) {
791 			(void) fprintf(stderr,
792 			    gettext("Can not set eku-none=true and modify "
793 			    "EKU values at the same time.\n"));
794 			rv = KC_ERR_USAGE;
795 			goto out;
796 		}
797 
798 		/* Release current EKU list (if any) */
799 		if (oplc.eku_set.eku_count > 0) {
800 			kmf_free_eku_policy(&oplc.eku_set);
801 			oplc.eku_set.eku_count = 0;
802 			oplc.eku_set.ekulist = NULL;
803 		}
804 	} else {
805 		/*
806 		 * If the "eku-none" option is not set or is set to false,
807 		 * then we only need to do the modification if either
808 		 * "ekuname" or "ekuoids" is specified.
809 		 */
810 		if (flags & KC_EKUS) {
811 			/* Release current EKU list (if any) */
812 			kmf_free_eku_policy(&oplc.eku_set);
813 			oplc.eku_set = plc.eku_set;
814 		}
815 	}
816 
817 	/* Do a sanity check on the modified policy */
818 	ret = kmf_verify_policy(&oplc);
819 	if (ret != KMF_OK) {
820 		print_sanity_error(ret);
821 		rv = KC_ERR_VERIFY_POLICY;
822 		goto out;
823 	}
824 
825 	/* The modify operation is a delete followed by an add */
826 	ret = kmf_delete_policy_from_db(oplc.name, filename);
827 	if (ret != KMF_OK) {
828 		rv = KC_ERR_DELETE_POLICY;
829 		goto out;
830 	}
831 
832 	/*
833 	 * Now add the modified policy back to the DB.
834 	 */
835 	ret = kmf_add_policy_to_db(&oplc, filename, B_FALSE);
836 	if (ret != KMF_OK) {
837 		(void) fprintf(stderr,
838 		    gettext("Error adding policy to database: 0x%04x\n"), ret);
839 		rv = KC_ERR_ADD_POLICY;
840 		goto out;
841 	}
842 
843 out:
844 	if (filename != NULL)
845 		free(filename);
846 
847 	kmf_free_policy_record(&oplc);
848 
849 	return (rv);
850 }
851 
852 
853 static int
854 kc_modify_plugin(int argc, char *argv[])
855 {
856 	int 		rv = KC_OK;
857 	int		opt;
858 	extern int	optind_av;
859 	extern char	*optarg_av;
860 	char 		*keystore_name = NULL;
861 	char		*option = NULL;
862 	boolean_t	modify_plugin = B_FALSE;
863 	boolean_t 	has_option_arg = B_FALSE;
864 	conf_entry_t	*entry = NULL;
865 	FILE		*pfile = NULL;
866 	FILE		*pfile_tmp = NULL;
867 	char		tmpfile_name[MAXPATHLEN];
868 	char 		buffer[MAXPATHLEN];
869 	char 		buffer2[MAXPATHLEN];
870 
871 	while ((opt = getopt_av(argc, argv, "p(plugin)k:(keystore)o:(option)"))
872 	    != EOF) {
873 		switch (opt) {
874 		case 'p':
875 			if (modify_plugin) {
876 				(void) fprintf(stderr,
877 				    gettext("duplicate plugin input.\n"));
878 				rv = KC_ERR_USAGE;
879 			} else {
880 				modify_plugin = B_TRUE;
881 			}
882 			break;
883 		case 'k':
884 			if (keystore_name != NULL)
885 				rv = KC_ERR_USAGE;
886 			else {
887 				keystore_name = get_string(optarg_av, &rv);
888 				if (keystore_name == NULL) {
889 					(void) fprintf(stderr, gettext(
890 					    "Error keystore input.\n"));
891 					rv = KC_ERR_USAGE;
892 				}
893 			}
894 			break;
895 		case 'o':
896 			if (has_option_arg) {
897 				(void) fprintf(stderr,
898 				    gettext("duplicate option input.\n"));
899 				rv = KC_ERR_USAGE;
900 			} else {
901 				has_option_arg = B_TRUE;
902 				option = get_string(optarg_av, NULL);
903 			}
904 			break;
905 		default:
906 			(void) fprintf(stderr,
907 			    gettext("Error input option.\n"));
908 			rv = KC_ERR_USAGE;
909 			break;
910 		}
911 
912 		if (rv != KC_OK)
913 			goto out;
914 	}
915 
916 	/* No additional args allowed. */
917 	argc -= optind_av;
918 	if (argc) {
919 		(void) fprintf(stderr,
920 		    gettext("Error input option\n"));
921 		rv = KC_ERR_USAGE;
922 		goto out;
923 	}
924 
925 	if (keystore_name == NULL || has_option_arg == B_FALSE) {
926 		(void) fprintf(stderr,
927 		    gettext("Error input option\n"));
928 		rv = KC_ERR_USAGE;
929 		goto out;
930 	}
931 
932 	if (strcasecmp(keystore_name, "nss") == 0 ||
933 	    strcasecmp(keystore_name, "pkcs11") == 0 ||
934 	    strcasecmp(keystore_name, "file") == 0) {
935 		(void) fprintf(stderr,
936 		    gettext("Can not modify the built-in keystore %s\n"),
937 		    keystore_name);
938 		rv = KC_ERR_USAGE;
939 		goto out;
940 	}
941 
942 	entry = get_keystore_entry(keystore_name);
943 	if (entry == NULL) {
944 		(void) fprintf(stderr, gettext("%s does not exist.\n"),
945 		    keystore_name);
946 		rv = KC_ERR_USAGE;
947 		goto out;
948 	}
949 
950 	if ((entry->option == NULL && option == NULL) ||
951 	    (entry->option != NULL && option != NULL &&
952 	    strcmp(entry->option, option) == 0)) {
953 		(void) fprintf(stderr, gettext("No change - "
954 		    "the new option is same as the old option.\n"));
955 		rv = KC_OK;
956 		goto out;
957 	}
958 
959 	if ((pfile = fopen(_PATH_KMF_CONF, "r+")) == NULL) {
960 		err = errno;
961 		(void) fprintf(stderr,
962 		    gettext("failed to update the configuration - %s\n"),
963 		    strerror(err));
964 		rv = KC_ERR_ACCESS;
965 		goto out;
966 	}
967 
968 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
969 		err = errno;
970 		(void) fprintf(stderr,
971 		    gettext("failed to lock the configuration - %s\n"),
972 		    strerror(err));
973 		rv = KC_ERR_MODIFY_PLUGIN;
974 		goto out;
975 	}
976 
977 	/*
978 	 * Create a temporary file in the /etc/crypto directory.
979 	 */
980 	(void) strlcpy(tmpfile_name, CONF_TEMPFILE, sizeof (tmpfile_name));
981 	if (mkstemp(tmpfile_name) == -1) {
982 		err = errno;
983 		(void) fprintf(stderr,
984 		    gettext("failed to create a temporary file - %s\n"),
985 		    strerror(err));
986 		rv = KC_ERR_MODIFY_PLUGIN;
987 		goto out;
988 	}
989 
990 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
991 		err = errno;
992 		(void) fprintf(stderr,
993 		    gettext("failed to open %s - %s\n"),
994 		    tmpfile_name, strerror(err));
995 		rv = KC_ERR_MODIFY_PLUGIN;
996 		goto out;
997 	}
998 
999 	/*
1000 	 * Loop thru the config file and update the entry.
1001 	 */
1002 	while (fgets(buffer, MAXPATHLEN, pfile) != NULL) {
1003 		char *name;
1004 		int len;
1005 
1006 		if (buffer[0] == '#') {
1007 			if (fputs(buffer, pfile_tmp) == EOF) {
1008 				rv = KC_ERR_MODIFY_PLUGIN;
1009 				goto out;
1010 			} else {
1011 				continue;
1012 			}
1013 		}
1014 
1015 		/*
1016 		 * make a copy of the original buffer to buffer2.  Also get
1017 		 * rid of the trailing '\n' from buffer2.
1018 		 */
1019 		(void) strlcpy(buffer2, buffer, MAXPATHLEN);
1020 		len = strlen(buffer2);
1021 		if (buffer2[len-1] == '\n') {
1022 			len--;
1023 		}
1024 		buffer2[len] = '\0';
1025 
1026 		if ((name = strtok(buffer2, SEP_COLON)) == NULL) {
1027 			rv = KC_ERR_UNINSTALL;
1028 			goto out;
1029 		}
1030 
1031 		if (strcmp(name, keystore_name) == 0) {
1032 			/* found the entry */
1033 			if (option == NULL)
1034 				(void) snprintf(buffer, MAXPATHLEN,
1035 				    "%s:%s%s\n", keystore_name,
1036 				    CONF_MODULEPATH, entry->modulepath);
1037 			else
1038 				(void) snprintf(buffer, MAXPATHLEN,
1039 				    "%s:%s%s;%s%s\n", keystore_name,
1040 				    CONF_MODULEPATH, entry->modulepath,
1041 				    CONF_OPTION, option);
1042 
1043 			if (fputs(buffer, pfile_tmp) == EOF) {
1044 				err = errno;
1045 				(void) fprintf(stderr, gettext(
1046 				    "failed to write to %s: %s\n"),
1047 				    tmpfile_name, strerror(err));
1048 				rv = KC_ERR_MODIFY_PLUGIN;
1049 				goto out;
1050 			}
1051 		} else {
1052 
1053 			if (fputs(buffer, pfile_tmp) == EOF) {
1054 				rv = KC_ERR_UNINSTALL;
1055 				goto out;
1056 			}
1057 		}
1058 	}
1059 
1060 	if (rename(tmpfile_name, _PATH_KMF_CONF) == -1) {
1061 		err = errno;
1062 		(void) fprintf(stderr, gettext(
1063 		    "failed to update the configuration - %s"), strerror(err));
1064 		rv = KC_ERR_MODIFY_PLUGIN;
1065 		goto out;
1066 	}
1067 
1068 	if (chmod(_PATH_KMF_CONF,
1069 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1070 		err = errno;
1071 		(void) fprintf(stderr, gettext(
1072 		    "failed to update the configuration - %s\n"),
1073 		    strerror(err));
1074 		rv = KC_ERR_MODIFY_PLUGIN;
1075 		goto out;
1076 	}
1077 
1078 out:
1079 	if (entry != NULL)
1080 		free_entry(entry);
1081 
1082 	if (pfile != NULL)
1083 		(void) fclose(pfile);
1084 
1085 	if (rv != KC_OK && pfile_tmp != NULL)
1086 		(void) unlink(tmpfile_name);
1087 
1088 	if (pfile_tmp != NULL)
1089 		(void) fclose(pfile_tmp);
1090 
1091 	return (rv);
1092 }
1093 
1094 
1095 int
1096 kc_modify(int argc, char *argv[])
1097 {
1098 	if (argc > 2 &&
1099 	    strcmp(argv[0], "modify") == 0 &&
1100 	    strcmp(argv[1], "plugin") == 0) {
1101 		return (kc_modify_plugin(argc, argv));
1102 	} else {
1103 		return (kc_modify_policy(argc, argv));
1104 	}
1105 }
1106