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