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