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 *
215051Swyllys * 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>
37*5626Shylee #include "util.h"
383089Swyllys
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
free_policy_list(POLICY_LIST * plist)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;
645051Swyllys kmf_free_policy_record(&n->plc);
653089Swyllys n = n->next;
663089Swyllys free(old);
673089Swyllys }
683089Swyllys plist = NULL;
693089Swyllys }
703089Swyllys
713089Swyllys int
load_policies(char * file,POLICY_LIST ** policy_list)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,
1075051Swyllys (const xmlChar *)KMF_POLICY_ELEMENT)) {
1083089Swyllys /* Check the name attribute */
1093089Swyllys c = (char *)xmlGetProp(node,
1105051Swyllys (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,
1185051Swyllys sizeof (POLICY_LIST));
1193089Swyllys kmfrv = parsePolicyElement(node,
1205051Swyllys &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
parseKUlist(char * kustring)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) {
1705051Swyllys 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
addToEKUList(KMF_EKU_POLICY * ekus,KMF_OID * newoid)1833089Swyllys addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid)
1843089Swyllys {
1853089Swyllys if (newoid != NULL && ekus != NULL) {
1863089Swyllys ekus->eku_count++;
1873089Swyllys ekus->ekulist = realloc(
1885051Swyllys 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
parseEKUNames(char * ekulist,KMF_POLICY_RECORD * plc)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) {
2135051Swyllys 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) {
2235051Swyllys 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)
2355051Swyllys kmf_free_eku_policy(ekus);
2363089Swyllys
2373089Swyllys return (rv);
2383089Swyllys }
2393089Swyllys
2403089Swyllys int
parseEKUOIDs(char * ekulist,KMF_POLICY_RECORD * plc)2413089Swyllys parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc)
2423089Swyllys {
2433089Swyllys int rv = KC_OK;
2443089Swyllys char *p;
2455051Swyllys 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) {
2565051Swyllys if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) {
2575051Swyllys addToEKUList(ekus, &newoid);
2583089Swyllys } else {
2593089Swyllys rv = KC_ERR_USAGE;
2603089Swyllys }
2613089Swyllys }
2623089Swyllys
2633089Swyllys while (p != NULL && rv == 0) {
2645051Swyllys if (kmf_string_to_oid(p, &newoid) == KMF_OK) {
2655051Swyllys addToEKUList(ekus, &newoid);
2663089Swyllys } else {
2673089Swyllys rv = KC_ERR_USAGE;
2683089Swyllys break;
2693089Swyllys }
2703089Swyllys p = strtok(NULL, ",");
2713089Swyllys }
2723089Swyllys
2733089Swyllys if (rv != KC_OK)
2745051Swyllys kmf_free_eku_policy(ekus);
2753089Swyllys
2763089Swyllys return (rv);
2773089Swyllys }
2783089Swyllys
2793089Swyllys int
get_boolean(char * arg)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 *
get_string(char * str,int * err_flag)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
populate_opts(char * optstring)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
getopt_av(int argc,char * const * argv,const char * optstring)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)
4365051Swyllys 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
print_sanity_error(KMF_RETURN ret)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*5626Shylee
494*5626Shylee
495*5626Shylee conf_entry_t *
get_keystore_entry(char * kstore_name)496*5626Shylee get_keystore_entry(char *kstore_name)
497*5626Shylee {
498*5626Shylee conf_entrylist_t *phead = NULL;
499*5626Shylee conf_entrylist_t *ptr;
500*5626Shylee conf_entry_t *rtn_entry = NULL;
501*5626Shylee
502*5626Shylee if (kstore_name == NULL)
503*5626Shylee return (NULL);
504*5626Shylee
505*5626Shylee if (get_entrylist(&phead) != KMF_OK)
506*5626Shylee return (NULL);
507*5626Shylee
508*5626Shylee ptr = phead;
509*5626Shylee while (ptr != NULL) {
510*5626Shylee if (strcmp(ptr->entry->keystore, kstore_name) == 0)
511*5626Shylee break;
512*5626Shylee ptr = ptr->next;
513*5626Shylee }
514*5626Shylee
515*5626Shylee if (ptr != NULL) /* found the entry */
516*5626Shylee rtn_entry = dup_entry(ptr->entry);
517*5626Shylee
518*5626Shylee free_entrylist(phead);
519*5626Shylee return (rtn_entry);
520*5626Shylee }
521