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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * The ioctl interface for administrative commands.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/modctl.h>
  33 #include <sys/conf.h>
  34 #include <sys/stat.h>
  35 #include <sys/ddi.h>
  36 #include <sys/sunddi.h>
  37 #include <sys/kmem.h>
  38 #include <sys/errno.h>
  39 #include <sys/ksynch.h>
  40 #include <sys/file.h>
  41 #include <sys/open.h>
  42 #include <sys/cred.h>
  43 #include <sys/model.h>
  44 #include <sys/sysmacros.h>
  45 #include <sys/crypto/common.h>
  46 #include <sys/crypto/api.h>
  47 #include <sys/crypto/impl.h>
  48 #include <sys/crypto/sched_impl.h>
  49 #include <sys/crypto/ioctladmin.h>
  50 #include <c2/audit.h>
  51 #include <sys/disp.h>
  52 
  53 /*
  54  * DDI entry points.
  55  */
  56 static int cryptoadm_attach(dev_info_t *, ddi_attach_cmd_t);
  57 static int cryptoadm_detach(dev_info_t *, ddi_detach_cmd_t);
  58 static int cryptoadm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  59 static int cryptoadm_open(dev_t *, int, int, cred_t *);
  60 static int cryptoadm_close(dev_t, int, int, cred_t *);
  61 static int cryptoadm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  62 
  63 extern void audit_cryptoadm(int, char *, crypto_mech_name_t *, uint_t,
  64     uint_t, uint32_t, int);
  65 
  66 /*
  67  * Module linkage.
  68  */
  69 static struct cb_ops cbops = {
  70         cryptoadm_open,         /* cb_open */
  71         cryptoadm_close,        /* cb_close */
  72         nodev,                  /* cb_strategy */
  73         nodev,                  /* cb_print */
  74         nodev,                  /* cb_dump */
  75         nodev,                  /* cb_read */
  76         nodev,                  /* cb_write */
  77         cryptoadm_ioctl,        /* cb_ioctl */
  78         nodev,                  /* cb_devmap */
  79         nodev,                  /* cb_mmap */
  80         nodev,                  /* cb_segmap */
  81         nochpoll,               /* cb_chpoll */
  82         ddi_prop_op,            /* cb_prop_op */
  83         NULL,                   /* cb_streamtab */
  84         D_MP,                   /* cb_flag */
  85         CB_REV,                 /* cb_rev */
  86         nodev,                  /* cb_aread */
  87         nodev,                  /* cb_awrite */
  88 };
  89 
  90 static struct dev_ops devops = {
  91         DEVO_REV,               /* devo_rev */
  92         0,                      /* devo_refcnt */
  93         cryptoadm_getinfo,      /* devo_getinfo */
  94         nulldev,                /* devo_identify */
  95         nulldev,                /* devo_probe */
  96         cryptoadm_attach,       /* devo_attach */
  97         cryptoadm_detach,       /* devo_detach */
  98         nodev,                  /* devo_reset */
  99         &cbops,                     /* devo_cb_ops */
 100         NULL,                   /* devo_bus_ops */
 101         NULL,                   /* devo_power */
 102         ddi_quiesce_not_needed,         /* devo_quiesce */
 103 };
 104 
 105 static struct modldrv modldrv = {
 106         &mod_driverops,                                     /* drv_modops */
 107         "Cryptographic Administrative Interface",       /* drv_linkinfo */
 108         &devops,
 109 };
 110 
 111 static struct modlinkage modlinkage = {
 112         MODREV_1,               /* ml_rev */
 113         {   &modldrv,               /* ml_linkage */
 114             NULL }
 115 };
 116 
 117 static dev_info_t       *cryptoadm_dip = NULL;
 118 
 119 /*
 120  * DDI entry points.
 121  */
 122 int
 123 _init(void)
 124 {
 125         return (mod_install(&modlinkage));
 126 }
 127 
 128 int
 129 _fini(void)
 130 {
 131         return (mod_remove(&modlinkage));
 132 }
 133 
 134 int
 135 _info(struct modinfo *modinfop)
 136 {
 137         return (mod_info(&modlinkage, modinfop));
 138 }
 139 
 140 /* ARGSUSED */
 141 static int
 142 cryptoadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 143 {
 144         switch (cmd) {
 145         case DDI_INFO_DEVT2DEVINFO:
 146                 *result = (void *)cryptoadm_dip;
 147                 return (DDI_SUCCESS);
 148 
 149         case DDI_INFO_DEVT2INSTANCE:
 150                 *result = (void *)0;
 151                 return (DDI_SUCCESS);
 152         }
 153         return (DDI_FAILURE);
 154 }
 155 
 156 static int
 157 cryptoadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 158 {
 159         if (cmd != DDI_ATTACH) {
 160                 return (DDI_FAILURE);
 161         }
 162         if (ddi_get_instance(dip) != 0) {
 163                 /* we only allow instance 0 to attach */
 164                 return (DDI_FAILURE);
 165         }
 166 
 167         /* create the minor node */
 168         if (ddi_create_minor_node(dip, "cryptoadm", S_IFCHR, 0,
 169             DDI_PSEUDO, 0) != DDI_SUCCESS) {
 170                 cmn_err(CE_WARN, "cryptoadm: failed creating minor node");
 171                 ddi_remove_minor_node(dip, NULL);
 172                 return (DDI_FAILURE);
 173         }
 174 
 175         cryptoadm_dip = dip;
 176 
 177         return (DDI_SUCCESS);
 178 }
 179 
 180 static int
 181 cryptoadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 182 {
 183         if (cmd != DDI_DETACH)
 184                 return (DDI_FAILURE);
 185 
 186         cryptoadm_dip = NULL;
 187         ddi_remove_minor_node(dip, NULL);
 188 
 189         return (DDI_SUCCESS);
 190 }
 191 
 192 /* ARGSUSED */
 193 static int
 194 cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
 195 {
 196         if (otyp != OTYP_CHR || cryptoadm_dip == NULL)
 197                 return (ENXIO);
 198 
 199         /* exclusive opens are not supported */
 200         if (flag & FEXCL)
 201                 return (ENOTSUP);
 202 
 203         *devp = makedevice(getmajor(*devp), 0);
 204 
 205         kcf_sched_start();
 206 
 207         return (0);
 208 }
 209 
 210 /* ARGSUSED */
 211 static int
 212 cryptoadm_close(dev_t dev, int flag, int otyp, cred_t *credp)
 213 {
 214         return (0);
 215 }
 216 
 217 /*
 218  * Returns TRUE if array of size MAXNAMELEN contains a '\0'
 219  * termination character, otherwise, it returns FALSE.
 220  */
 221 static boolean_t
 222 null_terminated(char *array)
 223 {
 224         int i;
 225 
 226         for (i = 0; i < MAXNAMELEN; i++)
 227                 if (array[i] == '\0')
 228                         return (B_TRUE);
 229 
 230         return (B_FALSE);
 231 }
 232 
 233 /*
 234  * This ioctl returns an array of hardware providers.  Each entry
 235  * contains a device name, device instance, and number of
 236  * supported mechanisms.
 237  */
 238 /* ARGSUSED */
 239 static int
 240 get_dev_list(dev_t dev, caddr_t arg, int mode, int *rval)
 241 {
 242         crypto_get_dev_list_t dev_list;
 243         crypto_dev_list_entry_t *entries;
 244         size_t copyout_size;
 245         uint_t count;
 246         ulong_t offset;
 247 
 248         if (copyin(arg, &dev_list, sizeof (dev_list)) != 0)
 249                 return (EFAULT);
 250 
 251         /* get the list from the core module */
 252         if (crypto_get_dev_list(&count, &entries) != 0) {
 253                 dev_list.dl_return_value = CRYPTO_FAILED;
 254                 if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
 255                         return (EFAULT);
 256                 }
 257                 return (0);
 258         }
 259 
 260         /* check if buffer is too small */
 261         if (count > dev_list.dl_dev_count) {
 262                 dev_list.dl_dev_count = count;
 263                 dev_list.dl_return_value = CRYPTO_BUFFER_TOO_SMALL;
 264                 crypto_free_dev_list(entries, count);
 265                 if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
 266                         return (EFAULT);
 267                 }
 268                 return (0);
 269         }
 270 
 271         dev_list.dl_dev_count = count;
 272         dev_list.dl_return_value = CRYPTO_SUCCESS;
 273 
 274         copyout_size = count * sizeof (crypto_dev_list_entry_t);
 275 
 276         /* copyout the first stuff */
 277         if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
 278                 crypto_free_dev_list(entries, count);
 279                 return (EFAULT);
 280         }
 281 
 282         /* copyout entries */
 283         offset = offsetof(crypto_get_dev_list_t, dl_devs);
 284         if (count > 0 && copyout(entries, arg + offset, copyout_size) != 0) {
 285                 crypto_free_dev_list(entries, count);
 286                 return (EFAULT);
 287         }
 288         crypto_free_dev_list(entries, count);
 289         return (0);
 290 }
 291 
 292 /*
 293  * This ioctl returns a buffer containing the null terminated names
 294  * of software providers.
 295  */
 296 /* ARGSUSED */
 297 static int
 298 get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval)
 299 {
 300         STRUCT_DECL(crypto_get_soft_list, soft_list);
 301         char *names;
 302         size_t len;
 303         uint_t count;
 304 
 305         STRUCT_INIT(soft_list, mode);
 306 
 307         if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0)
 308                 return (EFAULT);
 309 
 310         /* get the list from the core module */
 311         if (crypto_get_soft_list(&count, &names, &len) != 0) {
 312                 STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED);
 313                 if (copyout(STRUCT_BUF(soft_list), arg,
 314                     STRUCT_SIZE(soft_list)) != 0) {
 315                         return (EFAULT);
 316                 }
 317                 return (0);
 318         }
 319 
 320         /* check if buffer is too small */
 321         if (len > STRUCT_FGET(soft_list, sl_soft_len)) {
 322                 STRUCT_FSET(soft_list, sl_soft_count, count);
 323                 STRUCT_FSET(soft_list, sl_soft_len, len);
 324                 STRUCT_FSET(soft_list, sl_return_value,
 325                     CRYPTO_BUFFER_TOO_SMALL);
 326                 kmem_free(names, len);
 327                 if (copyout(STRUCT_BUF(soft_list), arg,
 328                     STRUCT_SIZE(soft_list)) != 0) {
 329                         return (EFAULT);
 330                 }
 331                 return (0);
 332         }
 333 
 334         STRUCT_FSET(soft_list, sl_soft_count, count);
 335         STRUCT_FSET(soft_list, sl_soft_len, len);
 336         STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS);
 337 
 338         if (count > 0 && copyout(names,
 339             STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) {
 340                 kmem_free(names, len);
 341                 return (EFAULT);
 342         }
 343         kmem_free(names, len);
 344 
 345         if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) {
 346                 return (EFAULT);
 347         }
 348 
 349         return (0);
 350 }
 351 
 352 /*
 353  * This ioctl returns an array of mechanisms supported by the
 354  * specified device.
 355  */
 356 /* ARGSUSED */
 357 static int
 358 get_dev_info(dev_t dev, caddr_t arg, int mode, int *rval)
 359 {
 360         crypto_get_dev_info_t dev_info;
 361         crypto_mech_name_t *entries;
 362         size_t copyout_size;
 363         uint_t count;
 364         ulong_t offset;
 365         char *dev_name;
 366         int rv;
 367 
 368         if (copyin(arg, &dev_info, sizeof (dev_info)) != 0)
 369                 return (EFAULT);
 370 
 371         dev_name = dev_info.di_dev_name;
 372         /* make sure the device name is null terminated */
 373         if (!null_terminated(dev_name)) {
 374                 dev_info.di_return_value = CRYPTO_ARGUMENTS_BAD;
 375                 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
 376                         return (EFAULT);
 377                 }
 378                 return (0);
 379         }
 380 
 381         /* get mechanism names from the core module */
 382         if ((rv = crypto_get_dev_info(dev_name, dev_info.di_dev_instance,
 383             &count, &entries)) != CRYPTO_SUCCESS) {
 384                 dev_info.di_return_value = rv;
 385                 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
 386                         return (EFAULT);
 387                 }
 388                 return (0);
 389         }
 390 
 391         /* check if buffer is too small */
 392         if (count > dev_info.di_count) {
 393                 dev_info.di_count = count;
 394                 dev_info.di_return_value = CRYPTO_BUFFER_TOO_SMALL;
 395                 crypto_free_mech_list(entries, count);
 396                 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
 397                         return (EFAULT);
 398                 }
 399                 return (0);
 400         }
 401 
 402         dev_info.di_count = count;
 403         dev_info.di_return_value = CRYPTO_SUCCESS;
 404 
 405         copyout_size = count * sizeof (crypto_mech_name_t);
 406 
 407         /* copyout the first stuff */
 408         if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
 409                 crypto_free_mech_list(entries, count);
 410                 return (EFAULT);
 411         }
 412 
 413         /* copyout entries */
 414         offset = offsetof(crypto_get_dev_info_t, di_list);
 415         if (copyout(entries, arg + offset, copyout_size) != 0) {
 416                 crypto_free_mech_list(entries, count);
 417                 return (EFAULT);
 418         }
 419         crypto_free_mech_list(entries, count);
 420         return (0);
 421 }
 422 
 423 /*
 424  * This ioctl returns an array of mechanisms supported by the
 425  * specified cryptographic module.
 426  */
 427 /* ARGSUSED */
 428 static int
 429 get_soft_info(dev_t dev, caddr_t arg, int mode, int *rval)
 430 {
 431         crypto_get_soft_info_t soft_info;
 432         crypto_mech_name_t *entries;
 433         size_t copyout_size;
 434         uint_t count;
 435         ulong_t offset;
 436         char *name;
 437 
 438         if (copyin(arg, &soft_info, sizeof (soft_info)) != 0)
 439                 return (EFAULT);
 440 
 441         name = soft_info.si_name;
 442         /* make sure the provider name is null terminated */
 443         if (!null_terminated(name)) {
 444                 soft_info.si_return_value = CRYPTO_ARGUMENTS_BAD;
 445                 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
 446                         return (EFAULT);
 447                 }
 448                 return (0);
 449         }
 450 
 451         /* get mechanism names from the core module */
 452         if (crypto_get_soft_info(name, &count, &entries) != 0) {
 453                 soft_info.si_return_value = CRYPTO_FAILED;
 454                 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
 455                         return (EFAULT);
 456                 }
 457                 return (0);
 458         }
 459 
 460         /* check if buffer is too small */
 461         if (count > soft_info.si_count) {
 462                 soft_info.si_count = count;
 463                 soft_info.si_return_value = CRYPTO_BUFFER_TOO_SMALL;
 464                 crypto_free_mech_list(entries, count);
 465                 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
 466                         return (EFAULT);
 467                 }
 468                 return (0);
 469         }
 470 
 471         soft_info.si_count = count;
 472         soft_info.si_return_value = CRYPTO_SUCCESS;
 473         copyout_size = count * sizeof (crypto_mech_name_t);
 474 
 475         /* copyout the first stuff */
 476         if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
 477                 crypto_free_mech_list(entries, count);
 478                 return (EFAULT);
 479         }
 480 
 481         /* copyout entries */
 482         offset = offsetof(crypto_get_soft_info_t, si_list);
 483         if (copyout(entries, arg + offset, copyout_size) != 0) {
 484                 crypto_free_mech_list(entries, count);
 485                 return (EFAULT);
 486         }
 487         crypto_free_mech_list(entries, count);
 488         return (0);
 489 }
 490 
 491 /*
 492  * This ioctl disables mechanisms supported by the specified device.
 493  */
 494 /* ARGSUSED */
 495 static int
 496 load_dev_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
 497 {
 498         crypto_load_dev_disabled_t dev_disabled;
 499         crypto_mech_name_t *entries;
 500         size_t size;
 501         ulong_t offset;
 502         uint_t count;
 503         uint_t instance;
 504         char *dev_name;
 505         uint32_t rv;
 506         int error = 0;
 507 
 508         if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
 509                 error =  EFAULT;
 510                 goto out2;
 511         }
 512 
 513         dev_name = dev_disabled.dd_dev_name;
 514         /* make sure the device name is null terminated */
 515         if (!null_terminated(dev_name)) {
 516                 rv = CRYPTO_ARGUMENTS_BAD;
 517                 goto out;
 518         }
 519 
 520         count = dev_disabled.dd_count;
 521         instance = dev_disabled.dd_dev_instance;
 522         if (count == 0) {
 523                 /* remove the entry */
 524                 if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
 525                         rv = CRYPTO_FAILED;
 526                 else
 527                         rv = CRYPTO_SUCCESS;
 528                 goto out;
 529         }
 530 
 531         if (count > KCF_MAXMECHS) {
 532                 rv = CRYPTO_ARGUMENTS_BAD;
 533                 goto out;
 534         }
 535 
 536         size = count * sizeof (crypto_mech_name_t);
 537         entries = kmem_alloc(size, KM_SLEEP);
 538 
 539         offset = offsetof(crypto_load_dev_disabled_t, dd_list);
 540         if (copyin(arg + offset, entries, size) != 0) {
 541                 kmem_free(entries, size);
 542                 error = EFAULT;
 543                 goto out2;
 544         }
 545 
 546         /* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
 547         if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
 548                 kmem_free(entries, size);
 549                 rv = CRYPTO_FAILED;
 550                 goto out;
 551         }
 552         rv = CRYPTO_SUCCESS;
 553 out:
 554         dev_disabled.dd_return_value = rv;
 555 
 556         if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
 557                 error = EFAULT;
 558         }
 559 out2:
 560         if (AU_AUDITING())
 561                 audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
 562                     count, instance, rv, error);
 563         return (error);
 564 }
 565 
 566 /*
 567  * This ioctl disables mechanisms supported by the specified
 568  * cryptographic module.
 569  */
 570 /* ARGSUSED */
 571 static int
 572 load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
 573 {
 574         crypto_load_soft_disabled_t soft_disabled;
 575         crypto_mech_name_t *entries;
 576         size_t size;
 577         uint_t count;
 578         ulong_t offset;
 579         char *name;
 580         uint32_t rv;
 581         int error = 0;
 582 
 583         if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
 584                 error = EFAULT;
 585                 goto out2;
 586         }
 587 
 588         name = soft_disabled.sd_name;
 589         /* make sure the name is null terminated */
 590         if (!null_terminated(name)) {
 591                 soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
 592                 if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
 593                         return (EFAULT);
 594                 }
 595                 return (0);
 596         }
 597 
 598         count = soft_disabled.sd_count;
 599         if (count == 0) {
 600                 /* remove the entry */
 601                 if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
 602                         rv = CRYPTO_FAILED;
 603                 } else {
 604                         rv = CRYPTO_SUCCESS;
 605                 }
 606                 goto out;
 607         }
 608 
 609         if (count > KCF_MAXMECHS) {
 610                 rv = CRYPTO_ARGUMENTS_BAD;
 611                 goto out;
 612         }
 613 
 614         size = count * sizeof (crypto_mech_name_t);
 615         entries = kmem_alloc(size, KM_SLEEP);
 616 
 617         offset = offsetof(crypto_load_soft_disabled_t, sd_list);
 618         if (copyin(arg + offset, entries, size) != 0) {
 619                 kmem_free(entries, size);
 620                 error = EFAULT;
 621                 goto out2;
 622         }
 623 
 624         /* 'entries' is consumed by crypto_load_soft_disabled() */
 625         if (crypto_load_soft_disabled(name, count, entries) != 0) {
 626                 kmem_free(entries, size);
 627                 rv = CRYPTO_FAILED;
 628                 goto out;
 629         }
 630         rv = CRYPTO_SUCCESS;
 631 out:
 632         soft_disabled.sd_return_value = rv;
 633 
 634         if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
 635                 error = EFAULT;
 636         }
 637 out2:
 638         if (AU_AUDITING())
 639                 audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
 640                     count, 0, rv, error);
 641         return (error);
 642 }
 643 
 644 /*
 645  * This ioctl loads the supported mechanisms of the specfied cryptographic
 646  * module.  This is so, at boot time, all software providers do not
 647  * have to be opened in order to cause them to register their
 648  * supported mechanisms.
 649  */
 650 /* ARGSUSED */
 651 static int
 652 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
 653 {
 654         crypto_load_soft_config_t soft_config;
 655         crypto_mech_name_t *entries;
 656         size_t size;
 657         uint_t count;
 658         ulong_t offset;
 659         char *name;
 660         uint32_t rv;
 661         int error = 0;
 662 
 663         if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
 664                 error = EFAULT;
 665                 goto out2;
 666         }
 667 
 668         name = soft_config.sc_name;
 669         /* make sure the name is null terminated */
 670         if (!null_terminated(name)) {
 671                 soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
 672                 if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
 673                         return (EFAULT);
 674                 }
 675                 return (0);
 676         }
 677 
 678         count = soft_config.sc_count;
 679         if (count == 0) {
 680                 if (crypto_load_soft_config(name, 0, NULL) != 0) {
 681                         rv = CRYPTO_FAILED;
 682                 } else {
 683                         rv = CRYPTO_SUCCESS;
 684                 }
 685                 goto out;
 686         }
 687 
 688         if (count > KCF_MAXMECHS) {
 689                 rv = CRYPTO_ARGUMENTS_BAD;
 690                 goto out;
 691         }
 692 
 693         size = count * sizeof (crypto_mech_name_t);
 694         entries = kmem_alloc(size, KM_SLEEP);
 695 
 696         offset = offsetof(crypto_load_soft_config_t, sc_list);
 697         if (copyin(arg + offset, entries, size) != 0) {
 698                 kmem_free(entries, size);
 699                 error = EFAULT;
 700                 goto out2;
 701         }
 702 
 703         /*
 704          * 'entries' is consumed (but not freed) by
 705          * crypto_load_soft_config()
 706          */
 707         if (crypto_load_soft_config(name, count, entries) != 0) {
 708                 kmem_free(entries, size);
 709                 rv = CRYPTO_FAILED;
 710                 goto out;
 711         }
 712         rv = CRYPTO_SUCCESS;
 713 out:
 714         soft_config.sc_return_value = rv;
 715 
 716         if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
 717                 error = EFAULT;
 718         }
 719 out2:
 720         if (AU_AUDITING())
 721                 audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
 722                     0, rv, error);
 723         return (error);
 724 }
 725 
 726 /*
 727  * This ioctl unloads the specfied cryptographic module and removes
 728  * its table of supported mechanisms.
 729  */
 730 /* ARGSUSED */
 731 static int
 732 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
 733 {
 734         crypto_unload_soft_module_t unload_soft_module;
 735         char *name;
 736         uint32_t rv;
 737         int error = 0;
 738 
 739         if (copyin(arg, &unload_soft_module,
 740             sizeof (unload_soft_module)) != 0) {
 741                 error = EFAULT;
 742                 goto out2;
 743         }
 744 
 745         name = unload_soft_module.sm_name;
 746         /* make sure the name is null terminated */
 747         if (!null_terminated(name)) {
 748                 unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
 749                 if (copyout(&unload_soft_module, arg,
 750                     sizeof (unload_soft_module)) != 0) {
 751                         return (EFAULT);
 752                 }
 753                 return (0);
 754         }
 755 
 756         rv = crypto_unload_soft_module(name);
 757 out:
 758         unload_soft_module.sm_return_value = rv;
 759 
 760         if (copyout(&unload_soft_module, arg,
 761             sizeof (unload_soft_module)) != 0) {
 762                 error = EFAULT;
 763         }
 764 out2:
 765         if (AU_AUDITING())
 766                 audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
 767                     rv, error);
 768 
 769         return (error);
 770 }
 771 
 772 static int
 773 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
 774     int *rval)
 775 {
 776         int error;
 777 #define ARG     ((caddr_t)arg)
 778 
 779         switch (cmd) {
 780         case CRYPTO_LOAD_DEV_DISABLED:
 781         case CRYPTO_LOAD_SOFT_DISABLED:
 782         case CRYPTO_LOAD_SOFT_CONFIG:
 783         case CRYPTO_UNLOAD_SOFT_MODULE:
 784         case CRYPTO_LOAD_DOOR:
 785         case CRYPTO_FIPS140_SET:
 786                 if ((error = drv_priv(c)) != 0)
 787                         return (error);
 788         default:
 789                 break;
 790         }
 791 
 792         switch (cmd) {
 793         case CRYPTO_GET_DEV_LIST:
 794                 return (get_dev_list(dev, ARG, mode, rval));
 795 
 796         case CRYPTO_GET_DEV_INFO:
 797                 return (get_dev_info(dev, ARG, mode, rval));
 798 
 799         case CRYPTO_GET_SOFT_LIST:
 800                 return (get_soft_list(dev, ARG, mode, rval));
 801 
 802         case CRYPTO_GET_SOFT_INFO:
 803                 return (get_soft_info(dev, ARG, mode, rval));
 804 
 805         case CRYPTO_LOAD_DEV_DISABLED:
 806                 return (load_dev_disabled(dev, ARG, mode, rval));
 807 
 808         case CRYPTO_LOAD_SOFT_DISABLED:
 809                 return (load_soft_disabled(dev, ARG, mode, rval));
 810 
 811         case CRYPTO_LOAD_SOFT_CONFIG:
 812                 return (load_soft_config(dev, ARG, mode, rval));
 813 
 814         case CRYPTO_UNLOAD_SOFT_MODULE:
 815                 return (unload_soft_module(dev, ARG, mode, rval));
 816         }
 817 
 818         return (EINVAL);
 819 }