summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-crypto/kmfcfg/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-crypto/kmfcfg/util.c')
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/util.c497
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;
+ }
+}