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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 /* 25 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <strings.h> 32 #include <unistd.h> 33 #include <locale.h> 34 #include <libgen.h> 35 #include <sys/types.h> 36 #include <sys/varargs.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 = NULL; 99 mechlist_t *plist = NULL; 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 = NULL; 144 mechlist_t *plist = NULL; 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 * Called by get_soft_info(). 221 */ 222 static crypto_get_soft_info_t * 223 setup_get_soft_info(char *provname, int count) 224 { 225 crypto_get_soft_info_t *psoft_info; 226 size_t extra_mech_size = 0; 227 228 if (provname == NULL) { 229 return (NULL); 230 } 231 232 if (count > 1) { 233 extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1); 234 } 235 236 psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size); 237 if (psoft_info == NULL) { 238 cryptodebug("out of memory."); 239 return (NULL); 240 } 241 242 (void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN); 243 psoft_info->si_count = count; 244 245 return (psoft_info); 246 } 247 248 249 /* 250 * Get the device list from kernel. 251 */ 252 int 253 get_dev_list(crypto_get_dev_list_t **ppdevlist) 254 { 255 crypto_get_dev_list_t *pdevlist; 256 int fd = -1; 257 int count = DEFAULT_DEV_NUM; 258 259 pdevlist = malloc(sizeof (crypto_get_dev_list_t) + 260 sizeof (crypto_dev_list_entry_t) * (count - 1)); 261 if (pdevlist == NULL) { 262 cryptodebug("out of memory."); 263 return (FAILURE); 264 } 265 266 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 267 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 268 ADMIN_IOCTL_DEVICE, strerror(errno)); 269 return (FAILURE); 270 } 271 272 pdevlist->dl_dev_count = count; 273 if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { 274 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", 275 strerror(errno)); 276 free(pdevlist); 277 (void) close(fd); 278 return (FAILURE); 279 } 280 281 /* BUFFER is too small, get the number of devices and retry it. */ 282 if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) { 283 count = pdevlist->dl_dev_count; 284 free(pdevlist); 285 pdevlist = malloc(sizeof (crypto_get_dev_list_t) + 286 sizeof (crypto_dev_list_entry_t) * (count - 1)); 287 if (pdevlist == NULL) { 288 cryptodebug("out of memory."); 289 (void) close(fd); 290 return (FAILURE); 291 } 292 293 if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { 294 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", 295 strerror(errno)); 296 free(pdevlist); 297 (void) close(fd); 298 return (FAILURE); 299 } 300 } 301 302 if (pdevlist->dl_return_value != CRYPTO_SUCCESS) { 303 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, " 304 "return_value = %d", pdevlist->dl_return_value); 305 free(pdevlist); 306 (void) close(fd); 307 return (FAILURE); 308 } 309 310 *ppdevlist = pdevlist; 311 (void) close(fd); 312 return (SUCCESS); 313 } 314 315 316 /* 317 * Get all the mechanisms supported by the hardware provider. 318 * The result will be stored in the second argument. 319 */ 320 int 321 get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist) 322 { 323 crypto_get_dev_info_t *dev_info; 324 mechlist_t *phead; 325 mechlist_t *pcur; 326 mechlist_t *pmech; 327 int fd = -1; 328 int i; 329 int rc; 330 331 if (devname == NULL || count < 1) { 332 cryptodebug("get_dev_info(): devname is NULL or bogus count"); 333 return (FAILURE); 334 } 335 336 /* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */ 337 dev_info = malloc(sizeof (crypto_get_dev_info_t) + 338 sizeof (crypto_mech_name_t) * (count - 1)); 339 if (dev_info == NULL) { 340 cryptodebug("out of memory."); 341 return (FAILURE); 342 } 343 (void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN); 344 dev_info->di_dev_instance = inst_num; 345 dev_info->di_count = count; 346 347 /* Open the ioctl device */ 348 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 349 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 350 ADMIN_IOCTL_DEVICE, strerror(errno)); 351 free(dev_info); 352 return (FAILURE); 353 } 354 355 if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) { 356 cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s", 357 strerror(errno)); 358 free(dev_info); 359 (void) close(fd); 360 return (FAILURE); 361 } 362 363 if (dev_info->di_return_value != CRYPTO_SUCCESS) { 364 cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, " 365 "return_value = %d", dev_info->di_return_value); 366 free(dev_info); 367 (void) close(fd); 368 return (FAILURE); 369 } 370 371 phead = pcur = NULL; 372 rc = SUCCESS; 373 for (i = 0; i < dev_info->di_count; i++) { 374 pmech = create_mech(&dev_info->di_list[i][0]); 375 if (pmech == NULL) { 376 rc = FAILURE; 377 break; 378 } else { 379 if (phead == NULL) { 380 phead = pcur = pmech; 381 } else { 382 pcur->next = pmech; 383 pcur = pmech; 384 } 385 } 386 } 387 388 if (rc == SUCCESS) { 389 *ppmechlist = phead; 390 } else { 391 free_mechlist(phead); 392 } 393 394 free(dev_info); 395 (void) close(fd); 396 return (rc); 397 } 398 399 400 /* 401 * Get the supported mechanism list of the software provider from kernel. 402 * 403 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). 404 * If NULL, this function calls get_kcfconf_info() internally. 405 */ 406 int 407 get_soft_info(char *provname, mechlist_t **ppmechlist, 408 entrylist_t *phardlist, entrylist_t *psoftlist) 409 { 410 boolean_t in_kernel = B_FALSE; 411 crypto_get_soft_info_t *psoft_info; 412 mechlist_t *phead; 413 mechlist_t *pmech; 414 mechlist_t *pcur; 415 entry_t *pent = NULL; 416 int count; 417 int fd = -1; 418 int rc; 419 int i; 420 421 if (provname == NULL) { 422 return (FAILURE); 423 } 424 425 if (getzoneid() == GLOBAL_ZONEID) { 426 /* use kcf.conf for kernel software providers in global zone */ 427 if ((pent = getent_kef(provname, phardlist, psoftlist)) == 428 NULL) { 429 430 /* No kcf.conf entry for this provider */ 431 if (check_kernel_for_soft(provname, NULL, &in_kernel) 432 == FAILURE) { 433 return (FAILURE); 434 } else if (in_kernel == B_FALSE) { 435 cryptoerror(LOG_STDERR, 436 gettext("%s does not exist."), provname); 437 return (FAILURE); 438 } 439 440 /* 441 * Set mech count to 1. It will be reset to the 442 * correct value later if the setup buffer is too small. 443 */ 444 count = 1; 445 } else { 446 count = pent->sup_count; 447 free_entry(pent); 448 } 449 } else { 450 /* 451 * kcf.conf not there in non-global zone: set mech count to 1. 452 * It will be reset to the correct value later if the setup 453 * buffer is too small. 454 */ 455 count = 1; 456 } 457 458 if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { 459 return (FAILURE); 460 } 461 462 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 463 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 464 ADMIN_IOCTL_DEVICE, strerror(errno)); 465 free(psoft_info); 466 return (FAILURE); 467 } 468 469 /* make GET_SOFT_INFO ioctl call */ 470 if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) { 471 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s", 472 strerror(errno)); 473 (void) close(fd); 474 free(psoft_info); 475 return (FAILURE); 476 } 477 478 /* BUFFER is too small, get the number of mechanisms and retry it. */ 479 if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) { 480 count = psoft_info->si_count; 481 free(psoft_info); 482 if ((psoft_info = setup_get_soft_info(provname, count)) 483 == NULL) { 484 (void) close(fd); 485 return (FAILURE); 486 } else { 487 rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info); 488 if (rc == -1) { 489 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl " 490 "failed: %s", strerror(errno)); 491 (void) close(fd); 492 free(psoft_info); 493 return (FAILURE); 494 } 495 } 496 } 497 498 (void) close(fd); 499 if (psoft_info->si_return_value != CRYPTO_SUCCESS) { 500 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, " 501 "return_value = %d", psoft_info->si_return_value); 502 free(psoft_info); 503 return (FAILURE); 504 } 505 506 507 /* Build the mechanism linked list and return it */ 508 rc = SUCCESS; 509 phead = pcur = NULL; 510 for (i = 0; i < psoft_info->si_count; i++) { 511 pmech = create_mech(&psoft_info->si_list[i][0]); 512 if (pmech == NULL) { 513 rc = FAILURE; 514 break; 515 } else { 516 if (phead == NULL) { 517 phead = pcur = pmech; 518 } else { 519 pcur->next = pmech; 520 pcur = pmech; 521 } 522 } 523 } 524 525 if (rc == FAILURE) { 526 free_mechlist(phead); 527 } else { 528 *ppmechlist = phead; 529 } 530 531 free(psoft_info); 532 return (rc); 533 } 534 535 536 /* 537 * Get the kernel software provider list from kernel. 538 */ 539 int 540 get_soft_list(crypto_get_soft_list_t **ppsoftlist) 541 { 542 crypto_get_soft_list_t *psoftlist = NULL; 543 int count = DEFAULT_SOFT_NUM; 544 int len; 545 int fd = -1; 546 547 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 548 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 549 ADMIN_IOCTL_DEVICE, strerror(errno)); 550 return (FAILURE); 551 } 552 553 len = MAXNAMELEN * count; 554 psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); 555 if (psoftlist == NULL) { 556 cryptodebug("out of memory."); 557 (void) close(fd); 558 return (FAILURE); 559 } 560 psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); 561 psoftlist->sl_soft_count = count; 562 psoftlist->sl_soft_len = len; 563 564 if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { 565 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s", 566 strerror(errno)); 567 free(psoftlist); 568 (void) close(fd); 569 return (FAILURE); 570 } 571 572 /* 573 * if BUFFER is too small, get the number of software providers and 574 * the minimum length needed for names and length and retry it. 575 */ 576 if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) { 577 count = psoftlist->sl_soft_count; 578 len = psoftlist->sl_soft_len; 579 free(psoftlist); 580 psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); 581 if (psoftlist == NULL) { 582 cryptodebug("out of memory."); 583 (void) close(fd); 584 return (FAILURE); 585 } 586 psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); 587 psoftlist->sl_soft_count = count; 588 psoftlist->sl_soft_len = len; 589 590 if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { 591 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:" 592 "%s", strerror(errno)); 593 free(psoftlist); 594 (void) close(fd); 595 return (FAILURE); 596 } 597 } 598 599 if (psoftlist->sl_return_value != CRYPTO_SUCCESS) { 600 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, " 601 "return_value = %d", psoftlist->sl_return_value); 602 free(psoftlist); 603 (void) close(fd); 604 return (FAILURE); 605 } 606 607 *ppsoftlist = psoftlist; 608 (void) close(fd); 609 return (SUCCESS); 610 } 611