xref: /titanic_50/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_ioctl.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <locale.h>
35 #include <libgen.h>
36 #include <sys/types.h>
37 #include <zone.h>
38 #include <sys/crypto/ioctladmin.h>
39 #include "cryptoadm.h"
40 
41 #define	DEFAULT_DEV_NUM 5
42 #define	DEFAULT_SOFT_NUM 10
43 
44 static crypto_get_soft_info_t *setup_get_soft_info(char *, int);
45 
46 /*
47  * Prepare the argument for the LOAD_SOFT_CONFIG ioctl call for the
48  * provider pointed by pent.  Return NULL if out of memory.
49  */
50 crypto_load_soft_config_t *
51 setup_soft_conf(entry_t *pent)
52 {
53 	crypto_load_soft_config_t	*pload_soft_conf;
54 	mechlist_t	*plist;
55 	uint_t	sup_count;
56 	size_t	extra_mech_size = 0;
57 	int	i;
58 
59 	if (pent == NULL) {
60 		return (NULL);
61 	}
62 
63 	sup_count = pent->sup_count;
64 	if (sup_count > 1) {
65 		extra_mech_size = sizeof (crypto_mech_name_t) *
66 		    (sup_count - 1);
67 	}
68 
69 	pload_soft_conf = malloc(sizeof (crypto_load_soft_config_t) +
70 	    extra_mech_size);
71 	if (pload_soft_conf == NULL) {
72 		cryptodebug("out of memory.");
73 		return (NULL);
74 	}
75 
76 	(void) strlcpy(pload_soft_conf->sc_name, pent->name, MAXNAMELEN);
77 	pload_soft_conf->sc_count = sup_count;
78 
79 	i = 0;
80 	plist =  pent->suplist;
81 	while (i < sup_count) {
82 		(void) strlcpy(pload_soft_conf->sc_list[i++],
83 		    plist->name, CRYPTO_MAX_MECH_NAME);
84 		plist = plist->next;
85 	}
86 
87 	return (pload_soft_conf);
88 }
89 
90 
91 /*
92  * Prepare the argument for the LOAD_SOFT_DISABLED ioctl call for the
93  * provider pointed by pent.  Return NULL if out of memory.
94  */
95 crypto_load_soft_disabled_t *
96 setup_soft_dis(entry_t *pent)
97 {
98 	crypto_load_soft_disabled_t	*pload_soft_dis;
99 	mechlist_t	*plist;
100 	size_t	extra_mech_size = 0;
101 	uint_t	dis_count;
102 	int	i;
103 
104 	if (pent == NULL) {
105 		return (NULL);
106 	}
107 
108 	dis_count = pent->dis_count;
109 	if (dis_count > 1) {
110 		extra_mech_size = sizeof (crypto_mech_name_t) *
111 		    (dis_count - 1);
112 	}
113 
114 	pload_soft_dis = malloc(sizeof (crypto_load_soft_disabled_t) +
115 	    extra_mech_size);
116 	if (pload_soft_dis == NULL) {
117 		cryptodebug("out of memory.");
118 		return (NULL);
119 	}
120 
121 	(void) strlcpy(pload_soft_dis->sd_name, pent->name, MAXNAMELEN);
122 	pload_soft_dis->sd_count = dis_count;
123 
124 	i = 0;
125 	plist =  pent->dislist;
126 	while (i < dis_count) {
127 		(void) strlcpy(pload_soft_dis->sd_list[i++],
128 		    plist->name, CRYPTO_MAX_MECH_NAME);
129 		plist = plist->next;
130 	}
131 
132 	return (pload_soft_dis);
133 }
134 
135 
136 /*
137  * Prepare the argument for the LOAD_DEV_DISABLED ioctl call for the
138  * provider pointed by pent.  Return NULL if out of memory.
139  */
140 crypto_load_dev_disabled_t *
141 setup_dev_dis(entry_t *pent)
142 {
143 	crypto_load_dev_disabled_t	*pload_dev_dis;
144 	mechlist_t	*plist;
145 	size_t	extra_mech_size = 0;
146 	uint_t	dis_count;
147 	int	i;
148 	char 	pname[MAXNAMELEN];
149 	int	inst_num;
150 
151 	if (pent == NULL) {
152 		return (NULL);
153 	}
154 
155 	/* get the device name and the instance number */
156 	if (split_hw_provname(pent->name, pname, &inst_num) == FAILURE) {
157 		return (NULL);
158 	}
159 
160 	/* allocate space for pload_dev_des */
161 	dis_count = pent->dis_count;
162 	if (dis_count > 1) {
163 		extra_mech_size = sizeof (crypto_mech_name_t) *
164 		    (dis_count - 1);
165 	}
166 
167 	pload_dev_dis = malloc(sizeof (crypto_load_dev_disabled_t) +
168 	    extra_mech_size);
169 	if (pload_dev_dis == NULL) {
170 		cryptodebug("out of memory.");
171 		return (NULL);
172 	}
173 
174 	/* set the values for pload_dev_dis */
175 	(void) strlcpy(pload_dev_dis->dd_dev_name, pname, MAXNAMELEN);
176 	pload_dev_dis->dd_dev_instance = inst_num;
177 	pload_dev_dis->dd_count = dis_count;
178 
179 	i = 0;
180 	plist =  pent->dislist;
181 	while (i < dis_count) {
182 		(void) strlcpy(pload_dev_dis->dd_list[i++],
183 		    plist->name, CRYPTO_MAX_MECH_NAME);
184 		plist = plist->next;
185 	}
186 
187 	return (pload_dev_dis);
188 }
189 
190 
191 /*
192  * Prepare the calling argument of the UNLOAD_SOFT_MODULE ioctl call for the
193  * provider pointed by pent.  Return NULL if out of memory.
194  */
195 crypto_unload_soft_module_t *
196 setup_unload_soft(entry_t *pent)
197 {
198 	crypto_unload_soft_module_t *punload_soft;
199 
200 	if (pent == NULL) {
201 		return (NULL);
202 	}
203 
204 	punload_soft = malloc(sizeof (crypto_unload_soft_module_t));
205 	if (punload_soft == NULL) {
206 		cryptodebug("out of memory.");
207 		return (NULL);
208 	}
209 
210 	(void) strlcpy(punload_soft->sm_name, pent->name, MAXNAMELEN);
211 
212 	return (punload_soft);
213 }
214 
215 
216 /*
217  * Prepare the calling argument for the GET_SOFT_INFO call for the provider
218  * with the number of mechanisms specified in the second argument.
219  */
220 static crypto_get_soft_info_t *
221 setup_get_soft_info(char *provname, int count)
222 {
223 	crypto_get_soft_info_t *psoft_info;
224 	size_t extra_mech_size = 0;
225 
226 	if (provname == NULL) {
227 		return (NULL);
228 	}
229 
230 	if (count > 1) {
231 		extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1);
232 	}
233 
234 	psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size);
235 	if (psoft_info == NULL) {
236 		cryptodebug("out of memory.");
237 		return (NULL);
238 	}
239 
240 	(void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN);
241 	psoft_info->si_count = count;
242 
243 	return (psoft_info);
244 }
245 
246 
247 /*
248  * Get the device list from kernel.
249  */
250 int
251 get_dev_list(crypto_get_dev_list_t **ppdevlist)
252 {
253 	crypto_get_dev_list_t *pdevlist;
254 	int fd;
255 	int count = DEFAULT_DEV_NUM;
256 
257 	pdevlist = malloc(sizeof (crypto_get_dev_list_t) +
258 	    sizeof (crypto_dev_list_entry_t) * (count - 1));
259 	if (pdevlist == NULL) {
260 		cryptodebug("out of memory.");
261 		return (FAILURE);
262 	}
263 
264 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
265 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
266 		    ADMIN_IOCTL_DEVICE, strerror(errno));
267 		return (FAILURE);
268 	}
269 
270 	pdevlist->dl_dev_count = count;
271 	if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) {
272 		cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s",
273 		    strerror(errno));
274 		free(pdevlist);
275 		(void) close(fd);
276 		return (FAILURE);
277 	}
278 
279 	/* BUFFER is too small, get the number of devices and retry it. */
280 	if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) {
281 		count = pdevlist->dl_dev_count;
282 		free(pdevlist);
283 		pdevlist = malloc(sizeof (crypto_get_dev_list_t) +
284 		    sizeof (crypto_dev_list_entry_t) * (count - 1));
285 		if (pdevlist == NULL) {
286 			cryptodebug("out of memory.");
287 			(void) close(fd);
288 			return (FAILURE);
289 		}
290 
291 		if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) {
292 			cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s",
293 			    strerror(errno));
294 			free(pdevlist);
295 			(void) close(fd);
296 			return (FAILURE);
297 		}
298 	}
299 
300 	if (pdevlist->dl_return_value != CRYPTO_SUCCESS) {
301 		cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, "
302 		    "return_value = %d", pdevlist->dl_return_value);
303 		free(pdevlist);
304 		(void) close(fd);
305 		return (FAILURE);
306 	}
307 
308 	*ppdevlist = pdevlist;
309 	(void) close(fd);
310 	return (SUCCESS);
311 }
312 
313 
314 /*
315  * Get all the mechanisms supported by the hardware provider.
316  * The result will be stored in the second argument.
317  */
318 int
319 get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist)
320 {
321 	crypto_get_dev_info_t *dev_info;
322 	mechlist_t *phead;
323 	mechlist_t *pcur;
324 	mechlist_t *pmech;
325 	int fd;
326 	int i;
327 	int rc;
328 
329 	if (devname == NULL || count < 1) {
330 		cryptodebug("get_dev_info(): devname is NULL or bogus count");
331 		return (FAILURE);
332 	}
333 
334 	/* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */
335 	dev_info = malloc(sizeof (crypto_get_dev_info_t) +
336 	    sizeof (crypto_mech_name_t) * (count - 1));
337 	if (dev_info == NULL) {
338 		cryptodebug("out of memory.");
339 		return (FAILURE);
340 	}
341 	(void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN);
342 	dev_info->di_dev_instance = inst_num;
343 	dev_info->di_count = count;
344 
345 	/* Open the ioctl device */
346 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
347 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
348 		    ADMIN_IOCTL_DEVICE, strerror(errno));
349 		free(dev_info);
350 		return (FAILURE);
351 	}
352 
353 	if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) {
354 		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s",
355 		    strerror(errno));
356 		free(dev_info);
357 		(void) close(fd);
358 		return (FAILURE);
359 	}
360 
361 	if (dev_info->di_return_value != CRYPTO_SUCCESS) {
362 		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, "
363 		    "return_value = %d", dev_info->di_return_value);
364 		free(dev_info);
365 		(void) close(fd);
366 		return (FAILURE);
367 	}
368 
369 	phead = pcur = NULL;
370 	rc = SUCCESS;
371 	for (i = 0; i < dev_info->di_count; i++) {
372 		pmech = create_mech(&dev_info->di_list[i][0]);
373 		if (pmech == NULL) {
374 			rc = FAILURE;
375 			break;
376 		} else {
377 			if (phead == NULL) {
378 				phead = pcur = pmech;
379 			} else {
380 				pcur->next = pmech;
381 				pcur = pmech;
382 			}
383 		}
384 	}
385 
386 	if (rc == SUCCESS) {
387 		*ppmechlist = phead;
388 	} else {
389 		free_mechlist(phead);
390 	}
391 
392 	free(dev_info);
393 	(void) close(fd);
394 	return (rc);
395 }
396 
397 
398 
399 /*
400  * Get the supported mechanism list of the software provider from kernel.
401  */
402 int
403 get_soft_info(char *provname, mechlist_t **ppmechlist)
404 {
405 	crypto_get_soft_info_t	*psoft_info;
406 	mechlist_t	*phead;
407 	mechlist_t	*pmech;
408 	mechlist_t	*pcur;
409 	entry_t	*pent;
410 	int	count;
411 	int	fd;
412 	int	rc;
413 	int	i;
414 
415 	if (provname == NULL) {
416 		return (FAILURE);
417 	}
418 
419 	if (getzoneid() == GLOBAL_ZONEID) {
420 		/* use kcf.conf for kernel software providers in global zone */
421 		if ((pent = getent_kef(provname)) == NULL) {
422 			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
423 			    provname);
424 			return (FAILURE);
425 		}
426 		count = pent->sup_count;
427 		free_entry(pent);
428 	} else {
429 		/*
430 		 * kcf.conf not there in non-global zone, set mech count to 1;
431 		 * it will be reset to the correct value later if the setup
432 		 * buffer is too small
433 		 */
434 		count = 1;
435 	}
436 
437 	if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) {
438 		return (FAILURE);
439 	}
440 
441 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
442 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
443 		    ADMIN_IOCTL_DEVICE, strerror(errno));
444 		free(psoft_info);
445 		return (FAILURE);
446 	}
447 
448 	/* make GET_SOFT_INFO ioctl call */
449 	if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) {
450 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s",
451 		    strerror(errno));
452 		(void) close(fd);
453 		free(psoft_info);
454 		return (FAILURE);
455 	}
456 
457 	/* BUFFER is too small, get the number of mechanisms and retry it. */
458 	if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) {
459 		count = psoft_info->si_count;
460 		free(psoft_info);
461 		if ((psoft_info = setup_get_soft_info(provname, count))
462 		    == NULL) {
463 			(void) close(fd);
464 			return (FAILURE);
465 		} else {
466 			rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info);
467 			if (rc == -1) {
468 				cryptodebug("CRYPTO_GET_SOFT_INFO ioctl "
469 				    "failed: %s", strerror(errno));
470 				(void) close(fd);
471 				free(psoft_info);
472 				return (FAILURE);
473 			}
474 		}
475 	}
476 
477 	(void) close(fd);
478 	if (psoft_info->si_return_value != CRYPTO_SUCCESS) {
479 		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, "
480 		    "return_value = %d", psoft_info->si_return_value);
481 		free(psoft_info);
482 		return (FAILURE);
483 	}
484 
485 
486 	/* Get the mechanism list and return it */
487 	rc = SUCCESS;
488 	phead = pcur = NULL;
489 	for (i = 0; i < psoft_info->si_count; i++) {
490 		pmech = create_mech(&psoft_info->si_list[i][0]);
491 		if (pmech == NULL) {
492 			rc = FAILURE;
493 			break;
494 		} else {
495 			if (phead == NULL) {
496 				phead = pcur = pmech;
497 			} else {
498 				pcur->next = pmech;
499 				pcur = pmech;
500 			}
501 		}
502 	}
503 
504 	if (rc == FAILURE) {
505 		free_mechlist(phead);
506 	} else {
507 		*ppmechlist = phead;
508 	}
509 
510 	free(psoft_info);
511 	return (rc);
512 }
513 
514 
515 /*
516  * Get the kernel software provider list from kernel.
517  */
518 int
519 get_soft_list(crypto_get_soft_list_t **ppsoftlist)
520 {
521 	crypto_get_soft_list_t *psoftlist = NULL;
522 	int count = DEFAULT_SOFT_NUM;
523 	int len;
524 	int fd;
525 
526 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
527 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
528 		    ADMIN_IOCTL_DEVICE, strerror(errno));
529 		return (FAILURE);
530 	}
531 
532 	len = MAXNAMELEN * count;
533 	psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
534 	if (psoftlist == NULL) {
535 		cryptodebug("out of memory.");
536 		(void) close(fd);
537 		return (FAILURE);
538 	}
539 	psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
540 	psoftlist->sl_soft_count = count;
541 	psoftlist->sl_soft_len = len;
542 
543 	if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
544 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s",
545 		    strerror(errno));
546 		free(psoftlist);
547 		(void) close(fd);
548 		return (FAILURE);
549 	}
550 
551 	/*
552 	 * if BUFFER is too small, get the number of software providers and
553 	 * the minimum length needed for names and length and retry it.
554 	 */
555 	if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) {
556 		count = psoftlist->sl_soft_count;
557 		len = psoftlist->sl_soft_len;
558 		free(psoftlist);
559 		psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len);
560 		if (psoftlist == NULL) {
561 			cryptodebug("out of memory.");
562 			(void) close(fd);
563 			return (FAILURE);
564 		}
565 		psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1);
566 		psoftlist->sl_soft_count = count;
567 		psoftlist->sl_soft_len = len;
568 
569 		if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) {
570 			cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:"
571 			    "%s", strerror(errno));
572 			free(psoftlist);
573 			(void) close(fd);
574 			return (FAILURE);
575 		}
576 	}
577 
578 	if (psoftlist->sl_return_value != CRYPTO_SUCCESS) {
579 		cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, "
580 		    "return_value = %d", psoftlist->sl_return_value);
581 		free(psoftlist);
582 		(void) close(fd);
583 		return (FAILURE);
584 	}
585 
586 	*ppsoftlist = psoftlist;
587 	(void) close(fd);
588 	return (SUCCESS);
589 }
590