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) 2003, 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/varargs.h>
34 #include <zone.h>
35 #include <sys/crypto/ioctladmin.h>
36 #include "cryptoadm.h"
37 
38 #define	DEFAULT_DEV_NUM 5
39 #define	DEFAULT_SOFT_NUM 10
40 
41 #define	NUM_FIPS_SW_PROV	\
42 	(sizeof (fips_sw_providers) / sizeof (char *))
43 
44 static char *fips_sw_providers[] = {
45 	"des",
46 	"aes",
47 	"ecc",
48 	"sha1",
49 	"sha2",
50 	"rsa",
51 	"swrand"
52 };
53 
54 static crypto_get_soft_info_t *setup_get_soft_info(char *, int);
55 
56 static void
57 fips_sw_printf(const char *format, ...)
58 {
59 	va_list	ap;
60 	char	message[1024];
61 	int	i;
62 
63 	va_start(ap, format);
64 	(void) snprintf(message, sizeof (message), format, ap);
65 	va_end(ap);
66 
67 	(void) printf(gettext("\nUser-level providers:\n"));
68 	(void) printf(gettext("=====================\n"));
69 	(void) printf(gettext("/usr/lib/security/$ISA/pkcs11_softtoken: %s\n"),
70 	    message);
71 	(void) printf(gettext("\nKernel software providers:\n"));
72 	(void) printf(gettext("==========================\n"));
73 	for (i = 0; i < NUM_FIPS_SW_PROV; i++) {
74 		(void) printf(gettext("%s: %s\n"),
75 		    fips_sw_providers[i], message);
76 	}
77 }
78 
79 /*
80  * Prepare the argument for the LOAD_SOFT_CONFIG ioctl call for the
81  * provider pointed by pent.  Return NULL if out of memory.
82  */
83 crypto_load_soft_config_t *
84 setup_soft_conf(entry_t *pent)
85 {
86 	crypto_load_soft_config_t	*pload_soft_conf;
87 	mechlist_t	*plist;
88 	uint_t		sup_count;
89 	size_t		extra_mech_size = 0;
90 	int		i;
91 
92 	if (pent == NULL) {
93 		return (NULL);
94 	}
95 
96 	sup_count = pent->sup_count;
97 	if (sup_count > 1) {
98 		extra_mech_size = sizeof (crypto_mech_name_t) *
99 		    (sup_count - 1);
100 	}
101 
102 	pload_soft_conf = malloc(sizeof (crypto_load_soft_config_t) +
103 	    extra_mech_size);
104 	if (pload_soft_conf == NULL) {
105 		cryptodebug("out of memory.");
106 		return (NULL);
107 	}
108 
109 	(void) strlcpy(pload_soft_conf->sc_name, pent->name, MAXNAMELEN);
110 	pload_soft_conf->sc_count = sup_count;
111 
112 	i = 0;
113 	plist =  pent->suplist;
114 	while (i < sup_count) {
115 		(void) strlcpy(pload_soft_conf->sc_list[i++],
116 		    plist->name, CRYPTO_MAX_MECH_NAME);
117 		plist = plist->next;
118 	}
119 
120 	return (pload_soft_conf);
121 }
122 
123 
124 /*
125  * Prepare the argument for the LOAD_SOFT_DISABLED ioctl call for the
126  * provider pointed by pent.  Return NULL if out of memory.
127  */
128 crypto_load_soft_disabled_t *
129 setup_soft_dis(entry_t *pent)
130 {
131 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
132 	mechlist_t	*plist = NULL;
133 	size_t		extra_mech_size = 0;
134 	uint_t		dis_count;
135 	int		i;
136 
137 	if (pent == NULL) {
138 		return (NULL);
139 	}
140 
141 	dis_count = pent->dis_count;
142 	if (dis_count > 1) {
143 		extra_mech_size = sizeof (crypto_mech_name_t) *
144 		    (dis_count - 1);
145 	}
146 
147 	pload_soft_dis = malloc(sizeof (crypto_load_soft_disabled_t) +
148 	    extra_mech_size);
149 	if (pload_soft_dis == NULL) {
150 		cryptodebug("out of memory.");
151 		return (NULL);
152 	}
153 
154 	(void) strlcpy(pload_soft_dis->sd_name, pent->name, MAXNAMELEN);
155 	pload_soft_dis->sd_count = dis_count;
156 
157 	i = 0;
158 	plist =  pent->dislist;
159 	while (i < dis_count) {
160 		(void) strlcpy(pload_soft_dis->sd_list[i++],
161 		    plist->name, CRYPTO_MAX_MECH_NAME);
162 		plist = plist->next;
163 	}
164 
165 	return (pload_soft_dis);
166 }
167 
168 
169 /*
170  * Prepare the argument for the LOAD_DEV_DISABLED ioctl call for the
171  * provider pointed by pent.  Return NULL if out of memory.
172  */
173 crypto_load_dev_disabled_t *
174 setup_dev_dis(entry_t *pent)
175 {
176 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
177 	mechlist_t	*plist = NULL;
178 	size_t		extra_mech_size = 0;
179 	uint_t		dis_count;
180 	int		i;
181 	char		pname[MAXNAMELEN];
182 	int		inst_num;
183 
184 	if (pent == NULL) {
185 		return (NULL);
186 	}
187 
188 	/* get the device name and the instance number */
189 	if (split_hw_provname(pent->name, pname, &inst_num) == FAILURE) {
190 		return (NULL);
191 	}
192 
193 	/* allocate space for pload_dev_des */
194 	dis_count = pent->dis_count;
195 	if (dis_count > 1) {
196 		extra_mech_size = sizeof (crypto_mech_name_t) *
197 		    (dis_count - 1);
198 	}
199 
200 	pload_dev_dis = malloc(sizeof (crypto_load_dev_disabled_t) +
201 	    extra_mech_size);
202 	if (pload_dev_dis == NULL) {
203 		cryptodebug("out of memory.");
204 		return (NULL);
205 	}
206 
207 	/* set the values for pload_dev_dis */
208 	(void) strlcpy(pload_dev_dis->dd_dev_name, pname, MAXNAMELEN);
209 	pload_dev_dis->dd_dev_instance = inst_num;
210 	pload_dev_dis->dd_count = dis_count;
211 
212 	i = 0;
213 	plist =  pent->dislist;
214 	while (i < dis_count) {
215 		(void) strlcpy(pload_dev_dis->dd_list[i++],
216 		    plist->name, CRYPTO_MAX_MECH_NAME);
217 		plist = plist->next;
218 	}
219 
220 	return (pload_dev_dis);
221 }
222 
223 
224 /*
225  * Prepare the calling argument of the UNLOAD_SOFT_MODULE ioctl call for the
226  * provider pointed by pent.  Return NULL if out of memory.
227  */
228 crypto_unload_soft_module_t *
229 setup_unload_soft(entry_t *pent)
230 {
231 	crypto_unload_soft_module_t *punload_soft;
232 
233 	if (pent == NULL) {
234 		return (NULL);
235 	}
236 
237 	punload_soft = malloc(sizeof (crypto_unload_soft_module_t));
238 	if (punload_soft == NULL) {
239 		cryptodebug("out of memory.");
240 		return (NULL);
241 	}
242 
243 	(void) strlcpy(punload_soft->sm_name, pent->name, MAXNAMELEN);
244 
245 	return (punload_soft);
246 }
247 
248 
249 /*
250  * Prepare the calling argument for the GET_SOFT_INFO call for the provider
251  * with the number of mechanisms specified in the second argument.
252  *
253  * Called by get_soft_info().
254  */
255 static crypto_get_soft_info_t *
256 setup_get_soft_info(char *provname, int count)
257 {
258 	crypto_get_soft_info_t	*psoft_info;
259 	size_t			extra_mech_size = 0;
260 
261 	if (provname == NULL) {
262 		return (NULL);
263 	}
264 
265 	if (count > 1) {
266 		extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1);
267 	}
268 
269 	psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size);
270 	if (psoft_info == NULL) {
271 		cryptodebug("out of memory.");
272 		return (NULL);
273 	}
274 
275 	(void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN);
276 	psoft_info->si_count = count;
277 
278 	return (psoft_info);
279 }
280 
281 
282 /*
283  * Get the device list from kernel.
284  */
285 int
286 get_dev_list(crypto_get_dev_list_t **ppdevlist)
287 {
288 	crypto_get_dev_list_t	*pdevlist;
289 	int			fd = -1;
290 	int			count = DEFAULT_DEV_NUM;
291 
292 	pdevlist = malloc(sizeof (crypto_get_dev_list_t) +
293 	    sizeof (crypto_dev_list_entry_t) * (count - 1));
294 	if (pdevlist == NULL) {
295 		cryptodebug("out of memory.");
296 		return (FAILURE);
297 	}
298 
299 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
300 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
301 		    ADMIN_IOCTL_DEVICE, strerror(errno));
302 		return (FAILURE);
303 	}
304 
305 	pdevlist->dl_dev_count = count;
306 	if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) {
307 		cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s",
308 		    strerror(errno));
309 		free(pdevlist);
310 		(void) close(fd);
311 		return (FAILURE);
312 	}
313 
314 	/* BUFFER is too small, get the number of devices and retry it. */
315 	if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) {
316 		count = pdevlist->dl_dev_count;
317 		free(pdevlist);
318 		pdevlist = malloc(sizeof (crypto_get_dev_list_t) +
319 		    sizeof (crypto_dev_list_entry_t) * (count - 1));
320 		if (pdevlist == NULL) {
321 			cryptodebug("out of memory.");
322 			(void) close(fd);
323 			return (FAILURE);
324 		}
325 
326 		if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) {
327 			cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s",
328 			    strerror(errno));
329 			free(pdevlist);
330 			(void) close(fd);
331 			return (FAILURE);
332 		}
333 	}
334 
335 	if (pdevlist->dl_return_value != CRYPTO_SUCCESS) {
336 		cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, "
337 		    "return_value = %d", pdevlist->dl_return_value);
338 		free(pdevlist);
339 		(void) close(fd);
340 		return (FAILURE);
341 	}
342 
343 	*ppdevlist = pdevlist;
344 	(void) close(fd);
345 	return (SUCCESS);
346 }
347 
348 
349 /*
350  * Get all the mechanisms supported by the hardware provider.
351  * The result will be stored in the second argument.
352  */
353 int
354 get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist)
355 {
356 	crypto_get_dev_info_t	*dev_info;
357 	mechlist_t	*phead;
358 	mechlist_t	*pcur;
359 	mechlist_t	*pmech;
360 	int		fd = -1;
361 	int		i;
362 	int		rc;
363 
364 	if (devname == NULL || count < 1) {
365 		cryptodebug("get_dev_info(): devname is NULL or bogus count");
366 		return (FAILURE);
367 	}
368 
369 	/* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */
370 	dev_info = malloc(sizeof (crypto_get_dev_info_t) +
371 	    sizeof (crypto_mech_name_t) * (count - 1));
372 	if (dev_info == NULL) {
373 		cryptodebug("out of memory.");
374 		return (FAILURE);
375 	}
376 	(void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN);
377 	dev_info->di_dev_instance = inst_num;
378 	dev_info->di_count = count;
379 
380 	/* Open the ioctl device */
381 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
382 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
383 		    ADMIN_IOCTL_DEVICE, strerror(errno));
384 		free(dev_info);
385 		return (FAILURE);
386 	}
387 
388 	if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) {
389 		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s",
390 		    strerror(errno));
391 		free(dev_info);
392 		(void) close(fd);
393 		return (FAILURE);
394 	}
395 
396 	if (dev_info->di_return_value != CRYPTO_SUCCESS) {
397 		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, "
398 		    "return_value = %d", dev_info->di_return_value);
399 		free(dev_info);
400 		(void) close(fd);
401 		return (FAILURE);
402 	}
403 
404 	phead = pcur = NULL;
405 	rc = SUCCESS;
406 	for (i = 0; i < dev_info->di_count; i++) {
407 		pmech = create_mech(&dev_info->di_list[i][0]);
408 		if (pmech == NULL) {
409 			rc = FAILURE;
410 			break;
411 		} else {
412 			if (phead == NULL) {
413 				phead = pcur = pmech;
414 			} else {
415 				pcur->next = pmech;
416 				pcur = pmech;
417 			}
418 		}
419 	}
420 
421 	if (rc == SUCCESS) {
422 		*ppmechlist = phead;
423 	} else {
424 		free_mechlist(phead);
425 	}
426 
427 	free(dev_info);
428 	(void) close(fd);
429 	return (rc);
430 }
431 
432 
433 /*
434  * Get the supported mechanism list of the software provider from kernel.
435  *
436  * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
437  * If NULL, this function calls get_kcfconf_info() internally.
438  */
439 int
440 get_soft_info(char *provname, mechlist_t **ppmechlist,
441 	entrylist_t *phardlist, entrylist_t *psoftlist)
442 {
443 	boolean_t		in_kernel = B_FALSE;
444 	crypto_get_soft_info_t	*psoft_info;
445 	mechlist_t		*phead;
446 	mechlist_t		*pmech;
447 	mechlist_t		*pcur;
448 	entry_t			*pent = NULL;
449 	int			count;
450 	int			fd = -1;
451 	int			rc;
452 	int			i;
453 
454 	if (provname == NULL) {
455 		return (FAILURE);
456 	}
457 
458 	if (getzoneid() == GLOBAL_ZONEID) {
459 		/* use kcf.conf for kernel software providers in global zone */
460 		if ((pent = getent_kef(provname, phardlist, psoftlist)) ==
461 		    NULL) {
462 
463 			/* No kcf.conf entry for this provider */
464 			if (check_kernel_for_soft(provname, NULL, &in_kernel)
465 			    == FAILURE) {
466 				return (FAILURE);
467 			} else if (in_kernel == B_FALSE) {
468 				cryptoerror(LOG_STDERR,
469 				    gettext("%s does not exist."), provname);
470 				return (FAILURE);
471 			}
472 
473 			/*
474 			 * Set mech count to 1.  It will be reset to the
475 			 * correct value later if the setup buffer is too small.
476 			 */
477 			count = 1;
478 		} else {
479 			count = pent->sup_count;
480 			free_entry(pent);
481 		}
482 	} else {
483 		/*
484 		 * kcf.conf not there in non-global zone: set mech count to 1.
485 		 * It will be reset to the correct value later if the setup
486 		 * buffer is too small.
487 		 */
488 		count = 1;
489 	}
490 
491 	if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) {
492 		return (FAILURE);
493 	}
494 
495 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
496 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
497 		    ADMIN_IOCTL_DEVICE, strerror(errno));
498 		free(psoft_info);
499 		return (FAILURE);
500 	}
501 
502 	/* make GET_SOFT_INFO ioctl call */
503 	if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) {
504 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s",
505 		    strerror(errno));
506 		(void) close(fd);
507 		free(psoft_info);
508 		return (FAILURE);
509 	}
510 
511 	/* BUFFER is too small, get the number of mechanisms and retry it. */
512 	if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) {
513 		count = psoft_info->si_count;
514 		free(psoft_info);
515 		if ((psoft_info = setup_get_soft_info(provname, count))
516 		    == NULL) {
517 			(void) close(fd);
518 			return (FAILURE);
519 		} else {
520 			rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info);
521 			if (rc == -1) {
522 				cryptodebug("CRYPTO_GET_SOFT_INFO ioctl "
523 				    "failed: %s", strerror(errno));
524 				(void) close(fd);
525 				free(psoft_info);
526 				return (FAILURE);
527 			}
528 		}
529 	}
530 
531 	(void) close(fd);
532 	if (psoft_info->si_return_value != CRYPTO_SUCCESS) {
533 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, "
534 		    "return_value = %d", psoft_info->si_return_value);
535 		free(psoft_info);
536 		return (FAILURE);
537 	}
538 
539 
540 	/* Build the mechanism linked list and return it */
541 	rc = SUCCESS;
542 	phead = pcur = NULL;
543 	for (i = 0; i < psoft_info->si_count; i++) {
544 		pmech = create_mech(&psoft_info->si_list[i][0]);
545 		if (pmech == NULL) {
546 			rc = FAILURE;
547 			break;
548 		} else {
549 			if (phead == NULL) {
550 				phead = pcur = pmech;
551 			} else {
552 				pcur->next = pmech;
553 				pcur = pmech;
554 			}
555 		}
556 	}
557 
558 	if (rc == FAILURE) {
559 		free_mechlist(phead);
560 	} else {
561 		*ppmechlist = phead;
562 	}
563 
564 	free(psoft_info);
565 	return (rc);
566 }
567 
568 
569 /*
570  * Get the kernel software provider list from kernel.
571  */
572 int
573 get_soft_list(crypto_get_soft_list_t **ppsoftlist)
574 {
575 	crypto_get_soft_list_t *psoftlist = NULL;
576 	int	count = DEFAULT_SOFT_NUM;
577 	int	len;
578 	int	fd = -1;
579 
580 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
581 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
582 		    ADMIN_IOCTL_DEVICE, strerror(errno));
583 		return (FAILURE);
584 	}
585 
586 	len = MAXNAMELEN * count;
587 	psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
588 	if (psoftlist == NULL) {
589 		cryptodebug("out of memory.");
590 		(void) close(fd);
591 		return (FAILURE);
592 	}
593 	psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
594 	psoftlist->sl_soft_count = count;
595 	psoftlist->sl_soft_len = len;
596 
597 	if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
598 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s",
599 		    strerror(errno));
600 		free(psoftlist);
601 		(void) close(fd);
602 		return (FAILURE);
603 	}
604 
605 	/*
606 	 * if BUFFER is too small, get the number of software providers and
607 	 * the minimum length needed for names and length and retry it.
608 	 */
609 	if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) {
610 		count = psoftlist->sl_soft_count;
611 		len = psoftlist->sl_soft_len;
612 		free(psoftlist);
613 		psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
614 		if (psoftlist == NULL) {
615 			cryptodebug("out of memory.");
616 			(void) close(fd);
617 			return (FAILURE);
618 		}
619 		psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
620 		psoftlist->sl_soft_count = count;
621 		psoftlist->sl_soft_len = len;
622 
623 		if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
624 			cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:"
625 			    "%s", strerror(errno));
626 			free(psoftlist);
627 			(void) close(fd);
628 			return (FAILURE);
629 		}
630 	}
631 
632 	if (psoftlist->sl_return_value != CRYPTO_SUCCESS) {
633 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, "
634 		    "return_value = %d", psoftlist->sl_return_value);
635 		free(psoftlist);
636 		(void) close(fd);
637 		return (FAILURE);
638 	}
639 
640 	*ppsoftlist = psoftlist;
641 	(void) close(fd);
642 	return (SUCCESS);
643 }
644 
645 /*
646  * Perform the FIPS related actions
647  */
648 int
649 do_fips_actions(int action, int caller)
650 {
651 
652 	crypto_fips140_t	fips_info;
653 	int	fd;
654 	int	rc = SUCCESS;
655 	int	pkcs11_fips_mode = 0;
656 
657 	/* Get FIPS-140 status from pkcs11.conf */
658 	fips_status_pkcs11conf(&pkcs11_fips_mode);
659 
660 	if (action == FIPS140_STATUS) {
661 		if (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED)
662 			fips_sw_printf(gettext("FIPS-140 mode is enabled."));
663 		else
664 			fips_sw_printf(gettext("FIPS-140 mode is disabled."));
665 		return (SUCCESS);
666 	}
667 
668 	if (caller == NOT_REFRESH) {
669 		/* Is it a duplicate operation? */
670 		if ((action == FIPS140_ENABLE) &&
671 		    (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED)) {
672 			fips_sw_printf(gettext("FIPS-140 mode has already "
673 			    "been enabled."));
674 			return (FAILURE);
675 		}
676 
677 		if ((action == FIPS140_DISABLE) &&
678 		    (pkcs11_fips_mode == CRYPTO_FIPS_MODE_DISABLED)) {
679 			fips_sw_printf(gettext("FIPS-140 mode has already "
680 			    "been disabled."));
681 			return (FAILURE);
682 		}
683 
684 		if ((action == FIPS140_ENABLE) || (action == FIPS140_DISABLE)) {
685 			/* Update pkcs11.conf */
686 			if ((rc = fips_update_pkcs11conf(action)) != SUCCESS)
687 				return (rc);
688 		}
689 
690 		/* No need to inform kernel */
691 		if (action == FIPS140_ENABLE) {
692 			fips_sw_printf(gettext("FIPS-140 mode was enabled "
693 			    "successfully."));
694 		} else {
695 			fips_sw_printf(gettext("FIPS-140 mode was disabled "
696 			    "successfully."));
697 		}
698 
699 		return (SUCCESS);
700 
701 	}
702 
703 	/* This is refresh, need to inform kernel */
704 	(void) memset(&fips_info, 0, sizeof (crypto_fips140_t));
705 
706 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
707 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
708 		    ADMIN_IOCTL_DEVICE, strerror(errno));
709 		return (FAILURE);
710 	}
711 
712 	switch (action) {
713 	case FIPS140_ENABLE:
714 		/* make CRYPTO_FIPS_SET ioctl call */
715 		fips_info.fips140_op = FIPS140_ENABLE;
716 		if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) {
717 			cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed: %s",
718 			    strerror(errno));
719 			rc = FAILURE;
720 			goto out;
721 		}
722 
723 		if (fips_info.fips140_return_value != CRYPTO_SUCCESS) {
724 			cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed, "
725 			    "return_value = %d",
726 			    fips_info.fips140_return_value);
727 			rc = FAILURE;
728 		}
729 
730 		break;
731 
732 	case FIPS140_DISABLE:
733 		/* make CRYPTO_FIPS140_SET ioctl call */
734 		fips_info.fips140_op = FIPS140_DISABLE;
735 		if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) {
736 			cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed: %s",
737 			    strerror(errno));
738 			rc = FAILURE;
739 			goto out;
740 		}
741 
742 		if (fips_info.fips140_return_value != CRYPTO_SUCCESS) {
743 			cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed, "
744 			    "return_value = %d",
745 			    fips_info.fips140_return_value);
746 			rc = FAILURE;
747 		}
748 
749 		break;
750 
751 	default:
752 		rc = FAILURE;
753 		break;
754 	};
755 
756 out:
757 	(void) close(fd);
758 	return (rc);
759 }
760