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