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 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_free_policy_record(&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_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 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 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 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 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 * 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 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 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 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