xref: /onnv-gate/usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c (revision 12929:f2051cc42292)
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