diff options
Diffstat (limited to 'usr/src/cmd/cmd-crypto/kmfcfg/util.c')
-rw-r--r-- | usr/src/cmd/cmd-crypto/kmfcfg/util.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/util.c b/usr/src/cmd/cmd-crypto/kmfcfg/util.c new file mode 100644 index 0000000000..f3bdc633f2 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/util.c @@ -0,0 +1,497 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <kmfapiP.h> + +#include "util.h" + +/* Supporting structures and global variables for getopt_av(). */ +typedef struct av_opts_s { + int shortnm; /* short name character */ + char *longnm; /* long name string, NOT terminated */ + int longnm_len; /* length of long name string */ + boolean_t has_arg; /* takes optional argument */ +} av_opts; + +static av_opts *opts_av = NULL; +static const char *_save_optstr = NULL; +static int _save_numopts = 0; +int optind_av = 1; +char *optarg_av = NULL; + +void +free_policy_list(POLICY_LIST *plist) +{ + POLICY_LIST *n = plist, *old; + + if (plist == NULL) + return; + + while (n != NULL) { + old = n; + KMF_FreePolicyRecord(&n->plc); + n = n->next; + free(old); + } + plist = NULL; +} + +int +load_policies(char *file, POLICY_LIST **policy_list) +{ + int rv = KC_OK; + KMF_RETURN kmfrv = KMF_OK; + POLICY_LIST *newitem, *plist = NULL; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc = NULL; + xmlNodePtr cur, node; + + /* Create a parser context */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return (KMF_ERR_POLICY_DB_FORMAT); + + /* Read the policy DB and verify it against the schema. */ + doc = xmlCtxtReadFile(ctxt, file, NULL, + XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (doc == NULL || ctxt->valid == 0) { + kmfrv = KMF_ERR_POLICY_DB_FORMAT; + goto end; + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + kmfrv = KMF_ERR_POLICY_DB_FORMAT; + goto end; + } + + node = cur->xmlChildrenNode; + while (node != NULL) { + char *c; + /* + * Search for the policy that matches the given name. + */ + if (!xmlStrcmp((const xmlChar *)node->name, + (const xmlChar *)KMF_POLICY_ELEMENT)) { + /* Check the name attribute */ + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_NAME_ATTR); + + /* If a match, parse the rest of the data */ + if (c != NULL) { + xmlFree(c); + newitem = malloc(sizeof (POLICY_LIST)); + if (newitem != NULL) { + (void) memset(newitem, 0, + sizeof (POLICY_LIST)); + kmfrv = parsePolicyElement(node, + &newitem->plc); + } else { + kmfrv = KMF_ERR_MEMORY; + goto end; + } + /* add to linked list */ + if (plist == NULL) { + plist = newitem; + } else { + POLICY_LIST *n = plist; + while (n->next != NULL) + n = n->next; + + n->next = newitem; + newitem->next = NULL; + } + } + } + node = node->next; + } + +end: + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + + if (doc != NULL) + xmlFreeDoc(doc); + + if (kmfrv != KMF_OK) { + free_policy_list(plist); + rv = KC_ERR_LOADDB; + } else { + *policy_list = plist; + } + + return (rv); +} + +/* + * Return 0 if there is any error in the input string. + */ +uint16_t +parseKUlist(char *kustring) +{ + uint16_t cur_bit; + uint16_t kubits = 0; + char *p; + + p = strtok(kustring, ","); + while (p != NULL) { + cur_bit = KMF_StringToKeyUsage(p); + if (cur_bit == 0) { + kubits = 0; + break; + } + kubits |= cur_bit; + p = strtok(NULL, ","); + } + + return (kubits); +} + +static void +addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid) +{ + if (newoid != NULL && ekus != NULL) { + ekus->eku_count++; + ekus->ekulist = realloc( + ekus->ekulist, + ekus->eku_count * sizeof (KMF_OID)); + if (ekus->ekulist != NULL) { + ekus->ekulist[ekus->eku_count-1] = *newoid; + } + } +} + +int +parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc) +{ + int rv = KC_OK; + char *p; + KMF_OID *newoid; + KMF_EKU_POLICY *ekus = &plc->eku_set; + + if (ekulist == NULL || !strlen(ekulist)) + return (0); + + /* + * The list should be comma separated list of EKU Names. + */ + p = strtok(ekulist, ","); + + /* If no tokens found, then maybe its just a single EKU value */ + if (p == NULL) { + newoid = kmf_ekuname2oid(ekulist); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + } + } + + while (p != NULL) { + newoid = kmf_ekuname2oid(p); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + break; + } + p = strtok(NULL, ","); + } + + if (rv != KC_OK) + KMF_FreeEKUPolicy(ekus); + + return (rv); +} + +int +parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) +{ + int rv = KC_OK; + char *p; + KMF_OID *newoid; + KMF_EKU_POLICY *ekus = &plc->eku_set; + + if (ekulist == NULL || !strlen(ekulist)) + return (0); + + /* + * The list should be comma separated list of EKU Names. + */ + p = strtok(ekulist, ","); + if (p == NULL) { + newoid = kmf_string2oid(ekulist); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + } + } + + while (p != NULL && rv == 0) { + newoid = kmf_string2oid(p); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + break; + } + p = strtok(NULL, ","); + } + + if (rv != KC_OK) + KMF_FreeEKUPolicy(ekus); + + return (rv); +} + +int +get_boolean(char *arg) +{ + if (arg == NULL) + return (-1); + if (strcasecmp(arg, "true") == 0) + return (1); + if (strcasecmp(arg, "false") == 0) + return (0); + return (-1); +} + +/* + * This function processes the input string. It removes the beginning + * and ending blank's first, makes a copy of the resulting string and + * return it. + * + * This function returns NULL, if there is an error in the + * input string or when the system is out of memory. The output + * "err_flag" argument will record the error code, if it is not NULL. + */ +char * +get_string(char *str, int *err_flag) +{ + char *p; + int len, i; + char *retstr = NULL; + + if (str == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Remove beginning whitespace */ + p = str; + while (p != NULL && isspace(*p)) + p++; + + if (p == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Remove the trailing blanks */ + len = strlen(p); + while (len > 0 && isspace(p[len-1])) + len--; + + if (len == 0) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Check if there is any non-printable character */ + i = 0; + while (i < len) { + if (isprint(p[i])) + i++; + else { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + } + + /* Make a copy of the string and return it */ + retstr = malloc(len + 1); + if (retstr == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_MEMORY; + return (NULL); + } + + if (err_flag != NULL) + *err_flag = KC_OK; + + (void) strncpy(retstr, p, len); + retstr[len] = '\0'; + return (retstr); +} + +/* + * Breaks out the getopt-style option string into a structure that can be + * traversed later for calls to getopt_av(). Option string is NOT altered, + * but the struct fields point to locations within option string. + */ +static int +populate_opts(char *optstring) +{ + int i; + av_opts *temp; + char *marker; + + if (optstring == NULL || *optstring == '\0') + return (0); + + /* + * This tries to imitate getopt(3c) Each option must conform to: + * <short name char> [ ':' ] [ '(' <long name string> ')' ] + * If long name is missing, the short name is used for long name. + */ + for (i = 0; *optstring != '\0'; i++) { + if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : + realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { + free(opts_av); + opts_av = NULL; + return (0); + } else + opts_av = (av_opts *)temp; + + marker = optstring; /* may need optstring later */ + + opts_av[i].shortnm = *marker++; /* set short name */ + + if (*marker == ':') { /* check for opt arg */ + marker++; + opts_av[i].has_arg = B_TRUE; + } + + if (*marker == '(') { /* check and set long name */ + marker++; + opts_av[i].longnm = marker; + opts_av[i].longnm_len = strcspn(marker, ")"); + optstring = marker + opts_av[i].longnm_len + 1; + } else { + /* use short name option character */ + opts_av[i].longnm = optstring; + opts_av[i].longnm_len = 1; + optstring = marker; + } + } + + return (i); +} + +/* + * getopt_av() is very similar to getopt(3c) in that the takes an option + * string, compares command line arguments for matches, and returns a single + * letter option when a match is found. However, getopt_av() differs from + * getopt(3c) by allowing both longname options and values be found + * on the command line. + */ +int +getopt_av(int argc, char * const *argv, const char *optstring) +{ + int i; + int len; + + if (optind_av >= argc) + return (EOF); + + /* First time or when optstring changes from previous one */ + if (_save_optstr != optstring) { + if (opts_av != NULL) + free(opts_av); + opts_av = NULL; + _save_optstr = optstring; + _save_numopts = populate_opts((char *)optstring); + } + + for (i = 0; i < _save_numopts; i++) { + if (strcmp(argv[optind_av], "--") == 0) { + optind_av++; + break; + } + + len = strcspn(argv[optind_av], "="); + + if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], + opts_av[i].longnm, opts_av[i].longnm_len) == 0) { + /* matched */ + if (!opts_av[i].has_arg) { + optind_av++; + return (opts_av[i].shortnm); + } + + /* needs optarg */ + if (argv[optind_av][len] == '=') { + optarg_av = &(argv[optind_av][len+1]); + optind_av++; + return (opts_av[i].shortnm); + } + + optarg_av = NULL; + optind_av++; + return ((int)'?'); + } + } + + return (EOF); +} + +void +print_sanity_error(KMF_RETURN ret) +{ + switch (ret) { + case KMF_ERR_POLICY_NAME: + (void) fprintf(stderr, gettext("Error in the policy name\n")); + break; + case KMF_ERR_TA_POLICY: + (void) fprintf(stderr, + gettext("Error in trust anchor attributes\n")); + break; + case KMF_ERR_OCSP_POLICY: + (void) fprintf(stderr, + gettext("Error in OCSP policy attributes\n")); + break; + default: + break; + } +} |