/* * 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" /* * This file contains the functions that are shared among * the various services this tool will ultimately provide. * The functions in this file return PKCS#11 CK_RV errors. * Only one session and one login per token is supported * at this time. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" /* Local status variables. */ static boolean_t initialized = B_FALSE; static boolean_t session_opened = B_FALSE; static boolean_t logged_in = B_FALSE; /* 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; static void close_sess(CK_SESSION_HANDLE); static void logout_token(CK_SESSION_HANDLE); /* * Perform PKCS#11 setup here. Currently only C_Initialize is required, * along with setting/resetting state variables. */ CK_RV init_pk11(void) { CK_RV rv = CKR_OK; /* If C_Initialize() already called, nothing to do here. */ if (initialized == B_TRUE) return (CKR_OK); /* Reset state variables because C_Initialize() not yet done. */ session_opened = B_FALSE; logged_in = B_FALSE; /* Initialize PKCS#11 library. */ if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { return (rv); } initialized = B_TRUE; return (CKR_OK); } /* * Finalize PKCS#11 library and reset state variables. Open sessions, * if any, are closed, and thereby any logins are logged out also. */ void final_pk11(CK_SESSION_HANDLE sess) { /* If the library wasn't initialized, nothing to do here. */ if (!initialized) return; /* Make sure the sesion is closed first. */ close_sess(sess); (void) C_Finalize(NULL); initialized = B_FALSE; } /* * Close PKCS#11 session and reset state variables. Any logins are * logged out. */ static void close_sess(CK_SESSION_HANDLE sess) { if (sess == NULL) { return; } /* If session is already closed, nothing to do here. */ if (!session_opened) return; /* Make sure user is logged out of token. */ logout_token(sess); (void) C_CloseSession(sess); session_opened = B_FALSE; } /* * Log user out of token and reset status variable. */ static void logout_token(CK_SESSION_HANDLE sess) { if (sess == NULL) { return; } /* If already logged out, nothing to do here. */ if (!logged_in) return; (void) C_Logout(sess); logged_in = B_FALSE; } /* * Gets PIN from user. Caller needs to free the returned PIN when done. * If two prompts are given, the PIN is confirmed with second prompt. * Note that getphassphrase() may return data in static memory area. */ CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) { char *save_phrase, *phrase1, *phrase2; #ifdef DEBUG if (getenv("TOKENPIN") != NULL) { *pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN")); *pinlen = strlen((char *)(*pin)); return (CKR_OK); } #endif /* DEBUG */ /* Prompt user for a PIN. */ if (prompt1 == NULL) { return (CKR_ARGUMENTS_BAD); } if ((phrase1 = getpassphrase(prompt1)) == NULL) { return (CKR_FUNCTION_FAILED); } /* Duplicate 1st PIN in separate chunk of memory. */ if ((save_phrase = strdup(phrase1)) == NULL) return (CKR_HOST_MEMORY); /* If second prompt given, PIN confirmation is requested. */ if (prompt2 != NULL) { if ((phrase2 = getpassphrase(prompt2)) == NULL) { free(save_phrase); return (CKR_FUNCTION_FAILED); } if (strcmp(save_phrase, phrase2) != 0) { free(save_phrase); return (CKR_PIN_INCORRECT); } } *pin = (CK_UTF8CHAR_PTR)save_phrase; *pinlen = strlen(save_phrase); return (CKR_OK); } /* * Gets yes/no response from user. If either no prompt is supplied, a * default prompt is used. If not message for invalid input is supplied, * a default will not be provided. If the user provides no response, * the input default B_TRUE == yes, B_FALSE == no is returned. * Otherwise, B_TRUE is returned for yes, and B_FALSE for no. */ boolean_t yesno(char *prompt, char *invalid, boolean_t dflt) { char *response, buf[1024]; char *yes = gettext("yes"); char *no = gettext("no"); #ifdef DEBUG /* If debugging or testing, return TRUE and avoid prompting */ if (getenv("TOKENPIN") != NULL) { return (B_TRUE); } #endif /* DEBUG */ if (prompt == NULL) prompt = gettext("Enter (y)es or (n)o? "); for (;;) { /* Prompt user. */ (void) printf("%s", prompt); (void) fflush(stdout); /* Get the response. */ if ((response = fgets(buf, sizeof (buf), stdin)) == NULL) break; /* go to default response */ /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') break; /* go to default response */ /* Is it valid input? Return appropriately. */ if (strncasecmp(response, yes, 1) == 0) return (B_TRUE); if (strncasecmp(response, no, 1) == 0) return (B_FALSE); /* Indicate invalid input, and try again. */ if (invalid != NULL) (void) printf("%s", invalid); } return (dflt); } /* * Gets the list of slots which have tokens in them. Keeps adjusting * the size of the slot list buffer until the call is successful or an * irrecoverable error occurs. */ CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) { CK_ULONG tmp_count = 0; CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; int rv = CKR_OK; if (!initialized) if ((rv = init_pk11()) != CKR_OK) return (rv); /* * Get the slot count first because we don't know how many * slots there are and how many of those slots even have tokens. * Don't specify an arbitrary buffer size for the slot list; * it may be too small (see section 11.5 of PKCS#11 spec). * Also select only those slots that have tokens in them, * because this tool has no need to know about empty slots. */ if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) return (rv); if (tmp_count == 0) { *slot_list = NULL_PTR; *slot_count = 0; return (CKR_OK); } /* Allocate initial space for the slot list. */ if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * sizeof (CK_SLOT_ID))) == NULL) return (CKR_HOST_MEMORY); /* Then get the slot list itself. */ for (;;) { if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { *slot_list = tmp_list; *slot_count = tmp_count; break; } if (rv != CKR_BUFFER_TOO_SMALL) { free(tmp_list); break; } /* If the number of slots grew, try again. */ if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, tmp_count * sizeof (CK_SLOT_ID))) == NULL) { free(tmp_list); rv = CKR_HOST_MEMORY; break; } tmp_list = tmp2_list; } return (rv); } /* * 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) { if (opts_av != NULL) free(opts_av); opts_av = NULL; return (0); } else { opts_av = (av_opts *)temp; } (void) memset(&opts_av[i], 0, sizeof (av_opts)); 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 requiring that only longname options and values be found * on the command line and all leading dashes are omitted. In other words, * it tries to enforce only longname "option=value" arguments on the command * line. Boolean options are not allowed either. */ int getopt_av(int argc, char * const *argv, const char *optstring) { int i; int len; char *cur_option; 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++) { cur_option = argv[optind_av]; if (strcmp(cur_option, "--") == 0) { optind_av++; break; } if (cur_option[0] == '-' && strlen(cur_option) == 2) { len = 1; cur_option++; /* remove "-" */ } else { len = strcspn(cur_option, "="); } if (len == opts_av[i].longnm_len && strncmp(cur_option, 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 (cur_option[len] == '=') { optarg_av = &(cur_option[len+1]); optind_av++; return (opts_av[i].shortnm); } optarg_av = NULL; optind_av++; return ((int)'?'); } } return (EOF); } KMF_KEYSTORE_TYPE KS2Int(char *keystore_str) { if (keystore_str == NULL) return (0); if (!strcasecmp(keystore_str, "pkcs11")) return (KMF_KEYSTORE_PK11TOKEN); else if (!strcasecmp(keystore_str, "nss")) return (KMF_KEYSTORE_NSS); else if (!strcasecmp(keystore_str, "file")) return (KMF_KEYSTORE_OPENSSL); else return (0); } int Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) { if (algm == NULL) { *sigAlg = KMF_ALGID_MD5WithRSA; *ktype = KMF_RSA; } else if (strcasecmp(algm, "DSA") == 0) { *sigAlg = KMF_ALGID_SHA1WithDSA; *ktype = KMF_DSA; } else if (strcasecmp(algm, "RSA") == 0) { *sigAlg = KMF_ALGID_MD5WithRSA; *ktype = KMF_RSA; } else { return (-1); } return (0); } int Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) { if (algm == NULL) *ktype = KMF_AES; else if (strcasecmp(algm, "aes") == 0) *ktype = KMF_AES; else if (strcasecmp(algm, "arcfour") == 0) *ktype = KMF_RC4; else if (strcasecmp(algm, "des") == 0) *ktype = KMF_DES; else if (strcasecmp(algm, "3des") == 0) *ktype = KMF_DES3; else return (-1); return (0); } int Str2Lifetime(char *ltimestr, uint32_t *ltime) { int num; char timetok[6]; if (ltimestr == NULL || !strlen(ltimestr)) { /* default to 1 year lifetime */ *ltime = SECSPERDAY * DAYSPERNYEAR; return (0); } (void) memset(timetok, 0, sizeof (timetok)); if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) return (-1); if (!strcasecmp(timetok, "day") || !strcasecmp(timetok, "days")) { *ltime = num * SECSPERDAY; } else if (!strcasecmp(timetok, "hour") || !strcasecmp(timetok, "hours")) { *ltime = num * SECSPERHOUR; } else if (!strcasecmp(timetok, "year") || !strcasecmp(timetok, "years")) { *ltime = num * SECSPERDAY * DAYSPERNYEAR; } else { *ltime = 0; return (-1); } return (0); } int OT2Int(char *objclass) { char *c = NULL; int retval = 0; if (objclass == NULL) return (-1); c = strchr(objclass, ':'); if (c != NULL) { if (!strcasecmp(c, ":private")) retval = PK_PRIVATE_OBJ; else if (!strcasecmp(c, ":public")) retval = PK_PUBLIC_OBJ; else if (!strcasecmp(c, ":both")) retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; else /* unrecognized option */ return (-1); *c = '\0'; } if (!strcasecmp(objclass, "public")) { if (retval) return (-1); return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ); } else if (!strcasecmp(objclass, "private")) { if (retval) return (-1); return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); } else if (!strcasecmp(objclass, "both")) { if (retval) return (-1); return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); } else if (!strcasecmp(objclass, "cert")) { return (retval | PK_CERT_OBJ); } else if (!strcasecmp(objclass, "key")) { if (retval == 0) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) /* return all keys */ return (retval | PK_KEY_OBJ); else if (retval & PK_PUBLIC_OBJ) /* Only return public keys */ return (retval | PK_PUBKEY_OBJ); else if (retval & PK_PRIVATE_OBJ) /* Only return private keys */ return (retval | PK_PRIKEY_OBJ); } else if (!strcasecmp(objclass, "crl")) { if (retval) return (-1); return (retval | PK_CRL_OBJ); } if (retval == 0) /* No matches found */ retval = -1; return (retval); } KMF_ENCODE_FORMAT Str2Format(char *formstr) { if (formstr == NULL || !strcasecmp(formstr, "der")) return (KMF_FORMAT_ASN1); if (!strcasecmp(formstr, "pem")) return (KMF_FORMAT_PEM); if (!strcasecmp(formstr, "pkcs12")) return (KMF_FORMAT_PKCS12); return (KMF_FORMAT_UNDEF); } KMF_RETURN select_token(void *kmfhandle, char *token, int readonly) { KMF_RETURN rv = KMF_OK; KMF_CONFIG_PARAMS config; if (token == NULL) return (KMF_ERR_BAD_PARAMETER); (void) memset(&config, 0, sizeof (config)); config.kstype = KMF_KEYSTORE_PK11TOKEN; config.pkcs11config.label = token; config.pkcs11config.readonly = readonly; rv = KMF_ConfigureKeystore(kmfhandle, &config); if (rv == KMF_ERR_TOKEN_SELECTED) rv = KMF_OK; return (rv); } KMF_RETURN configure_nss(void *kmfhandle, char *dir, char *prefix) { KMF_RETURN rv = KMF_OK; KMF_CONFIG_PARAMS config; (void) memset(&config, 0, sizeof (config)); config.kstype = KMF_KEYSTORE_NSS; config.nssconfig.configdir = dir; config.nssconfig.certPrefix = prefix; config.nssconfig.keyPrefix = prefix; config.nssconfig.secModName = NULL; rv = KMF_ConfigureKeystore(kmfhandle, &config); if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) rv = KMF_OK; return (rv); } KMF_RETURN get_pk12_password(KMF_CREDENTIAL *cred) { KMF_RETURN rv = KMF_OK; char prompt[1024]; /* * Get the password to use for the PK12 encryption. */ (void) strlcpy(prompt, gettext("Enter password to use for " "accessing the PKCS12 file: "), sizeof (prompt)); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } return (rv); } #define COUNTRY_PROMPT "Country Name (2 letter code) [US]:" #define STATE_PROMPT "State or Province Name (full name) [Some-State]:" #define LOCALITY_PROMPT "Locality Name (eg, city) []:" #define ORG_PROMPT "Organization Name (eg, company) []:" #define UNIT_PROMPT "Organizational Unit Name (eg, section) []:" #define NAME_PROMPT "Common Name (eg, YOUR name) []:" #define EMAIL_PROMPT "Email Address []:" #define COUNTRY_DEFAULT "US" #define STATE_DEFAULT "Some-State" #define INVALID_INPUT "Invalid input; please re-enter ..." #define SUBNAMESIZ 1024 #define RDN_MIN 1 #define RDN_MAX 64 #define COUNTRYNAME_MIN 2 #define COUNTRYNAME_MAX 2 static char * get_input_string(char *prompt, char *default_str, int min_len, int max_len) { char buf[1024]; char *response = NULL; char *ret = NULL; int len; for (;;) { (void) printf("\t%s", prompt); (void) fflush(stdout); response = fgets(buf, sizeof (buf), stdin); if (response == NULL) { if (default_str != NULL) { ret = strdup(default_str); } break; } /* Skip any leading white space. */ while (isspace(*response)) response++; if (*response == '\0') { if (default_str != NULL) { ret = strdup(default_str); } break; } len = strlen(response); response[len-1] = '\0'; /* get rid of "LF" */ len--; if (len >= min_len && len <= max_len) { ret = strdup(response); break; } (void) printf("%s\n", INVALID_INPUT); } return (ret); } int get_subname(char **result) { char *country = NULL; char *state = NULL; char *locality = NULL; char *org = NULL; char *unit = NULL; char *name = NULL; char *email = NULL; char *subname = NULL; (void) printf("Entering following fields for subject (a DN) ...\n"); country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, COUNTRYNAME_MIN, COUNTRYNAME_MAX); if (country == NULL) return (-1); state = get_input_string(STATE_PROMPT, STATE_DEFAULT, RDN_MIN, RDN_MAX); if (state == NULL) { goto out; } locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); /* Now create a subject name from the input strings */ if ((subname = malloc(SUBNAMESIZ)) == NULL) goto out; (void) memset(subname, 0, SUBNAMESIZ); (void) strlcpy(subname, "C=", SUBNAMESIZ); (void) strlcat(subname, country, SUBNAMESIZ); (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "ST=", SUBNAMESIZ); (void) strlcat(subname, state, SUBNAMESIZ); if (locality) { (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "L=", SUBNAMESIZ); (void) strlcat(subname, locality, SUBNAMESIZ); } if (org) { (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "O=", SUBNAMESIZ); (void) strlcat(subname, org, SUBNAMESIZ); } if (unit) { (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "OU=", SUBNAMESIZ); (void) strlcat(subname, unit, SUBNAMESIZ); } if (name) { (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "CN=", SUBNAMESIZ); (void) strlcat(subname, name, SUBNAMESIZ); } if (email) { (void) strlcat(subname, ", ", SUBNAMESIZ); (void) strlcat(subname, "E=", SUBNAMESIZ); (void) strlcat(subname, email, SUBNAMESIZ); } out: if (country) free(country); if (state) free(state); if (locality) free(locality); if (org) free(org); if (unit) free(unit); if (name) free(name); if (email) free(email); if (subname == NULL) return (-1); else { *result = subname; return (0); } } /* * Parse a string of KeyUsage values and convert * them to the correct KU Bits. * The field may be marked "critical" by prepending * "critical:" to the list. * EX: critical:digitialSignature,keyEncipherment */ KMF_RETURN verify_keyusage(char *kustr, uint16_t *kubits, int *critical) { KMF_RETURN ret = KMF_OK; uint16_t kuval; char *k; *kubits = 0; if (kustr == NULL || !strlen(kustr)) return (KMF_ERR_BAD_PARAMETER); /* Check to see if this is critical */ if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { *critical = TRUE; kustr += strlen("critical:"); } else { *critical = FALSE; } k = strtok(kustr, ","); while (k != NULL) { kuval = KMF_StringToKeyUsage(k); if (kuval == 0) { *kubits = 0; return (KMF_ERR_BAD_PARAMETER); } *kubits |= kuval; k = strtok(NULL, ","); } return (ret); } /* * Verify the alternate subject label is real or invalid. * * The field may be marked "critical" by prepending * "critical:" to the list. * EX: "critical:IP=1.2.3.4" */ KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) { char *p; KMF_RETURN rv = KMF_OK; /* Check to see if this is critical */ if (!strncasecmp(arg, "critical:", strlen("critical:"))) { *critical = TRUE; arg += strlen("critical:"); } else { *critical = FALSE; } /* Make sure there is an "=" sign */ p = strchr(arg, '='); if (p == NULL) return (KMF_ERR_BAD_PARAMETER); p[0] = '\0'; if (strcmp(arg, "IP") == 0) *type = GENNAME_IPADDRESS; else if (strcmp(arg, "DNS") == 0) *type = GENNAME_DNSNAME; else if (strcmp(arg, "EMAIL") == 0) *type = GENNAME_RFC822NAME; else if (strcmp(arg, "URI") == 0) *type = GENNAME_URI; else if (strcmp(arg, "DN") == 0) *type = GENNAME_DIRECTORYNAME; else if (strcmp(arg, "RID") == 0) *type = GENNAME_REGISTEREDID; else rv = KMF_ERR_BAD_PARAMETER; p[0] = '='; return (rv); } int get_token_password(KMF_KEYSTORE_TYPE kstype, char *token_spec, KMF_CREDENTIAL *cred) { char prompt[1024]; char *p = NULL; if (kstype == KMF_KEYSTORE_PK11TOKEN) { p = strchr(token_spec, ':'); if (p != NULL) *p = 0; } /* * Login to the token first. */ (void) snprintf(prompt, sizeof (prompt), gettext(DEFAULT_TOKEN_PROMPT), token_spec); if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, (ulong_t *)&cred->credlen) != CKR_OK) { cred->cred = NULL; cred->credlen = 0; } if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) *p = ':'; return (KMF_OK); } KMF_RETURN verify_file(char *filename) { KMF_RETURN ret = KMF_OK; int fd; /* * Attempt to open with the EXCL flag so that if * it already exists, the open will fail. It will * also fail if the file cannot be created due to * permissions on the parent directory, or if the * parent directory itself does not exist. */ fd = open(filename, O_CREAT | O_EXCL, 0600); if (fd == -1) return (KMF_ERR_OPEN_FILE); /* If we were able to create it, delete it. */ (void) close(fd); (void) unlink(filename); return (ret); } void display_error(void *handle, KMF_RETURN errcode, char *prefix) { KMF_RETURN rv1, rv2; char *plugin_errmsg = NULL; char *kmf_errmsg = NULL; rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg); rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg); cryptoerror(LOG_STDERR, "%s:", prefix); if (rv1 == KMF_OK && plugin_errmsg) { cryptoerror(LOG_STDERR, gettext("keystore error: %s"), plugin_errmsg); KMF_FreeString(plugin_errmsg); } if (rv2 == KMF_OK && kmf_errmsg) { cryptoerror(LOG_STDERR, gettext("libkmf error: %s"), kmf_errmsg); KMF_FreeString(kmf_errmsg); } if (rv1 != KMF_OK && rv2 != KMF_OK) cryptoerror(LOG_STDERR, gettext("\n")); }