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