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