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 boolean_t fips_entry = B_FALSE; 114 FILE *pfile; 115 FILE *pfile_tmp; 116 char tmpfile_name[MAXPATHLEN]; 117 char *ptr; 118 char *name; 119 char buffer[BUFSIZ]; 120 char buffer2[BUFSIZ]; 121 int found_count; 122 int rc = SUCCESS; 123 int err; 124 125 if ((pfile = fopen(conf_file, "r+")) == NULL) { 126 err = errno; 127 cryptoerror(LOG_STDERR, 128 gettext("failed to update the configuration - %s"), 129 strerror(err)); 130 cryptodebug("failed to open %s for write.", conf_file); 131 return (FAILURE); 132 } 133 134 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 135 err = errno; 136 cryptoerror(LOG_STDERR, 137 gettext("failed to lock the configuration - %s"), 138 strerror(err)); 139 (void) fclose(pfile); 140 return (FAILURE); 141 } 142 143 /* 144 * Create a temporary file in the /etc/crypto directory. 145 */ 146 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 147 if (mkstemp(tmpfile_name) == -1) { 148 err = errno; 149 cryptoerror(LOG_STDERR, 150 gettext("failed to create a temporary file - %s"), 151 strerror(err)); 152 (void) fclose(pfile); 153 return (FAILURE); 154 } 155 156 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 157 err = errno; 158 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 159 tmpfile_name, strerror(err)); 160 (void) fclose(pfile); 161 return (FAILURE); 162 } 163 164 165 /* 166 * Loop thru the config file. If the provider was reserved within a 167 * package bracket, just uncomment it. Otherwise, append it at 168 * the end. The resulting file will be saved in the temp file first. 169 */ 170 found_count = 0; 171 rc = SUCCESS; 172 173 while (fgets(buffer, BUFSIZ, pfile) != NULL) { 174 found = B_FALSE; 175 if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 176 if (buffer[0] == '#') { 177 ptr = buffer; 178 ptr++; 179 if (strcmp(entry, ptr) == 0) { 180 found = B_TRUE; 181 found_count++; 182 } 183 } else { 184 (void) strlcpy(buffer2, buffer, BUFSIZ); 185 ptr = buffer2; 186 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 187 rc = FAILURE; 188 break; 189 } else if (strcmp(FIPS_KEYWORD, name) == 0) { 190 found = B_TRUE; 191 found_count++; 192 fips_entry = B_TRUE; 193 } 194 } 195 } else { /* _PATH_KCF_CONF */ 196 if (buffer[0] == '#') { 197 (void) strlcpy(buffer2, buffer, BUFSIZ); 198 ptr = buffer2; 199 ptr++; /* skip # */ 200 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 201 rc = FAILURE; 202 break; 203 } 204 } else { 205 (void) strlcpy(buffer2, buffer, BUFSIZ); 206 ptr = buffer2; 207 if ((name = strtok(ptr, SEP_COLON)) == NULL) { 208 rc = FAILURE; 209 break; 210 } 211 } 212 } 213 214 if (found == B_FALSE) { 215 if (fputs(buffer, pfile_tmp) == EOF) { 216 rc = FAILURE; 217 } 218 } else { 219 if (found_count == 1) { 220 if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 221 if (fips_entry == B_TRUE) { 222 if (fputs(entry, pfile_tmp) == 223 EOF) { 224 rc = FAILURE; 225 } 226 fips_entry = B_FALSE; 227 } else { 228 if (fputs(ptr, pfile_tmp) == 229 EOF) { 230 rc = FAILURE; 231 } 232 } 233 } else { 234 if (fputs(entry, pfile_tmp) == EOF) { 235 rc = FAILURE; 236 } 237 } 238 } else { 239 /* 240 * Found a second entry with same tag name. 241 * Should not happen. The config file 242 * is corrupted. Give a warning and skip 243 * this entry. 244 */ 245 cryptoerror(LOG_STDERR, gettext( 246 "(Warning) Found an additional reserved " 247 "entry for %s."), entry); 248 } 249 } 250 251 if (rc == FAILURE) { 252 break; 253 } 254 } 255 256 (void) fclose(pfile); 257 258 if (rc == FAILURE) { 259 cryptoerror(LOG_STDERR, gettext("write error.")); 260 (void) fclose(pfile_tmp); 261 if (unlink(tmpfile_name) != 0) { 262 err = errno; 263 cryptoerror(LOG_STDERR, gettext( 264 "(Warning) failed to remove %s: %s"), tmpfile_name, 265 strerror(err)); 266 } 267 return (FAILURE); 268 } 269 270 if (found_count == 0) { 271 /* 272 * The entry was not in config file before, append it to the 273 * end of the temp file. 274 */ 275 if (fputs(entry, pfile_tmp) == EOF) { 276 cryptoerror(LOG_STDERR, gettext( 277 "failed to write to %s: %s"), tmpfile_name, 278 strerror(errno)); 279 (void) fclose(pfile_tmp); 280 if (unlink(tmpfile_name) != 0) { 281 err = errno; 282 cryptoerror(LOG_STDERR, gettext( 283 "(Warning) failed to remove %s: %s"), 284 tmpfile_name, strerror(err)); 285 } 286 return (FAILURE); 287 } 288 } 289 290 if (fclose(pfile_tmp) != 0) { 291 err = errno; 292 cryptoerror(LOG_STDERR, 293 gettext("failed to close %s: %s"), tmpfile_name, 294 strerror(err)); 295 return (FAILURE); 296 } 297 298 if (rename(tmpfile_name, conf_file) == -1) { 299 err = errno; 300 cryptoerror(LOG_STDERR, 301 gettext("failed to update the configuration - %s"), 302 strerror(err)); 303 cryptodebug("failed to rename %s to %s: %s", tmpfile_name, 304 conf_file, strerror(err)); 305 rc = FAILURE; 306 } else if (chmod(conf_file, 307 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 308 err = errno; 309 cryptoerror(LOG_STDERR, 310 gettext("failed to update the configuration - %s"), 311 strerror(err)); 312 cryptodebug("failed to chmod to %s: %s", conf_file, 313 strerror(err)); 314 rc = FAILURE; 315 } else { 316 rc = SUCCESS; 317 } 318 319 if (rc == FAILURE) { 320 if (unlink(tmpfile_name) != 0) { 321 err = errno; 322 cryptoerror(LOG_STDERR, gettext( 323 "(Warning) failed to remove %s: %s"), 324 tmpfile_name, strerror(err)); 325 } 326 } 327 328 return (rc); 329 330 } 331