/* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #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_free_policy_record(&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_string_to_ku(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_ekuname_to_oid(ekulist); if (newoid != NULL) { addToEKUList(ekus, newoid); free(newoid); } else { rv = KC_ERR_USAGE; } } while (p != NULL) { newoid = kmf_ekuname_to_oid(p); if (newoid != NULL) { addToEKUList(ekus, newoid); free(newoid); } else { rv = KC_ERR_USAGE; break; } p = strtok(NULL, ","); } if (rv != KC_OK) kmf_free_eku_policy(ekus); return (rv); } int parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) { int rv = KC_OK; char *p; KMF_OID newoid = { 0, NULL }; 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) { if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) { addToEKUList(ekus, &newoid); } else { rv = KC_ERR_USAGE; } } while (p != NULL && rv == 0) { if (kmf_string_to_oid(p, &newoid) == KMF_OK) { addToEKUList(ekus, &newoid); } else { rv = KC_ERR_USAGE; break; } p = strtok(NULL, ","); } if (rv != KC_OK) kmf_free_eku_policy(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: * [ ':' ] [ '(' ')' ] * 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; } } conf_entry_t * get_keystore_entry(char *kstore_name) { conf_entrylist_t *phead = NULL; conf_entrylist_t *ptr; conf_entry_t *rtn_entry = NULL; if (kstore_name == NULL) return (NULL); if (get_entrylist(&phead) != KMF_OK) return (NULL); ptr = phead; while (ptr != NULL) { if (strcmp(ptr->entry->keystore, kstore_name) == 0) break; ptr = ptr->next; } if (ptr != NULL) /* found the entry */ rtn_entry = dup_entry(ptr->entry); free_entrylist(phead); return (rtn_entry); }