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 *
create_mech(char * name)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
free_mechlist(mechlist_t * plist)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
is_in_list(char * mechname,mechlist_t * plist)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
update_conf(char * conf_file,char * entry)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