xref: /illumos-gate/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_ioctl.c (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
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 {
407 	boolean_t		in_kernel = B_FALSE;
408 	crypto_get_soft_info_t	*psoft_info;
409 	mechlist_t		*phead;
410 	mechlist_t		*pmech;
411 	mechlist_t		*pcur;
412 	entry_t			*pent = NULL;
413 	int			count;
414 	int			fd = -1;
415 	int			rc;
416 	int			i;
417 
418 	if (provname == NULL) {
419 		return (FAILURE);
420 	}
421 
422 	if (getzoneid() == GLOBAL_ZONEID) {
423 		/* use kcf.conf for kernel software providers in global zone */
424 		if ((pent = getent_kef(provname, phardlist, psoftlist)) ==
425 		    NULL) {
426 
427 			/* No kcf.conf entry for this provider */
428 			if (check_kernel_for_soft(provname, NULL, &in_kernel)
429 			    == FAILURE) {
430 				return (FAILURE);
431 			} else if (in_kernel == B_FALSE) {
432 				cryptoerror(LOG_STDERR,
433 				    gettext("%s does not exist."), provname);
434 				return (FAILURE);
435 			}
436 
437 			/*
438 			 * Set mech count to 1.  It will be reset to the
439 			 * correct value later if the setup buffer is too small.
440 			 */
441 			count = 1;
442 		} else {
443 			count = pent->sup_count;
444 			free_entry(pent);
445 		}
446 	} else {
447 		/*
448 		 * kcf.conf not there in non-global zone: set mech count to 1.
449 		 * It will be reset to the correct value later if the setup
450 		 * buffer is too small.
451 		 */
452 		count = 1;
453 	}
454 
455 	if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) {
456 		return (FAILURE);
457 	}
458 
459 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
460 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
461 		    ADMIN_IOCTL_DEVICE, strerror(errno));
462 		free(psoft_info);
463 		return (FAILURE);
464 	}
465 
466 	/* make GET_SOFT_INFO ioctl call */
467 	if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) {
468 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s",
469 		    strerror(errno));
470 		(void) close(fd);
471 		free(psoft_info);
472 		return (FAILURE);
473 	}
474 
475 	/* BUFFER is too small, get the number of mechanisms and retry it. */
476 	if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) {
477 		count = psoft_info->si_count;
478 		free(psoft_info);
479 		if ((psoft_info = setup_get_soft_info(provname, count))
480 		    == NULL) {
481 			(void) close(fd);
482 			return (FAILURE);
483 		} else {
484 			rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info);
485 			if (rc == -1) {
486 				cryptodebug("CRYPTO_GET_SOFT_INFO ioctl "
487 				    "failed: %s", strerror(errno));
488 				(void) close(fd);
489 				free(psoft_info);
490 				return (FAILURE);
491 			}
492 		}
493 	}
494 
495 	(void) close(fd);
496 	if (psoft_info->si_return_value != CRYPTO_SUCCESS) {
497 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, "
498 		    "return_value = %d", psoft_info->si_return_value);
499 		free(psoft_info);
500 		return (FAILURE);
501 	}
502 
503 
504 	/* Build the mechanism linked list and return it */
505 	rc = SUCCESS;
506 	phead = pcur = NULL;
507 	for (i = 0; i < psoft_info->si_count; i++) {
508 		pmech = create_mech(&psoft_info->si_list[i][0]);
509 		if (pmech == NULL) {
510 			rc = FAILURE;
511 			break;
512 		} else {
513 			if (phead == NULL) {
514 				phead = pcur = pmech;
515 			} else {
516 				pcur->next = pmech;
517 				pcur = pmech;
518 			}
519 		}
520 	}
521 
522 	if (rc == FAILURE) {
523 		free_mechlist(phead);
524 	} else {
525 		*ppmechlist = phead;
526 	}
527 
528 	free(psoft_info);
529 	return (rc);
530 }
531 
532 
533 /*
534  * Get the kernel software provider list from kernel.
535  */
536 int
537 get_soft_list(crypto_get_soft_list_t **ppsoftlist)
538 {
539 	crypto_get_soft_list_t *psoftlist = NULL;
540 	int	count = DEFAULT_SOFT_NUM;
541 	int	len;
542 	int	fd = -1;
543 
544 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
545 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
546 		    ADMIN_IOCTL_DEVICE, strerror(errno));
547 		return (FAILURE);
548 	}
549 
550 	len = MAXNAMELEN * count;
551 	psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
552 	if (psoftlist == NULL) {
553 		cryptodebug("out of memory.");
554 		(void) close(fd);
555 		return (FAILURE);
556 	}
557 	psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
558 	psoftlist->sl_soft_count = count;
559 	psoftlist->sl_soft_len = len;
560 
561 	if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
562 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s",
563 		    strerror(errno));
564 		free(psoftlist);
565 		(void) close(fd);
566 		return (FAILURE);
567 	}
568 
569 	/*
570 	 * if BUFFER is too small, get the number of software providers and
571 	 * the minimum length needed for names and length and retry it.
572 	 */
573 	if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) {
574 		count = psoftlist->sl_soft_count;
575 		len = psoftlist->sl_soft_len;
576 		free(psoftlist);
577 		psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
578 		if (psoftlist == NULL) {
579 			cryptodebug("out of memory.");
580 			(void) close(fd);
581 			return (FAILURE);
582 		}
583 		psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
584 		psoftlist->sl_soft_count = count;
585 		psoftlist->sl_soft_len = len;
586 
587 		if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
588 			cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:"
589 			    "%s", strerror(errno));
590 			free(psoftlist);
591 			(void) close(fd);
592 			return (FAILURE);
593 		}
594 	}
595 
596 	if (psoftlist->sl_return_value != CRYPTO_SUCCESS) {
597 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, "
598 		    "return_value = %d", psoftlist->sl_return_value);
599 		free(psoftlist);
600 		(void) close(fd);
601 		return (FAILURE);
602 	}
603 
604 	*ppsoftlist = psoftlist;
605 	(void) close(fd);
606 	return (SUCCESS);
607 }
608 
609 /*
610  * Perform the FIPS related actions
611  */
612 int
613 do_fips_actions(int action, int caller)
614 {
615 
616 	crypto_fips140_t	fips_info;
617 	int	fd;
618 	int	rc = SUCCESS;
619 	int	pkcs11_fips_mode = 0;
620 
621 	/* Get FIPS-140 status from pkcs11.conf */
622 	fips_status_pkcs11conf(&pkcs11_fips_mode);
623 
624 	if (action == FIPS140_STATUS) {
625 		if (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED)
626 			(void) printf(gettext(
627 			    "\tFIPS-140 mode is enabled.\n"));
628 		else
629 			(void) printf(gettext(
630 			    "\tFIPS-140 mode is disabled.\n"));
631 		return (SUCCESS);
632 	}
633 
634 	if (caller == NOT_REFRESH) {
635 		/* Is it a duplicate operation? */
636 		if ((action == FIPS140_ENABLE) &&
637 		    (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED)) {
638 			cryptoerror(LOG_STDERR,
639 			    gettext("FIPS-140 mode has already "
640 			    "been enabled.\n"));
641 			return (FAILURE);
642 		}
643 
644 		if ((action == FIPS140_DISABLE) &&
645 		    (pkcs11_fips_mode == CRYPTO_FIPS_MODE_DISABLED)) {
646 			cryptoerror(LOG_STDERR,
647 			    gettext("FIPS-140 mode has already "
648 			    "been disabled.\n"));
649 			return (FAILURE);
650 		}
651 
652 		if ((action == FIPS140_ENABLE) || (action == FIPS140_DISABLE)) {
653 			/* Update pkcs11.conf */
654 			if ((rc = fips_update_pkcs11conf(action)) != SUCCESS)
655 				return (rc);
656 		}
657 
658 		/* No need to inform kernel */
659 		if (action == FIPS140_ENABLE) {
660 			(void) printf(gettext(
661 			    "FIPS-140 mode was enabled successfully.\n"));
662 			(void) printf(gettext(
663 			    "Warning: In this release, the Cryptographic "
664 			    "Framework has not been FIPS 140-2 "
665 			    "certified.\n\n"));
666 		} else {
667 			(void) printf(gettext(
668 			    "FIPS-140 mode was disabled successfully.\n"));
669 		}
670 
671 		(void) printf(gettext(
672 		    "The FIPS-140 mode has changed.\n"));
673 		(void) printf(gettext(
674 		    "The system will require a reboot.\n\n"));
675 		return (SUCCESS);
676 
677 	}
678 
679 	/* This is refresh, need to inform kernel */
680 	(void) memset(&fips_info, 0, sizeof (crypto_fips140_t));
681 
682 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
683 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
684 		    ADMIN_IOCTL_DEVICE, strerror(errno));
685 		return (FAILURE);
686 	}
687 
688 	switch (action) {
689 	case FIPS140_ENABLE:
690 		/* make CRYPTO_FIPS_SET ioctl call */
691 		fips_info.fips140_op = FIPS140_ENABLE;
692 		if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) {
693 			cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed: %s",
694 			    strerror(errno));
695 			rc = FAILURE;
696 			goto out;
697 		}
698 
699 		if (fips_info.fips140_return_value != CRYPTO_SUCCESS) {
700 			cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed, "
701 			    "return_value = %d",
702 			    fips_info.fips140_return_value);
703 			rc = FAILURE;
704 		}
705 
706 		break;
707 
708 	case FIPS140_DISABLE:
709 		/* make CRYPTO_FIPS140_SET ioctl call */
710 		fips_info.fips140_op = FIPS140_DISABLE;
711 		if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) {
712 			cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed: %s",
713 			    strerror(errno));
714 			rc = FAILURE;
715 			goto out;
716 		}
717 
718 		if (fips_info.fips140_return_value != CRYPTO_SUCCESS) {
719 			cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed, "
720 			    "return_value = %d",
721 			    fips_info.fips140_return_value);
722 			rc = FAILURE;
723 		}
724 
725 		break;
726 
727 	default:
728 		rc = FAILURE;
729 		break;
730 	};
731 
732 out:
733 	(void) close(fd);
734 	return (rc);
735 }
736