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
33 #include <libxml/tree.h>
34 #include <libxml/parser.h>
35
36 #include <kmfapiP.h>
37 #include "util.h"
38
39
40 /* Supporting structures and global variables for getopt_av(). */
41 typedef struct av_opts_s {
42 int shortnm; /* short name character */
43 char *longnm; /* long name string, NOT terminated */
44 int longnm_len; /* length of long name string */
45 boolean_t has_arg; /* takes optional argument */
46 } av_opts;
47
48 static av_opts *opts_av = NULL;
49 static const char *_save_optstr = NULL;
50 static int _save_numopts = 0;
51 int optind_av = 1;
52 char *optarg_av = NULL;
53
54 void
free_policy_list(POLICY_LIST * plist)55 free_policy_list(POLICY_LIST *plist)
56 {
57 POLICY_LIST *n = plist, *old;
58
59 if (plist == NULL)
60 return;
61
62 while (n != NULL) {
63 old = n;
64 kmf_free_policy_record(&n->plc);
65 n = n->next;
66 free(old);
67 }
68 plist = NULL;
69 }
70
71 int
load_policies(char * file,POLICY_LIST ** policy_list)72 load_policies(char *file, POLICY_LIST **policy_list)
73 {
74 int rv = KC_OK;
75 KMF_RETURN kmfrv = KMF_OK;
76 POLICY_LIST *newitem, *plist = NULL;
77 xmlParserCtxtPtr ctxt;
78 xmlDocPtr doc = NULL;
79 xmlNodePtr cur, node;
80
81 /* Create a parser context */
82 ctxt = xmlNewParserCtxt();
83 if (ctxt == NULL)
84 return (KMF_ERR_POLICY_DB_FORMAT);
85
86 /* Read the policy DB and verify it against the schema. */
87 doc = xmlCtxtReadFile(ctxt, file, NULL,
88 XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
89 if (doc == NULL || ctxt->valid == 0) {
90 kmfrv = KMF_ERR_POLICY_DB_FORMAT;
91 goto end;
92 }
93
94 cur = xmlDocGetRootElement(doc);
95 if (cur == NULL) {
96 kmfrv = KMF_ERR_POLICY_DB_FORMAT;
97 goto end;
98 }
99
100 node = cur->xmlChildrenNode;
101 while (node != NULL) {
102 char *c;
103 /*
104 * Search for the policy that matches the given name.
105 */
106 if (!xmlStrcmp((const xmlChar *)node->name,
107 (const xmlChar *)KMF_POLICY_ELEMENT)) {
108 /* Check the name attribute */
109 c = (char *)xmlGetProp(node,
110 (const xmlChar *)KMF_POLICY_NAME_ATTR);
111
112 /* If a match, parse the rest of the data */
113 if (c != NULL) {
114 xmlFree(c);
115 newitem = malloc(sizeof (POLICY_LIST));
116 if (newitem != NULL) {
117 (void) memset(newitem, 0,
118 sizeof (POLICY_LIST));
119 kmfrv = parsePolicyElement(node,
120 &newitem->plc);
121 } else {
122 kmfrv = KMF_ERR_MEMORY;
123 goto end;
124 }
125 /* add to linked list */
126 if (plist == NULL) {
127 plist = newitem;
128 } else {
129 POLICY_LIST *n = plist;
130 while (n->next != NULL)
131 n = n->next;
132
133 n->next = newitem;
134 newitem->next = NULL;
135 }
136 }
137 }
138 node = node->next;
139 }
140
141 end:
142 if (ctxt != NULL)
143 xmlFreeParserCtxt(ctxt);
144
145 if (doc != NULL)
146 xmlFreeDoc(doc);
147
148 if (kmfrv != KMF_OK) {
149 free_policy_list(plist);
150 rv = KC_ERR_LOADDB;
151 } else {
152 *policy_list = plist;
153 }
154
155 return (rv);
156 }
157
158 /*
159 * Return 0 if there is any error in the input string.
160 */
161 uint16_t
parseKUlist(char * kustring)162 parseKUlist(char *kustring)
163 {
164 uint16_t cur_bit;
165 uint16_t kubits = 0;
166 char *p;
167
168 p = strtok(kustring, ",");
169 while (p != NULL) {
170 cur_bit = kmf_string_to_ku(p);
171 if (cur_bit == 0) {
172 kubits = 0;
173 break;
174 }
175 kubits |= cur_bit;
176 p = strtok(NULL, ",");
177 }
178
179 return (kubits);
180 }
181
182 static void
addToEKUList(KMF_EKU_POLICY * ekus,KMF_OID * newoid)183 addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid)
184 {
185 if (newoid != NULL && ekus != NULL) {
186 ekus->eku_count++;
187 ekus->ekulist = realloc(
188 ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
189 if (ekus->ekulist != NULL) {
190 ekus->ekulist[ekus->eku_count-1] = *newoid;
191 }
192 }
193 }
194
195 int
parseEKUNames(char * ekulist,KMF_POLICY_RECORD * plc)196 parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc)
197 {
198 int rv = KC_OK;
199 char *p;
200 KMF_OID *newoid;
201 KMF_EKU_POLICY *ekus = &plc->eku_set;
202
203 if (ekulist == NULL || !strlen(ekulist))
204 return (0);
205
206 /*
207 * The list should be comma separated list of EKU Names.
208 */
209 p = strtok(ekulist, ",");
210
211 /* If no tokens found, then maybe its just a single EKU value */
212 if (p == NULL) {
213 newoid = kmf_ekuname_to_oid(ekulist);
214 if (newoid != NULL) {
215 addToEKUList(ekus, newoid);
216 free(newoid);
217 } else {
218 rv = KC_ERR_USAGE;
219 }
220 }
221
222 while (p != NULL) {
223 newoid = kmf_ekuname_to_oid(p);
224 if (newoid != NULL) {
225 addToEKUList(ekus, newoid);
226 free(newoid);
227 } else {
228 rv = KC_ERR_USAGE;
229 break;
230 }
231 p = strtok(NULL, ",");
232 }
233
234 if (rv != KC_OK)
235 kmf_free_eku_policy(ekus);
236
237 return (rv);
238 }
239
240 int
parseEKUOIDs(char * ekulist,KMF_POLICY_RECORD * plc)241 parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc)
242 {
243 int rv = KC_OK;
244 char *p;
245 KMF_OID newoid = {NULL, 0};
246 KMF_EKU_POLICY *ekus = &plc->eku_set;
247
248 if (ekulist == NULL || !strlen(ekulist))
249 return (0);
250
251 /*
252 * The list should be comma separated list of EKU Names.
253 */
254 p = strtok(ekulist, ",");
255 if (p == NULL) {
256 if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) {
257 addToEKUList(ekus, &newoid);
258 } else {
259 rv = KC_ERR_USAGE;
260 }
261 }
262
263 while (p != NULL && rv == 0) {
264 if (kmf_string_to_oid(p, &newoid) == KMF_OK) {
265 addToEKUList(ekus, &newoid);
266 } else {
267 rv = KC_ERR_USAGE;
268 break;
269 }
270 p = strtok(NULL, ",");
271 }
272
273 if (rv != KC_OK)
274 kmf_free_eku_policy(ekus);
275
276 return (rv);
277 }
278
279 int
get_boolean(char * arg)280 get_boolean(char *arg)
281 {
282 if (arg == NULL)
283 return (-1);
284 if (strcasecmp(arg, "true") == 0)
285 return (1);
286 if (strcasecmp(arg, "false") == 0)
287 return (0);
288 return (-1);
289 }
290
291 /*
292 * This function processes the input string. It removes the beginning
293 * and ending blank's first, makes a copy of the resulting string and
294 * return it.
295 *
296 * This function returns NULL, if there is an error in the
297 * input string or when the system is out of memory. The output
298 * "err_flag" argument will record the error code, if it is not NULL.
299 */
300 char *
get_string(char * str,int * err_flag)301 get_string(char *str, int *err_flag)
302 {
303 char *p;
304 int len, i;
305 char *retstr = NULL;
306
307 if (str == NULL) {
308 if (err_flag != NULL)
309 *err_flag = KC_ERR_USAGE;
310 return (NULL);
311 }
312
313 /* Remove beginning whitespace */
314 p = str;
315 while (p != NULL && isspace(*p))
316 p++;
317
318 if (p == NULL) {
319 if (err_flag != NULL)
320 *err_flag = KC_ERR_USAGE;
321 return (NULL);
322 }
323
324 /* Remove the trailing blanks */
325 len = strlen(p);
326 while (len > 0 && isspace(p[len-1]))
327 len--;
328
329 if (len == 0) {
330 if (err_flag != NULL)
331 *err_flag = KC_ERR_USAGE;
332 return (NULL);
333 }
334
335 /* Check if there is any non-printable character */
336 i = 0;
337 while (i < len) {
338 if (isprint(p[i]))
339 i++;
340 else {
341 if (err_flag != NULL)
342 *err_flag = KC_ERR_USAGE;
343 return (NULL);
344 }
345 }
346
347 /* Make a copy of the string and return it */
348 retstr = malloc(len + 1);
349 if (retstr == NULL) {
350 if (err_flag != NULL)
351 *err_flag = KC_ERR_MEMORY;
352 return (NULL);
353 }
354
355 if (err_flag != NULL)
356 *err_flag = KC_OK;
357
358 (void) strncpy(retstr, p, len);
359 retstr[len] = '\0';
360 return (retstr);
361 }
362
363 /*
364 * Breaks out the getopt-style option string into a structure that can be
365 * traversed later for calls to getopt_av(). Option string is NOT altered,
366 * but the struct fields point to locations within option string.
367 */
368 static int
populate_opts(char * optstring)369 populate_opts(char *optstring)
370 {
371 int i;
372 av_opts *temp;
373 char *marker;
374
375 if (optstring == NULL || *optstring == '\0')
376 return (0);
377
378 /*
379 * This tries to imitate getopt(3c) Each option must conform to:
380 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
381 * If long name is missing, the short name is used for long name.
382 */
383 for (i = 0; *optstring != '\0'; i++) {
384 if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
385 realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
386 free(opts_av);
387 opts_av = NULL;
388 return (0);
389 } else
390 opts_av = (av_opts *)temp;
391
392 marker = optstring; /* may need optstring later */
393
394 opts_av[i].shortnm = *marker++; /* set short name */
395
396 if (*marker == ':') { /* check for opt arg */
397 marker++;
398 opts_av[i].has_arg = B_TRUE;
399 }
400
401 if (*marker == '(') { /* check and set long name */
402 marker++;
403 opts_av[i].longnm = marker;
404 opts_av[i].longnm_len = strcspn(marker, ")");
405 optstring = marker + opts_av[i].longnm_len + 1;
406 } else {
407 /* use short name option character */
408 opts_av[i].longnm = optstring;
409 opts_av[i].longnm_len = 1;
410 optstring = marker;
411 }
412 }
413
414 return (i);
415 }
416
417 /*
418 * getopt_av() is very similar to getopt(3c) in that the takes an option
419 * string, compares command line arguments for matches, and returns a single
420 * letter option when a match is found. However, getopt_av() differs from
421 * getopt(3c) by allowing both longname options and values be found
422 * on the command line.
423 */
424 int
getopt_av(int argc,char * const * argv,const char * optstring)425 getopt_av(int argc, char * const *argv, const char *optstring)
426 {
427 int i;
428 int len;
429
430 if (optind_av >= argc)
431 return (EOF);
432
433 /* First time or when optstring changes from previous one */
434 if (_save_optstr != optstring) {
435 if (opts_av != NULL)
436 free(opts_av);
437 opts_av = NULL;
438 _save_optstr = optstring;
439 _save_numopts = populate_opts((char *)optstring);
440 }
441
442 for (i = 0; i < _save_numopts; i++) {
443 if (strcmp(argv[optind_av], "--") == 0) {
444 optind_av++;
445 break;
446 }
447
448 len = strcspn(argv[optind_av], "=");
449
450 if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
451 opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
452 /* matched */
453 if (!opts_av[i].has_arg) {
454 optind_av++;
455 return (opts_av[i].shortnm);
456 }
457
458 /* needs optarg */
459 if (argv[optind_av][len] == '=') {
460 optarg_av = &(argv[optind_av][len+1]);
461 optind_av++;
462 return (opts_av[i].shortnm);
463 }
464
465 optarg_av = NULL;
466 optind_av++;
467 return ((int)'?');
468 }
469 }
470
471 return (EOF);
472 }
473
474 void
print_sanity_error(KMF_RETURN ret)475 print_sanity_error(KMF_RETURN ret)
476 {
477 switch (ret) {
478 case KMF_ERR_POLICY_NAME:
479 (void) fprintf(stderr, gettext("Error in the policy name\n"));
480 break;
481 case KMF_ERR_TA_POLICY:
482 (void) fprintf(stderr,
483 gettext("Error in trust anchor attributes\n"));
484 break;
485 case KMF_ERR_OCSP_POLICY:
486 (void) fprintf(stderr,
487 gettext("Error in OCSP policy attributes\n"));
488 break;
489 default:
490 break;
491 }
492 }
493
494
495 conf_entry_t *
get_keystore_entry(char * kstore_name)496 get_keystore_entry(char *kstore_name)
497 {
498 conf_entrylist_t *phead = NULL;
499 conf_entrylist_t *ptr;
500 conf_entry_t *rtn_entry = NULL;
501
502 if (kstore_name == NULL)
503 return (NULL);
504
505 if (get_entrylist(&phead) != KMF_OK)
506 return (NULL);
507
508 ptr = phead;
509 while (ptr != NULL) {
510 if (strcmp(ptr->entry->keystore, kstore_name) == 0)
511 break;
512 ptr = ptr->next;
513 }
514
515 if (ptr != NULL) /* found the entry */
516 rtn_entry = dup_entry(ptr->entry);
517
518 free_entrylist(phead);
519 return (rtn_entry);
520 }
521