1*5440Sjm199354 /* 2*5440Sjm199354 * CDDL HEADER START 3*5440Sjm199354 * 4*5440Sjm199354 * The contents of this file are subject to the terms of the 5*5440Sjm199354 * Common Development and Distribution License (the "License"). 6*5440Sjm199354 * You may not use this file except in compliance with the License. 7*5440Sjm199354 * 8*5440Sjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5440Sjm199354 * or http://www.opensolaris.org/os/licensing. 10*5440Sjm199354 * See the License for the specific language governing permissions 11*5440Sjm199354 * and limitations under the License. 12*5440Sjm199354 * 13*5440Sjm199354 * When distributing Covered Code, include this CDDL HEADER in each 14*5440Sjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5440Sjm199354 * If applicable, add the following below this CDDL HEADER, with the 16*5440Sjm199354 * fields enclosed by brackets "[]" replaced with your own identifying 17*5440Sjm199354 * information: Portions Copyright [yyyy] [name of copyright owner] 18*5440Sjm199354 * 19*5440Sjm199354 * CDDL HEADER END 20*5440Sjm199354 */ 21*5440Sjm199354 22*5440Sjm199354 /* 23*5440Sjm199354 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*5440Sjm199354 * Use is subject to license terms. 25*5440Sjm199354 */ 26*5440Sjm199354 27*5440Sjm199354 #pragma ident "%Z%%M% %I% %E% SMI" 28*5440Sjm199354 29*5440Sjm199354 #include <sys/stat.h> 30*5440Sjm199354 #include <sys/ddi.h> 31*5440Sjm199354 #include <sys/sunddi.h> 32*5440Sjm199354 #include <sys/time.h> 33*5440Sjm199354 #include <sys/varargs.h> 34*5440Sjm199354 #include <sys/conf.h> 35*5440Sjm199354 #include <sys/modctl.h> 36*5440Sjm199354 #include <sys/vnode.h> 37*5440Sjm199354 #include <fs/fs_subr.h> 38*5440Sjm199354 #include <sys/types.h> 39*5440Sjm199354 #include <sys/file.h> 40*5440Sjm199354 #include <sys/disp.h> 41*5440Sjm199354 #include <sys/vscan.h> 42*5440Sjm199354 #include <sys/policy.h> 43*5440Sjm199354 #include <sys/sdt.h> 44*5440Sjm199354 45*5440Sjm199354 #define VS_DRV_NODENAME_LEN 16 46*5440Sjm199354 47*5440Sjm199354 48*5440Sjm199354 /* 49*5440Sjm199354 * Instance States: VS_INIT (initial state), VS_OPEN, VS_READING 50*5440Sjm199354 * 51*5440Sjm199354 * Instance 0 controls the state of the driver: vscan_drv_connected. 52*5440Sjm199354 * vscan_drv_state[0] should NOT be used. 53*5440Sjm199354 * Actions: 54*5440Sjm199354 * open: VS_INIT->VS_OPEN, otherwise ERROR 55*5440Sjm199354 * close: any->VS_INIT 56*5440Sjm199354 * read: VS_OPEN->VS_READING, otherwise ERROR 57*5440Sjm199354 */ 58*5440Sjm199354 typedef enum { 59*5440Sjm199354 VS_INIT, 60*5440Sjm199354 VS_OPEN, 61*5440Sjm199354 VS_READING 62*5440Sjm199354 } vscan_drv_state_t; 63*5440Sjm199354 64*5440Sjm199354 static vscan_drv_state_t vscan_drv_state[VS_DRV_MAX_FILES + 1]; 65*5440Sjm199354 static boolean_t vscan_drv_connected = B_FALSE; /* vscand daemon connected */ 66*5440Sjm199354 67*5440Sjm199354 static dev_info_t *vscan_drv_dip; 68*5440Sjm199354 static kmutex_t vscan_drv_mutex; 69*5440Sjm199354 70*5440Sjm199354 /* 71*5440Sjm199354 * DDI entry points. 72*5440Sjm199354 */ 73*5440Sjm199354 static int vscan_drv_attach(dev_info_t *, ddi_attach_cmd_t); 74*5440Sjm199354 static int vscan_drv_detach(dev_info_t *, ddi_detach_cmd_t); 75*5440Sjm199354 static int vscan_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 76*5440Sjm199354 static int vscan_drv_open(dev_t *, int, int, cred_t *); 77*5440Sjm199354 static int vscan_drv_close(dev_t, int, int, cred_t *); 78*5440Sjm199354 static int vscan_drv_read(dev_t, struct uio *, cred_t *); 79*5440Sjm199354 static int vscan_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 80*5440Sjm199354 81*5440Sjm199354 static boolean_t vscan_drv_in_use(); 82*5440Sjm199354 83*5440Sjm199354 84*5440Sjm199354 /* 85*5440Sjm199354 * module linkage info for the kernel 86*5440Sjm199354 */ 87*5440Sjm199354 88*5440Sjm199354 static struct cb_ops cbops = { 89*5440Sjm199354 vscan_drv_open, /* cb_open */ 90*5440Sjm199354 vscan_drv_close, /* cb_close */ 91*5440Sjm199354 nodev, /* cb_strategy */ 92*5440Sjm199354 nodev, /* cb_print */ 93*5440Sjm199354 nodev, /* cb_dump */ 94*5440Sjm199354 vscan_drv_read, /* cb_read */ 95*5440Sjm199354 nodev, /* cb_write */ 96*5440Sjm199354 vscan_drv_ioctl, /* cb_ioctl */ 97*5440Sjm199354 nodev, /* cb_devmap */ 98*5440Sjm199354 nodev, /* cb_mmap */ 99*5440Sjm199354 nodev, /* cb_segmap */ 100*5440Sjm199354 nochpoll, /* cb_chpoll */ 101*5440Sjm199354 ddi_prop_op, /* cb_prop_op */ 102*5440Sjm199354 NULL, /* cb_streamtab */ 103*5440Sjm199354 D_MP, /* cb_flag */ 104*5440Sjm199354 CB_REV, /* cb_rev */ 105*5440Sjm199354 nodev, /* cb_aread */ 106*5440Sjm199354 nodev, /* cb_awrite */ 107*5440Sjm199354 }; 108*5440Sjm199354 109*5440Sjm199354 static struct dev_ops devops = { 110*5440Sjm199354 DEVO_REV, /* devo_rev */ 111*5440Sjm199354 0, /* devo_refcnt */ 112*5440Sjm199354 vscan_drv_getinfo, /* devo_getinfo */ 113*5440Sjm199354 nulldev, /* devo_identify */ 114*5440Sjm199354 nulldev, /* devo_probe */ 115*5440Sjm199354 vscan_drv_attach, /* devo_attach */ 116*5440Sjm199354 vscan_drv_detach, /* devo_detach */ 117*5440Sjm199354 nodev, /* devo_reset */ 118*5440Sjm199354 &cbops, /* devo_cb_ops */ 119*5440Sjm199354 NULL, /* devo_bus_ops */ 120*5440Sjm199354 NULL, /* devo_power */ 121*5440Sjm199354 }; 122*5440Sjm199354 123*5440Sjm199354 static struct modldrv modldrv = { 124*5440Sjm199354 &mod_driverops, /* drv_modops */ 125*5440Sjm199354 "virus scanning", /* drv_linkinfo */ 126*5440Sjm199354 &devops, 127*5440Sjm199354 }; 128*5440Sjm199354 129*5440Sjm199354 static struct modlinkage modlinkage = { 130*5440Sjm199354 131*5440Sjm199354 MODREV_1, /* revision of the module, must be: MODREV_1 */ 132*5440Sjm199354 &modldrv, /* ptr to linkage structures */ 133*5440Sjm199354 NULL, 134*5440Sjm199354 }; 135*5440Sjm199354 136*5440Sjm199354 137*5440Sjm199354 /* 138*5440Sjm199354 * _init 139*5440Sjm199354 */ 140*5440Sjm199354 int 141*5440Sjm199354 _init(void) 142*5440Sjm199354 { 143*5440Sjm199354 int rc; 144*5440Sjm199354 145*5440Sjm199354 mutex_init(&vscan_drv_mutex, NULL, MUTEX_DRIVER, NULL); 146*5440Sjm199354 147*5440Sjm199354 if (vscan_door_init() != 0) { 148*5440Sjm199354 mutex_destroy(&vscan_drv_mutex); 149*5440Sjm199354 return (DDI_FAILURE); 150*5440Sjm199354 } 151*5440Sjm199354 152*5440Sjm199354 if (vscan_svc_init() != 0) { 153*5440Sjm199354 vscan_door_fini(); 154*5440Sjm199354 mutex_destroy(&vscan_drv_mutex); 155*5440Sjm199354 return (DDI_FAILURE); 156*5440Sjm199354 } 157*5440Sjm199354 158*5440Sjm199354 (void) memset(&vscan_drv_state, 0, sizeof (vscan_drv_state)); 159*5440Sjm199354 160*5440Sjm199354 if ((rc = mod_install(&modlinkage)) != 0) { 161*5440Sjm199354 vscan_door_fini(); 162*5440Sjm199354 vscan_svc_fini(); 163*5440Sjm199354 mutex_destroy(&vscan_drv_mutex); 164*5440Sjm199354 } 165*5440Sjm199354 166*5440Sjm199354 return (rc); 167*5440Sjm199354 } 168*5440Sjm199354 169*5440Sjm199354 170*5440Sjm199354 /* 171*5440Sjm199354 * _info 172*5440Sjm199354 */ 173*5440Sjm199354 int 174*5440Sjm199354 _info(struct modinfo *modinfop) 175*5440Sjm199354 { 176*5440Sjm199354 return (mod_info(&modlinkage, modinfop)); 177*5440Sjm199354 } 178*5440Sjm199354 179*5440Sjm199354 180*5440Sjm199354 /* 181*5440Sjm199354 * _fini 182*5440Sjm199354 */ 183*5440Sjm199354 int 184*5440Sjm199354 _fini(void) 185*5440Sjm199354 { 186*5440Sjm199354 int rc; 187*5440Sjm199354 188*5440Sjm199354 if (vscan_drv_in_use()) 189*5440Sjm199354 return (EBUSY); 190*5440Sjm199354 191*5440Sjm199354 if ((rc = mod_remove(&modlinkage)) == 0) { 192*5440Sjm199354 vscan_door_fini(); 193*5440Sjm199354 vscan_svc_fini(); 194*5440Sjm199354 mutex_destroy(&vscan_drv_mutex); 195*5440Sjm199354 } 196*5440Sjm199354 197*5440Sjm199354 return (rc); 198*5440Sjm199354 } 199*5440Sjm199354 200*5440Sjm199354 201*5440Sjm199354 /* 202*5440Sjm199354 * DDI entry points. 203*5440Sjm199354 */ 204*5440Sjm199354 205*5440Sjm199354 /* 206*5440Sjm199354 * vscan_drv_getinfo 207*5440Sjm199354 */ 208*5440Sjm199354 /* ARGSUSED */ 209*5440Sjm199354 static int 210*5440Sjm199354 vscan_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 211*5440Sjm199354 { 212*5440Sjm199354 ulong_t inst = getminor((dev_t)arg); 213*5440Sjm199354 214*5440Sjm199354 switch (cmd) { 215*5440Sjm199354 case DDI_INFO_DEVT2DEVINFO: 216*5440Sjm199354 *result = vscan_drv_dip; 217*5440Sjm199354 return (DDI_SUCCESS); 218*5440Sjm199354 case DDI_INFO_DEVT2INSTANCE: 219*5440Sjm199354 *result = (void *)inst; 220*5440Sjm199354 return (DDI_SUCCESS); 221*5440Sjm199354 } 222*5440Sjm199354 return (DDI_FAILURE); 223*5440Sjm199354 } 224*5440Sjm199354 225*5440Sjm199354 226*5440Sjm199354 /* 227*5440Sjm199354 * vscan_drv_attach 228*5440Sjm199354 */ 229*5440Sjm199354 static int 230*5440Sjm199354 vscan_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 231*5440Sjm199354 { 232*5440Sjm199354 int i; 233*5440Sjm199354 char name[VS_DRV_NODENAME_LEN]; 234*5440Sjm199354 235*5440Sjm199354 if (cmd != DDI_ATTACH) 236*5440Sjm199354 return (DDI_FAILURE); 237*5440Sjm199354 238*5440Sjm199354 if (ddi_get_instance(dip) != 0) 239*5440Sjm199354 return (DDI_FAILURE); 240*5440Sjm199354 241*5440Sjm199354 vscan_drv_dip = dip; 242*5440Sjm199354 243*5440Sjm199354 /* create the minor nodes */ 244*5440Sjm199354 for (i = 0; i <= VS_DRV_MAX_FILES; i++) { 245*5440Sjm199354 (void) snprintf(name, VS_DRV_NODENAME_LEN, "vscan%d", i); 246*5440Sjm199354 if (ddi_create_minor_node(dip, name, S_IFCHR, i, 247*5440Sjm199354 DDI_PSEUDO, 0) != DDI_SUCCESS) { 248*5440Sjm199354 ddi_remove_minor_node(dip, NULL); 249*5440Sjm199354 return (DDI_FAILURE); 250*5440Sjm199354 } 251*5440Sjm199354 } 252*5440Sjm199354 253*5440Sjm199354 return (DDI_SUCCESS); 254*5440Sjm199354 } 255*5440Sjm199354 256*5440Sjm199354 257*5440Sjm199354 /* 258*5440Sjm199354 * vscan_drv_detach 259*5440Sjm199354 */ 260*5440Sjm199354 static int 261*5440Sjm199354 vscan_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 262*5440Sjm199354 { 263*5440Sjm199354 if (cmd != DDI_DETACH) 264*5440Sjm199354 return (DDI_FAILURE); 265*5440Sjm199354 266*5440Sjm199354 if (ddi_get_instance(dip) != 0) 267*5440Sjm199354 return (DDI_FAILURE); 268*5440Sjm199354 269*5440Sjm199354 if (vscan_drv_in_use()) 270*5440Sjm199354 return (DDI_FAILURE); 271*5440Sjm199354 272*5440Sjm199354 vscan_drv_dip = NULL; 273*5440Sjm199354 ddi_remove_minor_node(dip, NULL); 274*5440Sjm199354 275*5440Sjm199354 return (DDI_SUCCESS); 276*5440Sjm199354 } 277*5440Sjm199354 278*5440Sjm199354 279*5440Sjm199354 /* 280*5440Sjm199354 * vscan_drv_in_use 281*5440Sjm199354 */ 282*5440Sjm199354 static boolean_t 283*5440Sjm199354 vscan_drv_in_use() 284*5440Sjm199354 { 285*5440Sjm199354 if (vscan_drv_connected) 286*5440Sjm199354 return (B_TRUE); 287*5440Sjm199354 else 288*5440Sjm199354 return (vscan_svc_in_use()); 289*5440Sjm199354 } 290*5440Sjm199354 291*5440Sjm199354 292*5440Sjm199354 /* 293*5440Sjm199354 * vscan_drv_open 294*5440Sjm199354 * if inst == 0, this is vscand initializing. 295*5440Sjm199354 * Otherwise, open the file associated with inst. 296*5440Sjm199354 */ 297*5440Sjm199354 /* ARGSUSED */ 298*5440Sjm199354 static int 299*5440Sjm199354 vscan_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 300*5440Sjm199354 { 301*5440Sjm199354 int rc; 302*5440Sjm199354 int inst = getminor(*devp); 303*5440Sjm199354 304*5440Sjm199354 if ((inst < 0) || (inst > VS_DRV_MAX_FILES)) 305*5440Sjm199354 return (EINVAL); 306*5440Sjm199354 307*5440Sjm199354 /* check if caller has privilege for virus scanning */ 308*5440Sjm199354 if ((rc = secpolicy_vscan(credp)) != 0) { 309*5440Sjm199354 DTRACE_PROBE1(vscan__priv, int, rc); 310*5440Sjm199354 return (EPERM); 311*5440Sjm199354 } 312*5440Sjm199354 313*5440Sjm199354 mutex_enter(&vscan_drv_mutex); 314*5440Sjm199354 if (inst == 0) { 315*5440Sjm199354 if (vscan_drv_connected) { 316*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 317*5440Sjm199354 return (EINVAL); 318*5440Sjm199354 } 319*5440Sjm199354 vscan_drv_connected = B_TRUE; 320*5440Sjm199354 } else { 321*5440Sjm199354 if ((!vscan_drv_connected) || 322*5440Sjm199354 (vscan_drv_state[inst] != VS_INIT)) { 323*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 324*5440Sjm199354 return (EINVAL); 325*5440Sjm199354 } 326*5440Sjm199354 vscan_drv_state[inst] = VS_OPEN; 327*5440Sjm199354 } 328*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 329*5440Sjm199354 330*5440Sjm199354 return (0); 331*5440Sjm199354 } 332*5440Sjm199354 333*5440Sjm199354 334*5440Sjm199354 /* 335*5440Sjm199354 * vscan_drv_close 336*5440Sjm199354 * if inst == 0, this is vscand detaching 337*5440Sjm199354 * Otherwise close the file associated with inst 338*5440Sjm199354 */ 339*5440Sjm199354 /* ARGSUSED */ 340*5440Sjm199354 static int 341*5440Sjm199354 vscan_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 342*5440Sjm199354 { 343*5440Sjm199354 int i, inst = getminor(dev); 344*5440Sjm199354 345*5440Sjm199354 if ((inst < 0) || (inst > VS_DRV_MAX_FILES)) 346*5440Sjm199354 return (EINVAL); 347*5440Sjm199354 348*5440Sjm199354 mutex_enter(&vscan_drv_mutex); 349*5440Sjm199354 if (inst == 0) { 350*5440Sjm199354 for (i = 1; i <= VS_DRV_MAX_FILES; i++) 351*5440Sjm199354 vscan_drv_state[i] = VS_INIT; 352*5440Sjm199354 353*5440Sjm199354 vscan_drv_connected = B_FALSE; 354*5440Sjm199354 vscan_svc_enable(B_FALSE); 355*5440Sjm199354 vscan_door_close(); 356*5440Sjm199354 } else { 357*5440Sjm199354 vscan_drv_state[inst] = VS_INIT; 358*5440Sjm199354 } 359*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 360*5440Sjm199354 361*5440Sjm199354 return (0); 362*5440Sjm199354 } 363*5440Sjm199354 364*5440Sjm199354 365*5440Sjm199354 /* 366*5440Sjm199354 * vscan_drv_read 367*5440Sjm199354 */ 368*5440Sjm199354 /* ARGSUSED */ 369*5440Sjm199354 static int 370*5440Sjm199354 vscan_drv_read(dev_t dev, struct uio *uiop, cred_t *credp) 371*5440Sjm199354 { 372*5440Sjm199354 int rc; 373*5440Sjm199354 int inst = getminor(dev); 374*5440Sjm199354 vnode_t *vp; 375*5440Sjm199354 376*5440Sjm199354 if ((inst <= 0) || (inst > VS_DRV_MAX_FILES)) 377*5440Sjm199354 return (EINVAL); 378*5440Sjm199354 379*5440Sjm199354 mutex_enter(&vscan_drv_mutex); 380*5440Sjm199354 if ((!vscan_drv_connected) || (vscan_drv_state[inst] != VS_OPEN)) { 381*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 382*5440Sjm199354 return (EINVAL); 383*5440Sjm199354 } 384*5440Sjm199354 vscan_drv_state[inst] = VS_READING; 385*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 386*5440Sjm199354 387*5440Sjm199354 if ((vp = vscan_svc_get_vnode(inst)) == NULL) 388*5440Sjm199354 return (EINVAL); 389*5440Sjm199354 390*5440Sjm199354 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 391*5440Sjm199354 rc = VOP_READ(vp, uiop, 0, kcred, NULL); 392*5440Sjm199354 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 393*5440Sjm199354 394*5440Sjm199354 mutex_enter(&vscan_drv_mutex); 395*5440Sjm199354 if (vscan_drv_state[inst] == VS_READING) 396*5440Sjm199354 vscan_drv_state[inst] = VS_OPEN; 397*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 398*5440Sjm199354 399*5440Sjm199354 return (rc); 400*5440Sjm199354 } 401*5440Sjm199354 402*5440Sjm199354 403*5440Sjm199354 /* 404*5440Sjm199354 * vscan_drv_ioctl 405*5440Sjm199354 */ 406*5440Sjm199354 /* ARGSUSED */ 407*5440Sjm199354 static int 408*5440Sjm199354 vscan_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 409*5440Sjm199354 cred_t *credp, int *rvalp) 410*5440Sjm199354 { 411*5440Sjm199354 int inst = getminor(dev); 412*5440Sjm199354 vs_config_t conf; 413*5440Sjm199354 414*5440Sjm199354 if (inst != 0) 415*5440Sjm199354 return (EINVAL); 416*5440Sjm199354 417*5440Sjm199354 switch (cmd) { 418*5440Sjm199354 case VS_DRV_IOCTL_ENABLE: 419*5440Sjm199354 mutex_enter(&vscan_drv_mutex); 420*5440Sjm199354 if ((!vscan_drv_connected) || 421*5440Sjm199354 (vscan_door_open((int)arg) != 0)) { 422*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 423*5440Sjm199354 return (EINVAL); 424*5440Sjm199354 } 425*5440Sjm199354 vscan_svc_enable(B_TRUE); 426*5440Sjm199354 mutex_exit(&vscan_drv_mutex); 427*5440Sjm199354 break; 428*5440Sjm199354 case VS_DRV_IOCTL_DISABLE: 429*5440Sjm199354 vscan_svc_enable(B_FALSE); 430*5440Sjm199354 break; 431*5440Sjm199354 case VS_DRV_IOCTL_CONFIG: 432*5440Sjm199354 if (ddi_copyin((void *)arg, &conf, 433*5440Sjm199354 sizeof (vs_config_t), 0) == -1) 434*5440Sjm199354 return (EFAULT); 435*5440Sjm199354 if (vscan_svc_configure(&conf) == -1) 436*5440Sjm199354 return (EINVAL); 437*5440Sjm199354 break; 438*5440Sjm199354 default: 439*5440Sjm199354 return (ENOTTY); 440*5440Sjm199354 } 441*5440Sjm199354 442*5440Sjm199354 return (0); 443*5440Sjm199354 } 444