1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <stdio.h> 28 #include <strings.h> 29 #include <ctype.h> 30 #include <libgen.h> 31 #include <libintl.h> 32 #include <errno.h> 33 #include <kmfapiP.h> 34 #include <sys/stat.h> 35 #include <sys/param.h> 36 #include <cryptoutil.h> 37 #include "util.h" 38 39 static int err; /* To store errno which may be overwritten by gettext() */ 40 41 int 42 kc_install(int argc, char *argv[]) 43 { 44 int rv = KC_OK; 45 int opt; 46 extern int optind_av; 47 extern char *optarg_av; 48 char *keystore_name = NULL; 49 char *modulepath = NULL; 50 char *option_str = NULL; 51 conf_entry_t *entry = NULL; 52 char realpath[MAXPATHLEN]; 53 struct stat statbuf; 54 FILE *pfile = NULL; 55 FILE *pfile_tmp = NULL; 56 char tmpfile_name[MAXPATHLEN]; 57 int found_count = 0; 58 char buffer[BUFSIZ]; 59 char *ptr; 60 boolean_t found; 61 62 while ((opt = getopt_av(argc, argv, "k:(keystore)m:(modulepath)" 63 "o:(option)")) != EOF) { 64 switch (opt) { 65 case 'k': 66 if (keystore_name != NULL) 67 rv = KC_ERR_USAGE; 68 else { 69 keystore_name = get_string(optarg_av, &rv); 70 if (keystore_name == NULL) { 71 (void) fprintf(stderr, gettext( 72 "Error keystore input.\n")); 73 } 74 } 75 break; 76 case 'm': 77 if (modulepath != NULL) 78 rv = KC_ERR_USAGE; 79 else { 80 modulepath = get_string(optarg_av, &rv); 81 if (modulepath == NULL) { 82 (void) fprintf(stderr, 83 gettext("Error modulepath.\n")); 84 } 85 } 86 break; 87 case 'o': 88 if (option_str != NULL) { 89 rv = KC_ERR_USAGE; 90 } else { 91 option_str = get_string(optarg_av, &rv); 92 if (option_str == NULL) { 93 (void) fprintf(stderr, 94 gettext("Error option input.\n")); 95 } 96 } 97 break; 98 default: 99 (void) fprintf(stderr, 100 gettext("Error input option.\n")); 101 rv = KC_ERR_USAGE; 102 break; 103 } 104 if (rv != KC_OK) 105 goto out; 106 } 107 108 /* No additional args allowed. */ 109 argc -= optind_av; 110 if (argc) { 111 (void) fprintf(stderr, 112 gettext("Error input option\n")); 113 rv = KC_ERR_USAGE; 114 goto out; 115 } 116 117 if (keystore_name == NULL || modulepath == NULL) { 118 (void) fprintf(stderr, gettext("Error input option\n")); 119 rv = KC_ERR_USAGE; 120 goto out; 121 } 122 123 if (strcasecmp(keystore_name, "nss") == 0 || 124 strcasecmp(keystore_name, "pkcs11") == 0 || 125 strcasecmp(keystore_name, "file") == 0) { 126 (void) fprintf(stderr, 127 gettext("Can not use the built-in keystore name %s\n"), 128 keystore_name); 129 rv = KC_ERR_USAGE; 130 goto out; 131 } 132 133 entry = get_keystore_entry(keystore_name); 134 if (entry != NULL) { 135 (void) fprintf(stderr, gettext("%s exists already.\n"), 136 keystore_name); 137 rv = KC_ERR_USAGE; 138 goto out; 139 } 140 141 /* 142 * Find the absolute path of the module and check if it exists in 143 * the system. If $ISA is in the path, will check the 32bit version 144 * only. 145 */ 146 if (strncmp(modulepath, "/", 1) != 0) { 147 /* 148 * Only contain the base name; prepand it with 149 * KMF_PLUGIN_PATH 150 */ 151 (void) snprintf(realpath, MAXPATHLEN, "%s%s", 152 KMF_PLUGIN_PATH, modulepath); 153 } else { 154 char *buf = modulepath; 155 char *isa; 156 157 if ((isa = strstr(buf, PKCS11_ISA)) != NULL) { 158 (void) strncpy(realpath, buf, isa - buf); 159 isa += strlen(PKCS11_ISA) - 1; 160 (void) strlcat(realpath, isa, MAXPATHLEN); 161 } else { 162 (void) strlcpy(realpath, modulepath, MAXPATHLEN); 163 } 164 } 165 166 if (stat(realpath, &statbuf) != 0) { 167 (void) fprintf(stderr, gettext("%s not found.\n"), 168 realpath); 169 rv = KC_ERR_ACCESS; 170 goto out; 171 } 172 173 if ((pfile = fopen(_PATH_KMF_CONF, "r+")) == NULL) { 174 err = errno; 175 (void) fprintf(stderr, 176 gettext("failed to update the configuration - %s\n"), 177 strerror(err)); 178 rv = KC_ERR_ACCESS; 179 goto out; 180 } 181 182 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 183 err = errno; 184 (void) fprintf(stderr, 185 gettext("failed to lock the configuration - %s\n"), 186 strerror(err)); 187 rv = KC_ERR_INSTALL; 188 goto out; 189 } 190 191 /* 192 * Create a temporary file in the /etc/crypto directory. 193 */ 194 (void) strlcpy(tmpfile_name, CONF_TEMPFILE, sizeof (tmpfile_name)); 195 if (mkstemp(tmpfile_name) == -1) { 196 err = errno; 197 (void) fprintf(stderr, 198 gettext("failed to create a temporary file - %s\n"), 199 strerror(err)); 200 rv = KC_ERR_INSTALL; 201 goto out; 202 } 203 204 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 205 err = errno; 206 (void) fprintf(stderr, 207 gettext("failed to open %s - %s\n"), 208 tmpfile_name, strerror(err)); 209 rv = KC_ERR_INSTALL; 210 goto out; 211 } 212 213 /* 214 * Loop thru the config file. If the file was reserved within a 215 * package bracket, just uncomment it. Other wise, append it at 216 * the end. The resulting file will be saved in the temp file first. 217 */ 218 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 219 found = B_FALSE; 220 if (buffer[0] == '#') { 221 ptr = buffer; 222 ptr++; 223 while (*ptr == '#' || *ptr == ' ') 224 ptr++; 225 if (strncmp(keystore_name, ptr, strlen(keystore_name)) 226 == 0) { 227 found = B_TRUE; 228 found_count++; 229 } 230 } 231 232 if (found == B_FALSE) { 233 if (fputs(buffer, pfile_tmp) == EOF) { 234 rv = KC_ERR_INSTALL; 235 goto out; 236 } 237 } else { 238 if (found_count == 1) { 239 if (fputs(ptr, pfile_tmp) == EOF) { 240 rv = KC_ERR_INSTALL; 241 goto out; 242 } 243 } else { 244 /* 245 * Found a second entry with #keystore_name. 246 * This should not happen. The kmf.conf file 247 * is corrupted. Give a warning and skip 248 * this entry. 249 */ 250 (void) fprintf(stderr, gettext( 251 "(Warning) Found an additional reserved " 252 "entry for %s.\n"), keystore_name); 253 } 254 } 255 } 256 257 if (found_count == 0) { 258 char buf[MAXPATHLEN]; 259 /* 260 * This entry was not in package before, append it to the 261 * end of the temp file. 262 */ 263 if (option_str == NULL) 264 (void) snprintf(buf, MAXPATHLEN, "%s:%s%s\n", 265 keystore_name, CONF_MODULEPATH, modulepath); 266 else 267 (void) snprintf(buf, MAXPATHLEN, "%s:%s%s;%s%s\n", 268 keystore_name, CONF_MODULEPATH, modulepath, 269 CONF_OPTION, option_str); 270 271 if (fputs(buf, pfile_tmp) == EOF) { 272 err = errno; 273 (void) fprintf(stderr, gettext( 274 "failed to write to %s: %s\n"), tmpfile_name, 275 strerror(err)); 276 rv = KC_ERR_INSTALL; 277 goto out; 278 } 279 } 280 281 out: 282 if (pfile != NULL) 283 (void) fclose(pfile); 284 285 if (rv != KC_OK && pfile_tmp != NULL) 286 (void) unlink(tmpfile_name); 287 288 if (pfile_tmp != NULL) 289 (void) fclose(pfile_tmp); 290 291 if (rv == KC_OK) { 292 if (rename(tmpfile_name, _PATH_KMF_CONF) == -1) { 293 err = errno; 294 (void) fprintf(stderr, gettext( 295 "failed to update the configuration - %s"), 296 strerror(err)); 297 return (KC_ERR_INSTALL); 298 } 299 300 if (chmod(_PATH_KMF_CONF, 301 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 302 err = errno; 303 (void) fprintf(stderr, gettext( 304 "failed to update the configuration - %s\n"), 305 strerror(err)); 306 return (KC_ERR_INSTALL); 307 } 308 } 309 310 return (rv); 311 } 312