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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * Blacklist special file
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/conf.h>
  33 #include <sys/stat.h>
  34 #include <sys/modctl.h>
  35 #include <sys/kmem.h>
  36 #include <sys/ddi.h>
  37 #include <sys/sunddi.h>
  38 #include <sys/open.h>
  39 #include <sys/policy.h>
  40 #include <sys/fm/protocol.h>
  41 #include <sys/bl.h>
  42 
  43 static dev_info_t *bl_dip;      /* private copy of devinfo pointer */
  44 
  45 static int
  46 bl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
  47 {
  48         switch (cmd) {
  49         case DDI_ATTACH:
  50                 break;
  51         case DDI_RESUME:
  52                 return (DDI_SUCCESS);
  53         default:
  54                 return (DDI_FAILURE);
  55         }
  56 
  57         if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
  58             ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS)
  59                 return (DDI_FAILURE);
  60 
  61         bl_dip = dip;
  62         return (DDI_SUCCESS);
  63 }
  64 
  65 /*ARGSUSED*/
  66 static int
  67 bl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
  68 {
  69         switch (cmd) {
  70         case DDI_DETACH:
  71                 break;
  72         case DDI_SUSPEND:
  73                 return (DDI_SUCCESS);
  74         default:
  75                 return (DDI_FAILURE);
  76         }
  77 
  78         ddi_remove_minor_node(bl_dip, NULL);
  79         return (DDI_SUCCESS);
  80 }
  81 
  82 /*ARGSUSED*/
  83 static int
  84 bl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
  85 {
  86         int rc = DDI_SUCCESS;
  87 
  88         switch (infocmd) {
  89         case DDI_INFO_DEVT2DEVINFO:
  90                 *result = bl_dip;
  91                 break;
  92 
  93         case DDI_INFO_DEVT2INSTANCE:
  94                 *result = (void *)(uintptr_t)getminor((dev_t)arg);
  95                 break;
  96 
  97         default:
  98                 *result = NULL;
  99                 rc = DDI_FAILURE;
 100         }
 101 
 102         return (rc);
 103 }
 104 
 105 /*ARGSUSED*/
 106 static int
 107 bl_open(dev_t *devp, int flag, int otyp, struct cred *credp)
 108 {
 109         if (otyp != OTYP_CHR)
 110                 return (EINVAL);
 111 
 112         if (secpolicy_blacklist(credp) != 0)
 113                 return (EPERM);
 114 
 115         return (0);
 116 }
 117 
 118 /*ARGSUSED*/
 119 static int
 120 bl_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
 121 {
 122         bl_req_t blr;
 123         nvlist_t *fmri;
 124         const char *scheme;
 125         char class[128];
 126         char *buf;
 127         int err;
 128 
 129 #ifdef _SYSCALL32
 130         if (get_udatamodel() != DATAMODEL_NATIVE) {
 131                 bl_req32_t blr32;
 132 
 133                 if (copyin((void *)data, &blr32, sizeof (bl_req32_t)) != 0)
 134                         return (EFAULT);
 135 
 136                 blr.bl_fmri = (caddr_t)(uintptr_t)blr32.bl_fmri;
 137                 blr.bl_fmrisz = blr32.bl_fmrisz;
 138 
 139                 blr.bl_class = (caddr_t)(uintptr_t)blr32.bl_class;
 140         } else
 141 #endif
 142         {
 143                 if (copyin((void *)data, &blr, sizeof (bl_req_t)) != 0)
 144                         return (EFAULT);
 145         }
 146 
 147         if (blr.bl_fmri == NULL || blr.bl_fmrisz > BL_FMRI_MAX_BUFSIZE ||
 148             blr.bl_class == NULL)
 149                 return (EINVAL);
 150 
 151         if (copyinstr(blr.bl_class, class, sizeof (class), NULL) != 0)
 152                 return (EFAULT);
 153 
 154         buf = kmem_zalloc(blr.bl_fmrisz, KM_SLEEP);
 155         if (copyin(blr.bl_fmri, buf, blr.bl_fmrisz) != 0) {
 156                 kmem_free(buf, blr.bl_fmrisz);
 157                 return (EFAULT);
 158         }
 159 
 160         err = nvlist_unpack(buf, blr.bl_fmrisz, &fmri, KM_SLEEP);
 161         kmem_free(buf, blr.bl_fmrisz);
 162         if (err != 0)
 163                 return (err);
 164 
 165         if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, (char **)&scheme) != 0) {
 166                 nvlist_free(fmri);
 167                 return (EINVAL);
 168         }
 169 
 170         switch (cmd) {
 171         case BLIOC_INSERT:
 172         case BLIOC_DELETE:
 173                 err = blacklist(cmd, scheme, fmri, class);
 174                 break;
 175         default:
 176                 err = ENOTSUP;
 177         }
 178 
 179         nvlist_free(fmri);
 180         return (err);
 181 
 182 }
 183 
 184 static struct cb_ops bl_cb_ops = {
 185         bl_open,                /* open */
 186         nulldev,                /* close */
 187         nodev,                  /* strategy */
 188         nodev,                  /* print */
 189         nodev,                  /* dump */
 190         nodev,                  /* read */
 191         nodev,                  /* write */
 192         bl_ioctl,               /* ioctl */
 193         nodev,                  /* devmap */
 194         nodev,                  /* mmap */
 195         nodev,                  /* segmap */
 196         nochpoll,               /* poll */
 197         ddi_prop_op,            /* cb_prop_op */
 198         0,                      /* streamtab  */
 199         D_NEW | D_MP | D_64BIT  /* Driver compatibility flag */
 200 };
 201 
 202 static struct dev_ops bl_ops = {
 203         DEVO_REV,               /* devo_rev */
 204         0,                      /* devo_refcnt  */
 205         bl_getinfo,             /* devo_getinfo */
 206         nulldev,                /* devo_identify */
 207         nulldev,                /* devo_probe */
 208         bl_attach,              /* devo_attach */
 209         bl_detach,              /* devo_detach */
 210         nodev,                  /* devo_reset */
 211         &bl_cb_ops,         /* devo_cb_ops */
 212         (struct bus_ops *)0,    /* devo_bus_ops */
 213         NULL,                   /* devo_power */
 214         ddi_quiesce_not_needed,         /* devo_quiesce */
 215 };
 216 
 217 static struct modldrv modldrv = {
 218         &mod_driverops, "blacklist driver", &bl_ops,
 219 };
 220 
 221 static struct modlinkage modlinkage = {
 222         MODREV_1, &modldrv, NULL
 223 };
 224 
 225 int
 226 _init(void)
 227 {
 228         return (mod_install(&modlinkage));
 229 }
 230 
 231 int
 232 _info(struct modinfo *modinfop)
 233 {
 234         return (mod_info(&modlinkage, modinfop));
 235 }
 236 
 237 int
 238 _fini(void)
 239 {
 240         return (mod_remove(&modlinkage));
 241 }