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 }