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