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 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 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 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 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 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 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 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 * 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 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 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 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 * 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