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 2006 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 38 #include "util.h" 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 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_FreePolicyRecord(&n->plc); 65 n = n->next; 66 free(old); 67 } 68 plist = NULL; 69 } 70 71 int 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 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_StringToKeyUsage(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 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, 189 ekus->eku_count * sizeof (KMF_OID)); 190 if (ekus->ekulist != NULL) { 191 ekus->ekulist[ekus->eku_count-1] = *newoid; 192 } 193 } 194 } 195 196 int 197 parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc) 198 { 199 int rv = KC_OK; 200 char *p; 201 KMF_OID *newoid; 202 KMF_EKU_POLICY *ekus = &plc->eku_set; 203 204 if (ekulist == NULL || !strlen(ekulist)) 205 return (0); 206 207 /* 208 * The list should be comma separated list of EKU Names. 209 */ 210 p = strtok(ekulist, ","); 211 212 /* If no tokens found, then maybe its just a single EKU value */ 213 if (p == NULL) { 214 newoid = kmf_ekuname2oid(ekulist); 215 if (newoid != NULL) { 216 addToEKUList(ekus, newoid); 217 free(newoid); 218 } else { 219 rv = KC_ERR_USAGE; 220 } 221 } 222 223 while (p != NULL) { 224 newoid = kmf_ekuname2oid(p); 225 if (newoid != NULL) { 226 addToEKUList(ekus, newoid); 227 free(newoid); 228 } else { 229 rv = KC_ERR_USAGE; 230 break; 231 } 232 p = strtok(NULL, ","); 233 } 234 235 if (rv != KC_OK) 236 KMF_FreeEKUPolicy(ekus); 237 238 return (rv); 239 } 240 241 int 242 parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) 243 { 244 int rv = KC_OK; 245 char *p; 246 KMF_OID *newoid; 247 KMF_EKU_POLICY *ekus = &plc->eku_set; 248 249 if (ekulist == NULL || !strlen(ekulist)) 250 return (0); 251 252 /* 253 * The list should be comma separated list of EKU Names. 254 */ 255 p = strtok(ekulist, ","); 256 if (p == NULL) { 257 newoid = kmf_string2oid(ekulist); 258 if (newoid != NULL) { 259 addToEKUList(ekus, newoid); 260 free(newoid); 261 } else { 262 rv = KC_ERR_USAGE; 263 } 264 } 265 266 while (p != NULL && rv == 0) { 267 newoid = kmf_string2oid(p); 268 if (newoid != NULL) { 269 addToEKUList(ekus, newoid); 270 free(newoid); 271 } else { 272 rv = KC_ERR_USAGE; 273 break; 274 } 275 p = strtok(NULL, ","); 276 } 277 278 if (rv != KC_OK) 279 KMF_FreeEKUPolicy(ekus); 280 281 return (rv); 282 } 283 284 int 285 get_boolean(char *arg) 286 { 287 if (arg == NULL) 288 return (-1); 289 if (strcasecmp(arg, "true") == 0) 290 return (1); 291 if (strcasecmp(arg, "false") == 0) 292 return (0); 293 return (-1); 294 } 295 296 /* 297 * This function processes the input string. It removes the beginning 298 * and ending blank's first, makes a copy of the resulting string and 299 * return it. 300 * 301 * This function returns NULL, if there is an error in the 302 * input string or when the system is out of memory. The output 303 * "err_flag" argument will record the error code, if it is not NULL. 304 */ 305 char * 306 get_string(char *str, int *err_flag) 307 { 308 char *p; 309 int len, i; 310 char *retstr = NULL; 311 312 if (str == NULL) { 313 if (err_flag != NULL) 314 *err_flag = KC_ERR_USAGE; 315 return (NULL); 316 } 317 318 /* Remove beginning whitespace */ 319 p = str; 320 while (p != NULL && isspace(*p)) 321 p++; 322 323 if (p == NULL) { 324 if (err_flag != NULL) 325 *err_flag = KC_ERR_USAGE; 326 return (NULL); 327 } 328 329 /* Remove the trailing blanks */ 330 len = strlen(p); 331 while (len > 0 && isspace(p[len-1])) 332 len--; 333 334 if (len == 0) { 335 if (err_flag != NULL) 336 *err_flag = KC_ERR_USAGE; 337 return (NULL); 338 } 339 340 /* Check if there is any non-printable character */ 341 i = 0; 342 while (i < len) { 343 if (isprint(p[i])) 344 i++; 345 else { 346 if (err_flag != NULL) 347 *err_flag = KC_ERR_USAGE; 348 return (NULL); 349 } 350 } 351 352 /* Make a copy of the string and return it */ 353 retstr = malloc(len + 1); 354 if (retstr == NULL) { 355 if (err_flag != NULL) 356 *err_flag = KC_ERR_MEMORY; 357 return (NULL); 358 } 359 360 if (err_flag != NULL) 361 *err_flag = KC_OK; 362 363 (void) strncpy(retstr, p, len); 364 retstr[len] = '\0'; 365 return (retstr); 366 } 367 368 /* 369 * Breaks out the getopt-style option string into a structure that can be 370 * traversed later for calls to getopt_av(). Option string is NOT altered, 371 * but the struct fields point to locations within option string. 372 */ 373 static int 374 populate_opts(char *optstring) 375 { 376 int i; 377 av_opts *temp; 378 char *marker; 379 380 if (optstring == NULL || *optstring == '\0') 381 return (0); 382 383 /* 384 * This tries to imitate getopt(3c) Each option must conform to: 385 * <short name char> [ ':' ] [ '(' <long name string> ')' ] 386 * If long name is missing, the short name is used for long name. 387 */ 388 for (i = 0; *optstring != '\0'; i++) { 389 if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 390 realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 391 free(opts_av); 392 opts_av = NULL; 393 return (0); 394 } else 395 opts_av = (av_opts *)temp; 396 397 marker = optstring; /* may need optstring later */ 398 399 opts_av[i].shortnm = *marker++; /* set short name */ 400 401 if (*marker == ':') { /* check for opt arg */ 402 marker++; 403 opts_av[i].has_arg = B_TRUE; 404 } 405 406 if (*marker == '(') { /* check and set long name */ 407 marker++; 408 opts_av[i].longnm = marker; 409 opts_av[i].longnm_len = strcspn(marker, ")"); 410 optstring = marker + opts_av[i].longnm_len + 1; 411 } else { 412 /* use short name option character */ 413 opts_av[i].longnm = optstring; 414 opts_av[i].longnm_len = 1; 415 optstring = marker; 416 } 417 } 418 419 return (i); 420 } 421 422 /* 423 * getopt_av() is very similar to getopt(3c) in that the takes an option 424 * string, compares command line arguments for matches, and returns a single 425 * letter option when a match is found. However, getopt_av() differs from 426 * getopt(3c) by allowing both longname options and values be found 427 * on the command line. 428 */ 429 int 430 getopt_av(int argc, char * const *argv, const char *optstring) 431 { 432 int i; 433 int len; 434 435 if (optind_av >= argc) 436 return (EOF); 437 438 /* First time or when optstring changes from previous one */ 439 if (_save_optstr != optstring) { 440 if (opts_av != NULL) 441 free(opts_av); 442 opts_av = NULL; 443 _save_optstr = optstring; 444 _save_numopts = populate_opts((char *)optstring); 445 } 446 447 for (i = 0; i < _save_numopts; i++) { 448 if (strcmp(argv[optind_av], "--") == 0) { 449 optind_av++; 450 break; 451 } 452 453 len = strcspn(argv[optind_av], "="); 454 455 if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], 456 opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 457 /* matched */ 458 if (!opts_av[i].has_arg) { 459 optind_av++; 460 return (opts_av[i].shortnm); 461 } 462 463 /* needs optarg */ 464 if (argv[optind_av][len] == '=') { 465 optarg_av = &(argv[optind_av][len+1]); 466 optind_av++; 467 return (opts_av[i].shortnm); 468 } 469 470 optarg_av = NULL; 471 optind_av++; 472 return ((int)'?'); 473 } 474 } 475 476 return (EOF); 477 } 478 479 void 480 print_sanity_error(KMF_RETURN ret) 481 { 482 switch (ret) { 483 case KMF_ERR_POLICY_NAME: 484 (void) fprintf(stderr, gettext("Error in the policy name\n")); 485 break; 486 case KMF_ERR_TA_POLICY: 487 (void) fprintf(stderr, 488 gettext("Error in trust anchor attributes\n")); 489 break; 490 case KMF_ERR_OCSP_POLICY: 491 (void) fprintf(stderr, 492 gettext("Error in OCSP policy attributes\n")); 493 break; 494 default: 495 break; 496 } 497 } 498