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 2008 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 }