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 }