13089Swyllys /* 23089Swyllys * CDDL HEADER START 33089Swyllys * 43089Swyllys * The contents of this file are subject to the terms of the 53089Swyllys * Common Development and Distribution License (the "License"). 63089Swyllys * You may not use this file except in compliance with the License. 73089Swyllys * 83089Swyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93089Swyllys * or http://www.opensolaris.org/os/licensing. 103089Swyllys * See the License for the specific language governing permissions 113089Swyllys * and limitations under the License. 123089Swyllys * 133089Swyllys * When distributing Covered Code, include this CDDL HEADER in each 143089Swyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153089Swyllys * If applicable, add the following below this CDDL HEADER, with the 163089Swyllys * fields enclosed by brackets "[]" replaced with your own identifying 173089Swyllys * information: Portions Copyright [yyyy] [name of copyright owner] 183089Swyllys * 193089Swyllys * CDDL HEADER END 203089Swyllys * 21*5051Swyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 223089Swyllys * Use is subject to license terms. 233089Swyllys */ 243089Swyllys 253089Swyllys #pragma ident "%Z%%M% %I% %E% SMI" 263089Swyllys 273089Swyllys #include <stdio.h> 283089Swyllys #include <strings.h> 293089Swyllys #include <ctype.h> 303089Swyllys #include <libgen.h> 313089Swyllys #include <libintl.h> 323089Swyllys 333089Swyllys #include <libxml/tree.h> 343089Swyllys #include <libxml/parser.h> 353089Swyllys 363089Swyllys #include <kmfapiP.h> 373089Swyllys 383089Swyllys #include "util.h" 393089Swyllys 403089Swyllys /* Supporting structures and global variables for getopt_av(). */ 413089Swyllys typedef struct av_opts_s { 423089Swyllys int shortnm; /* short name character */ 433089Swyllys char *longnm; /* long name string, NOT terminated */ 443089Swyllys int longnm_len; /* length of long name string */ 453089Swyllys boolean_t has_arg; /* takes optional argument */ 463089Swyllys } av_opts; 473089Swyllys 483089Swyllys static av_opts *opts_av = NULL; 493089Swyllys static const char *_save_optstr = NULL; 503089Swyllys static int _save_numopts = 0; 513089Swyllys int optind_av = 1; 523089Swyllys char *optarg_av = NULL; 533089Swyllys 543089Swyllys void 553089Swyllys free_policy_list(POLICY_LIST *plist) 563089Swyllys { 573089Swyllys POLICY_LIST *n = plist, *old; 583089Swyllys 593089Swyllys if (plist == NULL) 603089Swyllys return; 613089Swyllys 623089Swyllys while (n != NULL) { 633089Swyllys old = n; 64*5051Swyllys kmf_free_policy_record(&n->plc); 653089Swyllys n = n->next; 663089Swyllys free(old); 673089Swyllys } 683089Swyllys plist = NULL; 693089Swyllys } 703089Swyllys 713089Swyllys int 723089Swyllys load_policies(char *file, POLICY_LIST **policy_list) 733089Swyllys { 743089Swyllys int rv = KC_OK; 753089Swyllys KMF_RETURN kmfrv = KMF_OK; 763089Swyllys POLICY_LIST *newitem, *plist = NULL; 773089Swyllys xmlParserCtxtPtr ctxt; 783089Swyllys xmlDocPtr doc = NULL; 793089Swyllys xmlNodePtr cur, node; 803089Swyllys 813089Swyllys /* Create a parser context */ 823089Swyllys ctxt = xmlNewParserCtxt(); 833089Swyllys if (ctxt == NULL) 843089Swyllys return (KMF_ERR_POLICY_DB_FORMAT); 853089Swyllys 863089Swyllys /* Read the policy DB and verify it against the schema. */ 873089Swyllys doc = xmlCtxtReadFile(ctxt, file, NULL, 883089Swyllys XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); 893089Swyllys if (doc == NULL || ctxt->valid == 0) { 903089Swyllys kmfrv = KMF_ERR_POLICY_DB_FORMAT; 913089Swyllys goto end; 923089Swyllys } 933089Swyllys 943089Swyllys cur = xmlDocGetRootElement(doc); 953089Swyllys if (cur == NULL) { 963089Swyllys kmfrv = KMF_ERR_POLICY_DB_FORMAT; 973089Swyllys goto end; 983089Swyllys } 993089Swyllys 1003089Swyllys node = cur->xmlChildrenNode; 1013089Swyllys while (node != NULL) { 1023089Swyllys char *c; 1033089Swyllys /* 1043089Swyllys * Search for the policy that matches the given name. 1053089Swyllys */ 1063089Swyllys if (!xmlStrcmp((const xmlChar *)node->name, 107*5051Swyllys (const xmlChar *)KMF_POLICY_ELEMENT)) { 1083089Swyllys /* Check the name attribute */ 1093089Swyllys c = (char *)xmlGetProp(node, 110*5051Swyllys (const xmlChar *)KMF_POLICY_NAME_ATTR); 1113089Swyllys 1123089Swyllys /* If a match, parse the rest of the data */ 1133089Swyllys if (c != NULL) { 1143089Swyllys xmlFree(c); 1153089Swyllys newitem = malloc(sizeof (POLICY_LIST)); 1163089Swyllys if (newitem != NULL) { 1173089Swyllys (void) memset(newitem, 0, 118*5051Swyllys sizeof (POLICY_LIST)); 1193089Swyllys kmfrv = parsePolicyElement(node, 120*5051Swyllys &newitem->plc); 1213089Swyllys } else { 1223089Swyllys kmfrv = KMF_ERR_MEMORY; 1233089Swyllys goto end; 1243089Swyllys } 1253089Swyllys /* add to linked list */ 1263089Swyllys if (plist == NULL) { 1273089Swyllys plist = newitem; 1283089Swyllys } else { 1293089Swyllys POLICY_LIST *n = plist; 1303089Swyllys while (n->next != NULL) 1313089Swyllys n = n->next; 1323089Swyllys 1333089Swyllys n->next = newitem; 1343089Swyllys newitem->next = NULL; 1353089Swyllys } 1363089Swyllys } 1373089Swyllys } 1383089Swyllys node = node->next; 1393089Swyllys } 1403089Swyllys 1413089Swyllys end: 1423089Swyllys if (ctxt != NULL) 1433089Swyllys xmlFreeParserCtxt(ctxt); 1443089Swyllys 1453089Swyllys if (doc != NULL) 1463089Swyllys xmlFreeDoc(doc); 1473089Swyllys 1483089Swyllys if (kmfrv != KMF_OK) { 1493089Swyllys free_policy_list(plist); 1503089Swyllys rv = KC_ERR_LOADDB; 1513089Swyllys } else { 1523089Swyllys *policy_list = plist; 1533089Swyllys } 1543089Swyllys 1553089Swyllys return (rv); 1563089Swyllys } 1573089Swyllys 1583089Swyllys /* 1593089Swyllys * Return 0 if there is any error in the input string. 1603089Swyllys */ 1613089Swyllys uint16_t 1623089Swyllys parseKUlist(char *kustring) 1633089Swyllys { 1643089Swyllys uint16_t cur_bit; 1653089Swyllys uint16_t kubits = 0; 1663089Swyllys char *p; 1673089Swyllys 1683089Swyllys p = strtok(kustring, ","); 1693089Swyllys while (p != NULL) { 170*5051Swyllys cur_bit = kmf_string_to_ku(p); 1713089Swyllys if (cur_bit == 0) { 1723089Swyllys kubits = 0; 1733089Swyllys break; 1743089Swyllys } 1753089Swyllys kubits |= cur_bit; 1763089Swyllys p = strtok(NULL, ","); 1773089Swyllys } 1783089Swyllys 1793089Swyllys return (kubits); 1803089Swyllys } 1813089Swyllys 1823089Swyllys static void 1833089Swyllys addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid) 1843089Swyllys { 1853089Swyllys if (newoid != NULL && ekus != NULL) { 1863089Swyllys ekus->eku_count++; 1873089Swyllys ekus->ekulist = realloc( 188*5051Swyllys ekus->ekulist, ekus->eku_count * sizeof (KMF_OID)); 1893089Swyllys if (ekus->ekulist != NULL) { 1903089Swyllys ekus->ekulist[ekus->eku_count-1] = *newoid; 1913089Swyllys } 1923089Swyllys } 1933089Swyllys } 1943089Swyllys 1953089Swyllys int 1963089Swyllys parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc) 1973089Swyllys { 1983089Swyllys int rv = KC_OK; 1993089Swyllys char *p; 2003089Swyllys KMF_OID *newoid; 2013089Swyllys KMF_EKU_POLICY *ekus = &plc->eku_set; 2023089Swyllys 2033089Swyllys if (ekulist == NULL || !strlen(ekulist)) 2043089Swyllys return (0); 2053089Swyllys 2063089Swyllys /* 2073089Swyllys * The list should be comma separated list of EKU Names. 2083089Swyllys */ 2093089Swyllys p = strtok(ekulist, ","); 2103089Swyllys 2113089Swyllys /* If no tokens found, then maybe its just a single EKU value */ 2123089Swyllys if (p == NULL) { 213*5051Swyllys newoid = kmf_ekuname_to_oid(ekulist); 2143089Swyllys if (newoid != NULL) { 2153089Swyllys addToEKUList(ekus, newoid); 2163089Swyllys free(newoid); 2173089Swyllys } else { 2183089Swyllys rv = KC_ERR_USAGE; 2193089Swyllys } 2203089Swyllys } 2213089Swyllys 2223089Swyllys while (p != NULL) { 223*5051Swyllys newoid = kmf_ekuname_to_oid(p); 2243089Swyllys if (newoid != NULL) { 2253089Swyllys addToEKUList(ekus, newoid); 2263089Swyllys free(newoid); 2273089Swyllys } else { 2283089Swyllys rv = KC_ERR_USAGE; 2293089Swyllys break; 2303089Swyllys } 2313089Swyllys p = strtok(NULL, ","); 2323089Swyllys } 2333089Swyllys 2343089Swyllys if (rv != KC_OK) 235*5051Swyllys kmf_free_eku_policy(ekus); 2363089Swyllys 2373089Swyllys return (rv); 2383089Swyllys } 2393089Swyllys 2403089Swyllys int 2413089Swyllys parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) 2423089Swyllys { 2433089Swyllys int rv = KC_OK; 2443089Swyllys char *p; 245*5051Swyllys KMF_OID newoid = {NULL, 0}; 2463089Swyllys KMF_EKU_POLICY *ekus = &plc->eku_set; 2473089Swyllys 2483089Swyllys if (ekulist == NULL || !strlen(ekulist)) 2493089Swyllys return (0); 2503089Swyllys 2513089Swyllys /* 2523089Swyllys * The list should be comma separated list of EKU Names. 2533089Swyllys */ 2543089Swyllys p = strtok(ekulist, ","); 2553089Swyllys if (p == NULL) { 256*5051Swyllys if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) { 257*5051Swyllys addToEKUList(ekus, &newoid); 2583089Swyllys } else { 2593089Swyllys rv = KC_ERR_USAGE; 2603089Swyllys } 2613089Swyllys } 2623089Swyllys 2633089Swyllys while (p != NULL && rv == 0) { 264*5051Swyllys if (kmf_string_to_oid(p, &newoid) == KMF_OK) { 265*5051Swyllys addToEKUList(ekus, &newoid); 2663089Swyllys } else { 2673089Swyllys rv = KC_ERR_USAGE; 2683089Swyllys break; 2693089Swyllys } 2703089Swyllys p = strtok(NULL, ","); 2713089Swyllys } 2723089Swyllys 2733089Swyllys if (rv != KC_OK) 274*5051Swyllys kmf_free_eku_policy(ekus); 2753089Swyllys 2763089Swyllys return (rv); 2773089Swyllys } 2783089Swyllys 2793089Swyllys int 2803089Swyllys get_boolean(char *arg) 2813089Swyllys { 2823089Swyllys if (arg == NULL) 2833089Swyllys return (-1); 2843089Swyllys if (strcasecmp(arg, "true") == 0) 2853089Swyllys return (1); 2863089Swyllys if (strcasecmp(arg, "false") == 0) 2873089Swyllys return (0); 2883089Swyllys return (-1); 2893089Swyllys } 2903089Swyllys 2913089Swyllys /* 2923089Swyllys * This function processes the input string. It removes the beginning 2933089Swyllys * and ending blank's first, makes a copy of the resulting string and 2943089Swyllys * return it. 2953089Swyllys * 2963089Swyllys * This function returns NULL, if there is an error in the 2973089Swyllys * input string or when the system is out of memory. The output 2983089Swyllys * "err_flag" argument will record the error code, if it is not NULL. 2993089Swyllys */ 3003089Swyllys char * 3013089Swyllys get_string(char *str, int *err_flag) 3023089Swyllys { 3033089Swyllys char *p; 3043089Swyllys int len, i; 3053089Swyllys char *retstr = NULL; 3063089Swyllys 3073089Swyllys if (str == NULL) { 3083089Swyllys if (err_flag != NULL) 3093089Swyllys *err_flag = KC_ERR_USAGE; 3103089Swyllys return (NULL); 3113089Swyllys } 3123089Swyllys 3133089Swyllys /* Remove beginning whitespace */ 3143089Swyllys p = str; 3153089Swyllys while (p != NULL && isspace(*p)) 3163089Swyllys p++; 3173089Swyllys 3183089Swyllys if (p == NULL) { 3193089Swyllys if (err_flag != NULL) 3203089Swyllys *err_flag = KC_ERR_USAGE; 3213089Swyllys return (NULL); 3223089Swyllys } 3233089Swyllys 3243089Swyllys /* Remove the trailing blanks */ 3253089Swyllys len = strlen(p); 3263089Swyllys while (len > 0 && isspace(p[len-1])) 3273089Swyllys len--; 3283089Swyllys 3293089Swyllys if (len == 0) { 3303089Swyllys if (err_flag != NULL) 3313089Swyllys *err_flag = KC_ERR_USAGE; 3323089Swyllys return (NULL); 3333089Swyllys } 3343089Swyllys 3353089Swyllys /* Check if there is any non-printable character */ 3363089Swyllys i = 0; 3373089Swyllys while (i < len) { 3383089Swyllys if (isprint(p[i])) 3393089Swyllys i++; 3403089Swyllys else { 3413089Swyllys if (err_flag != NULL) 3423089Swyllys *err_flag = KC_ERR_USAGE; 3433089Swyllys return (NULL); 3443089Swyllys } 3453089Swyllys } 3463089Swyllys 3473089Swyllys /* Make a copy of the string and return it */ 3483089Swyllys retstr = malloc(len + 1); 3493089Swyllys if (retstr == NULL) { 3503089Swyllys if (err_flag != NULL) 3513089Swyllys *err_flag = KC_ERR_MEMORY; 3523089Swyllys return (NULL); 3533089Swyllys } 3543089Swyllys 3553089Swyllys if (err_flag != NULL) 3563089Swyllys *err_flag = KC_OK; 3573089Swyllys 3583089Swyllys (void) strncpy(retstr, p, len); 3593089Swyllys retstr[len] = '\0'; 3603089Swyllys return (retstr); 3613089Swyllys } 3623089Swyllys 3633089Swyllys /* 3643089Swyllys * Breaks out the getopt-style option string into a structure that can be 3653089Swyllys * traversed later for calls to getopt_av(). Option string is NOT altered, 3663089Swyllys * but the struct fields point to locations within option string. 3673089Swyllys */ 3683089Swyllys static int 3693089Swyllys populate_opts(char *optstring) 3703089Swyllys { 3713089Swyllys int i; 3723089Swyllys av_opts *temp; 3733089Swyllys char *marker; 3743089Swyllys 3753089Swyllys if (optstring == NULL || *optstring == '\0') 3763089Swyllys return (0); 3773089Swyllys 3783089Swyllys /* 3793089Swyllys * This tries to imitate getopt(3c) Each option must conform to: 3803089Swyllys * <short name char> [ ':' ] [ '(' <long name string> ')' ] 3813089Swyllys * If long name is missing, the short name is used for long name. 3823089Swyllys */ 3833089Swyllys for (i = 0; *optstring != '\0'; i++) { 3843089Swyllys if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : 3853089Swyllys realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { 3863089Swyllys free(opts_av); 3873089Swyllys opts_av = NULL; 3883089Swyllys return (0); 3893089Swyllys } else 3903089Swyllys opts_av = (av_opts *)temp; 3913089Swyllys 3923089Swyllys marker = optstring; /* may need optstring later */ 3933089Swyllys 3943089Swyllys opts_av[i].shortnm = *marker++; /* set short name */ 3953089Swyllys 3963089Swyllys if (*marker == ':') { /* check for opt arg */ 3973089Swyllys marker++; 3983089Swyllys opts_av[i].has_arg = B_TRUE; 3993089Swyllys } 4003089Swyllys 4013089Swyllys if (*marker == '(') { /* check and set long name */ 4023089Swyllys marker++; 4033089Swyllys opts_av[i].longnm = marker; 4043089Swyllys opts_av[i].longnm_len = strcspn(marker, ")"); 4053089Swyllys optstring = marker + opts_av[i].longnm_len + 1; 4063089Swyllys } else { 4073089Swyllys /* use short name option character */ 4083089Swyllys opts_av[i].longnm = optstring; 4093089Swyllys opts_av[i].longnm_len = 1; 4103089Swyllys optstring = marker; 4113089Swyllys } 4123089Swyllys } 4133089Swyllys 4143089Swyllys return (i); 4153089Swyllys } 4163089Swyllys 4173089Swyllys /* 4183089Swyllys * getopt_av() is very similar to getopt(3c) in that the takes an option 4193089Swyllys * string, compares command line arguments for matches, and returns a single 4203089Swyllys * letter option when a match is found. However, getopt_av() differs from 4213089Swyllys * getopt(3c) by allowing both longname options and values be found 4223089Swyllys * on the command line. 4233089Swyllys */ 4243089Swyllys int 4253089Swyllys getopt_av(int argc, char * const *argv, const char *optstring) 4263089Swyllys { 4273089Swyllys int i; 4283089Swyllys int len; 4293089Swyllys 4303089Swyllys if (optind_av >= argc) 4313089Swyllys return (EOF); 4323089Swyllys 4333089Swyllys /* First time or when optstring changes from previous one */ 4343089Swyllys if (_save_optstr != optstring) { 4353089Swyllys if (opts_av != NULL) 436*5051Swyllys free(opts_av); 4373089Swyllys opts_av = NULL; 4383089Swyllys _save_optstr = optstring; 4393089Swyllys _save_numopts = populate_opts((char *)optstring); 4403089Swyllys } 4413089Swyllys 4423089Swyllys for (i = 0; i < _save_numopts; i++) { 4433089Swyllys if (strcmp(argv[optind_av], "--") == 0) { 4443089Swyllys optind_av++; 4453089Swyllys break; 4463089Swyllys } 4473089Swyllys 4483089Swyllys len = strcspn(argv[optind_av], "="); 4493089Swyllys 4503089Swyllys if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], 4513089Swyllys opts_av[i].longnm, opts_av[i].longnm_len) == 0) { 4523089Swyllys /* matched */ 4533089Swyllys if (!opts_av[i].has_arg) { 4543089Swyllys optind_av++; 4553089Swyllys return (opts_av[i].shortnm); 4563089Swyllys } 4573089Swyllys 4583089Swyllys /* needs optarg */ 4593089Swyllys if (argv[optind_av][len] == '=') { 4603089Swyllys optarg_av = &(argv[optind_av][len+1]); 4613089Swyllys optind_av++; 4623089Swyllys return (opts_av[i].shortnm); 4633089Swyllys } 4643089Swyllys 4653089Swyllys optarg_av = NULL; 4663089Swyllys optind_av++; 4673089Swyllys return ((int)'?'); 4683089Swyllys } 4693089Swyllys } 4703089Swyllys 4713089Swyllys return (EOF); 4723089Swyllys } 4733089Swyllys 4743089Swyllys void 4753089Swyllys print_sanity_error(KMF_RETURN ret) 4763089Swyllys { 4773089Swyllys switch (ret) { 4783089Swyllys case KMF_ERR_POLICY_NAME: 4793089Swyllys (void) fprintf(stderr, gettext("Error in the policy name\n")); 4803089Swyllys break; 4813089Swyllys case KMF_ERR_TA_POLICY: 4823089Swyllys (void) fprintf(stderr, 4833089Swyllys gettext("Error in trust anchor attributes\n")); 4843089Swyllys break; 4853089Swyllys case KMF_ERR_OCSP_POLICY: 4863089Swyllys (void) fprintf(stderr, 4873089Swyllys gettext("Error in OCSP policy attributes\n")); 4883089Swyllys break; 4893089Swyllys default: 4903089Swyllys break; 4913089Swyllys } 4923089Swyllys } 493