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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <unistd.h>
30 #include <locale.h>
31 #include <libgen.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <zone.h>
35 #include <sys/crypto/ioctladmin.h>
36 #include "cryptoadm.h"
37
38 #define HW_CONF_DIR "/platform/sun4v/kernel/drv"
39
40
41 /* Get FIPS-140 status from .conf */
42 int
fips_hw_status(char * filename,char * property,int * hw_fips_mode)43 fips_hw_status(char *filename, char *property, int *hw_fips_mode)
44 {
45 FILE *pfile;
46 char buffer[BUFSIZ];
47 char *str = NULL;
48 char *cursor = NULL;
49
50 /* Open the .conf file */
51 if ((pfile = fopen(filename, "r")) == NULL) {
52 cryptodebug("failed to open %s for write.", filename);
53 return (FAILURE);
54 }
55
56 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
57 if (buffer[0] == '#') {
58 /* skip comments */
59 continue;
60 }
61
62 /* find the property string */
63 if ((str = strstr(buffer, property)) == NULL) {
64 /* didn't find the property string in this line */
65 continue;
66 }
67
68 cursor = strtok(str, "= ;");
69 cursor = strtok(NULL, "= ;");
70 if (cursor == NULL) {
71 cryptoerror(LOG_STDERR, gettext(
72 "Invalid config file contents: %s."), filename);
73 (void) fclose(pfile);
74 return (FAILURE);
75 }
76 *hw_fips_mode = atoi(cursor);
77 (void) fclose(pfile);
78 return (SUCCESS);
79 }
80
81 /*
82 * If the fips property is not found in the config file,
83 * FIPS mode is false by default.
84 */
85 *hw_fips_mode = CRYPTO_FIPS_MODE_DISABLED;
86 (void) fclose(pfile);
87
88 return (SUCCESS);
89 }
90
91 /*
92 * Update the HW .conf file with the updated entry.
93 */
94 int
fips_update_hw_conf(char * filename,char * property,int action)95 fips_update_hw_conf(char *filename, char *property, int action)
96 {
97 FILE *pfile;
98 FILE *pfile_tmp;
99 char buffer[BUFSIZ];
100 char buffer2[BUFSIZ];
101 char *tmpfile_name = NULL;
102 char *str = NULL;
103 char *cursor = NULL;
104 int rc = SUCCESS;
105 boolean_t found = B_FALSE;
106
107 /* Open the .conf file */
108 if ((pfile = fopen(filename, "r+")) == NULL) {
109 cryptoerror(LOG_STDERR,
110 gettext("failed to update the configuration - %s"),
111 strerror(errno));
112 cryptodebug("failed to open %s for write.", filename);
113 return (FAILURE);
114 }
115
116 /* Lock the .conf file */
117 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
118 cryptoerror(LOG_STDERR,
119 gettext("failed to update the configuration - %s"),
120 strerror(errno));
121 cryptodebug(gettext("failed to lock %s"), filename);
122 (void) fclose(pfile);
123 return (FAILURE);
124 }
125
126 /*
127 * Create a temporary file to save updated configuration file first.
128 */
129 tmpfile_name = tempnam(HW_CONF_DIR, NULL);
130 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
131 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
132 tmpfile_name, strerror(errno));
133 free(tmpfile_name);
134 (void) fclose(pfile);
135 return (FAILURE);
136 }
137
138
139 /*
140 * Loop thru entire .conf file, update the entry to be
141 * updated and save the updated file to the temporary file first.
142 */
143 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
144 if (buffer[0] == '#') {
145 /* comments: write to the file without modification */
146 goto write_to_tmp;
147 }
148
149 (void) strlcpy(buffer2, buffer, BUFSIZ);
150
151 /* find the property string */
152 if ((str = strstr(buffer2, property)) == NULL) {
153 /*
154 * Didn't find the property string in this line.
155 * Write to the file without modification.
156 */
157 goto write_to_tmp;
158 }
159
160 found = B_TRUE;
161
162 cursor = strtok(str, "= ;");
163 cursor = strtok(NULL, "= ;");
164 if (cursor == NULL) {
165 cryptoerror(LOG_STDERR, gettext(
166 "Invalid config file contents %s: %s."),
167 filename, strerror(errno));
168 goto errorexit;
169 }
170
171 cursor = buffer + (cursor - buffer2);
172 *cursor = (action == FIPS140_ENABLE) ? '1' : '0';
173
174 write_to_tmp:
175
176 if (fputs(buffer, pfile_tmp) == EOF) {
177 cryptoerror(LOG_STDERR, gettext(
178 "failed to write to a temp file: %s."),
179 strerror(errno));
180 goto errorexit;
181 }
182 }
183
184 /* if the fips mode property is not specified, FALSE by default */
185 if (found == B_FALSE) {
186 (void) snprintf(buffer, BUFSIZ, "%s=%c;\n",
187 property, (action == FIPS140_ENABLE) ? '1' : '0');
188 if (fputs(buffer, pfile_tmp) == EOF) {
189 cryptoerror(LOG_STDERR, gettext(
190 "failed to write to a tmp file: %s."),
191 strerror(errno));
192 goto errorexit;
193 }
194 }
195
196 (void) fclose(pfile);
197 if (fclose(pfile_tmp) != 0) {
198 cryptoerror(LOG_STDERR,
199 gettext("failed to close %s: %s"), tmpfile_name,
200 strerror(errno));
201 free(tmpfile_name);
202 return (FAILURE);
203 }
204
205 /* Copy the temporary file to the .conf file */
206 if (rename(tmpfile_name, filename) == -1) {
207 cryptoerror(LOG_STDERR,
208 gettext("failed to update the configuration - %s"),
209 strerror(errno));
210 cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
211 filename, strerror(errno));
212 rc = FAILURE;
213 } else if (chmod(filename,
214 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
215 cryptoerror(LOG_STDERR,
216 gettext("failed to update the configuration - %s"),
217 strerror(errno));
218 cryptodebug("failed to chmod to %s: %s", filename,
219 strerror(errno));
220 rc = FAILURE;
221 } else {
222 rc = SUCCESS;
223 }
224
225 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
226 cryptoerror(LOG_STDERR, gettext(
227 "(Warning) failed to remove %s: %s"),
228 tmpfile_name, strerror(errno));
229 }
230
231 free(tmpfile_name);
232 return (rc);
233
234 errorexit:
235 (void) fclose(pfile);
236 (void) fclose(pfile_tmp);
237 free(tmpfile_name);
238
239 return (FAILURE);
240 }
241
242
243 /*
244 * Perform the FIPS related actions
245 */
246 int
do_fips_hw_actions(int action,int provider)247 do_fips_hw_actions(int action, int provider)
248 {
249 int rc = SUCCESS;
250 int fips_mode = 0;
251 char *filename;
252 char *propname;
253 char *provname;
254
255 switch (provider) {
256 case HW_PROVIDER_NCP:
257 filename = "/platform/sun4v/kernel/drv/ncp.conf";
258 propname = "ncp-fips-140";
259 provname = "ncp";
260 break;
261 case HW_PROVIDER_N2CP:
262 filename = "/platform/sun4v/kernel/drv/n2cp.conf";
263 propname = "n2cp-fips-140";
264 provname = "n2cp";
265 break;
266 case HW_PROVIDER_N2RNG:
267 filename = "/platform/sun4v/kernel/drv/n2rng.conf";
268 propname = "n2rng-fips-140";
269 provname = "n2rng";
270 break;
271 default:
272 (void) printf(gettext("Internal Error: Invalid HW "
273 "provider [%d] specified.\n"));
274 return (FAILURE);
275 }
276
277 /* Get FIPS-140 status from .conf */
278 if (fips_hw_status(filename, propname, &fips_mode) != SUCCESS) {
279 return (FAILURE);
280 }
281
282 if (action == FIPS140_STATUS) {
283 if (fips_mode == CRYPTO_FIPS_MODE_ENABLED)
284 (void) printf(gettext(
285 "%s: FIPS-140 mode is enabled.\n"), provname);
286 else
287 (void) printf(gettext(
288 "%s: FIPS-140 mode is disabled.\n"), provname);
289 return (SUCCESS);
290 }
291
292 /* Is it a duplicate operation? */
293 if ((action == FIPS140_ENABLE) &&
294 (fips_mode == CRYPTO_FIPS_MODE_ENABLED)) {
295 (void) printf(
296 gettext("%s: FIPS-140 mode has already been enabled.\n"),
297 provname);
298 return (FAILURE);
299 }
300
301 if ((action == FIPS140_DISABLE) &&
302 (fips_mode == CRYPTO_FIPS_MODE_DISABLED)) {
303 (void) printf(
304 gettext("%s: FIPS-140 mode has already been disabled.\n"),
305 provname);
306 return (FAILURE);
307 }
308
309 if ((action == FIPS140_ENABLE) || (action == FIPS140_DISABLE)) {
310 /* Update .conf */
311 if ((rc = fips_update_hw_conf(filename, propname, action))
312 != SUCCESS)
313 return (rc);
314 }
315
316 /* No need to inform kernel */
317 if (action == FIPS140_ENABLE) {
318 (void) printf(gettext(
319 "%s: FIPS-140 mode was enabled successfully.\n"),
320 provname);
321 } else {
322 (void) printf(gettext(
323 "%s: FIPS-140 mode was disabled successfully.\n"),
324 provname);
325 }
326
327 return (SUCCESS);
328 }
329