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 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <ctype.h> 27 #include <strings.h> 28 #include <libintl.h> 29 #include <stdio.h> 30 #include <sys/stat.h> 31 #include "cryptoadm.h" 32 #include <cryptoutil.h> 33 34 /* 35 * Create one item of type mechlist_t with the mechanism name. A null is 36 * returned to indicate that the storage space available is insufficient. 37 */ 38 mechlist_t * 39 create_mech(char *name) 40 { 41 mechlist_t *pres = NULL; 42 char *first, *last; 43 44 if (name == NULL) { 45 return (NULL); 46 } 47 48 pres = malloc(sizeof (mechlist_t)); 49 if (pres == NULL) { 50 cryptodebug("out of memory."); 51 return (NULL); 52 } 53 54 first = name; 55 while (isspace(*first)) /* nuke leading whitespace */ 56 first++; 57 (void) strlcpy(pres->name, first, sizeof (pres->name)); 58 59 last = strrchr(pres->name, '\0'); 60 last--; 61 while (isspace(*last)) /* nuke trailing whitespace */ 62 *last-- = '\0'; 63 64 pres->next = NULL; 65 66 return (pres); 67 } 68 69 70 71 void 72 free_mechlist(mechlist_t *plist) 73 { 74 mechlist_t *pnext; 75 76 while (plist != NULL) { 77 pnext = plist->next; 78 free(plist); 79 plist = pnext; 80 } 81 } 82 83 84 85 /* 86 * Check if the mechanism is in the mechanism list. 87 */ 88 boolean_t 89 is_in_list(char *mechname, mechlist_t *plist) 90 { 91 boolean_t found = B_FALSE; 92 93 if (mechname == NULL) { 94 return (B_FALSE); 95 } 96 97 while (plist != NULL) { 98 if (strcmp(plist->name, mechname) == 0) { 99 found = B_TRUE; 100 break; 101 } 102 plist = plist->next; 103 } 104 105 return (found); 106 } 107 108 int 109 update_conf(char *conf_file, char *entry) 110 { 111 112 boolean_t found; 113 FILE *pfile; 114 FILE *pfile_tmp; 115 char tmpfile_name[MAXPATHLEN]; 116 char *ptr; 117 char *name; 118 char buffer[BUFSIZ]; 119 char buffer2[BUFSIZ]; 120 int found_count; 121 int rc = SUCCESS; 122 int err; 123 124 if ((pfile = fopen(conf_file, "r+")) == NULL) { 125 err = errno; 126 cryptoerror(LOG_STDERR, 127 gettext("failed to update the configuration - %s"), 128 strerror(err)); 129 cryptodebug("failed to open %s for write.", conf_file); 130 return (FAILURE); 131 } 132 133 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 134 err = errno; 135 cryptoerror(LOG_STDERR, 136 gettext("failed to lock the configuration - %s"), 137 strerror(err)); 138 (void) fclose(pfile); 139 return (FAILURE); 140 } 141 142 /* 143 * Create a temporary file in the /etc/crypto directory. 144 */ 145 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 146 if (mkstemp(tmpfile_name) == -1) { 147 err = errno; 148 cryptoerror(LOG_STDERR, 149 gettext("failed to create a temporary file - %s"), 150 strerror(err)); 151 (void) fclose(pfile); 152 return (FAILURE); 153 } 154 155 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 156 err = errno; 157 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 158 tmpfile_name, strerror(err)); 159 (void) fclose(pfile); 160 return (FAILURE); 161 } 162 163 164 /* 165 * Loop thru the config file. If the provider was reserved within a 166 * package bracket, just uncomment it. Otherwise, append it at 167 * the end. The resulting file will be saved in the temp file first. 168 */ 169 found_count = 0; 170 rc = SUCCESS; 171 172 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 173 found = B_FALSE; 174 if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 175 if (buffer[0] == '#') { 176 ptr = buffer; 177 ptr++; 178 if (strcmp(entry, ptr) == 0) { 179 found = B_TRUE; 180 found_count++; 181 } 182 } 183 } else { /* _PATH_KCF_CONF */ 184 if (buffer[0] == '#') { 185 (void) strlcpy(buffer2, buffer, BUFSIZ); 186 ptr = buffer2; 187 ptr++; /* skip # */ 188 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 189 rc = FAILURE; 190 break; 191 } else if (strcmp(FIPS_KEYWORD, name) == 0) { 192 found = B_TRUE; 193 found_count++; 194 } 195 } else { 196 (void) strlcpy(buffer2, buffer, BUFSIZ); 197 ptr = buffer2; 198 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 199 rc = FAILURE; 200 break; 201 } else if (strcmp(FIPS_KEYWORD, name) == 0) { 202 found = B_TRUE; 203 found_count++; 204 } 205 } 206 } 207 208 if (found == B_FALSE) { 209 if (fputs(buffer, pfile_tmp) == EOF) { 210 rc = FAILURE; 211 } 212 } else { 213 if (found_count == 1) { 214 if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 215 if (fputs(ptr, pfile_tmp) == EOF) { 216 rc = FAILURE; 217 } 218 } else { 219 if (fputs(entry, pfile_tmp) == EOF) { 220 rc = FAILURE; 221 } 222 } 223 } else { 224 /* 225 * Found a second entry with same tag name. 226 * Should not happen. The config file 227 * is corrupted. Give a warning and skip 228 * this entry. 229 */ 230 cryptoerror(LOG_STDERR, gettext( 231 "(Warning) Found an additional reserved " 232 "entry for %s."), entry); 233 } 234 } 235 236 if (rc == FAILURE) { 237 break; 238 } 239 } 240 241 (void) fclose(pfile); 242 243 if (rc == FAILURE) { 244 cryptoerror(LOG_STDERR, gettext("write error.")); 245 (void) fclose(pfile_tmp); 246 if (unlink(tmpfile_name) != 0) { 247 err = errno; 248 cryptoerror(LOG_STDERR, gettext( 249 "(Warning) failed to remove %s: %s"), tmpfile_name, 250 strerror(err)); 251 } 252 return (FAILURE); 253 } 254 255 if (found_count == 0) { 256 /* 257 * The entry was not in config file before, append it to the 258 * end of the temp file. 259 */ 260 if (fputs(entry, pfile_tmp) == EOF) { 261 cryptoerror(LOG_STDERR, gettext( 262 "failed to write to %s: %s"), tmpfile_name, 263 strerror(errno)); 264 (void) fclose(pfile_tmp); 265 if (unlink(tmpfile_name) != 0) { 266 err = errno; 267 cryptoerror(LOG_STDERR, gettext( 268 "(Warning) failed to remove %s: %s"), 269 tmpfile_name, strerror(err)); 270 } 271 return (FAILURE); 272 } 273 } 274 275 if (fclose(pfile_tmp) != 0) { 276 err = errno; 277 cryptoerror(LOG_STDERR, 278 gettext("failed to close %s: %s"), tmpfile_name, 279 strerror(err)); 280 return (FAILURE); 281 } 282 283 if (rename(tmpfile_name, conf_file) == -1) { 284 err = errno; 285 cryptoerror(LOG_STDERR, 286 gettext("failed to update the configuration - %s"), 287 strerror(err)); 288 cryptodebug("failed to rename %s to %s: %s", tmpfile_name, 289 conf_file, strerror(err)); 290 rc = FAILURE; 291 } else if (chmod(conf_file, 292 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 293 err = errno; 294 cryptoerror(LOG_STDERR, 295 gettext("failed to update the configuration - %s"), 296 strerror(err)); 297 cryptodebug("failed to chmod to %s: %s", conf_file, 298 strerror(err)); 299 rc = FAILURE; 300 } else { 301 rc = SUCCESS; 302 } 303 304 if (rc == FAILURE) { 305 if (unlink(tmpfile_name) != 0) { 306 err = errno; 307 cryptoerror(LOG_STDERR, gettext( 308 "(Warning) failed to remove %s: %s"), 309 tmpfile_name, strerror(err)); 310 } 311 } 312 313 return (rc); 314 315 } 316