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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/ddi.h> 28 #include <sys/modctl.h> 29 #include <sys/cred.h> 30 #include <sys/ioccom.h> 31 #include <sys/policy.h> 32 #include <sys/cmn_err.h> 33 #include <smbsrv/smb_incl.h> 34 #include <smbsrv/smb_door_svc.h> 35 #include <smbsrv/smb_ioctl.h> 36 #include <smbsrv/smb_kproto.h> 37 38 static int smb_drv_open(dev_t *, int, int, cred_t *); 39 static int smb_drv_close(dev_t, int, int, cred_t *); 40 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 41 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 42 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 43 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 44 45 /* 46 * ***************************************************************************** 47 * ****************************** Global Variables ***************************** 48 * ***************************************************************************** 49 * 50 * These variables can only be changed through the /etc/system file. 51 */ 52 53 /* 54 * Maximum buffer size for NT: configurable based on the client environment. 55 * IR104720 Experiments with Windows 2000 indicate that we achieve better 56 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 57 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 58 * listing problems so this buffer size is configurable based on the end-user 59 * environment. When in doubt use 37KB. 60 */ 61 int smb_maxbufsize = SMB_NT_MAXBUF; 62 clock_t smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 63 int smb_flush_required = 1; 64 int smb_dirsymlink_enable = 1; 65 int smb_announce_quota = 0; 66 int smb_sign_debug = 0; 67 68 /* 69 * ***************************************************************************** 70 * ********************** Static Variables / Module Linkage ******************** 71 * ***************************************************************************** 72 */ 73 74 static struct cb_ops cbops = { 75 smb_drv_open, /* cb_open */ 76 smb_drv_close, /* cb_close */ 77 nodev, /* cb_strategy */ 78 nodev, /* cb_print */ 79 nodev, /* cb_dump */ 80 nodev, /* cb_read */ 81 nodev, /* cb_write */ 82 smb_drv_ioctl, /* cb_ioctl */ 83 nodev, /* cb_devmap */ 84 nodev, /* cb_mmap */ 85 nodev, /* cb_segmap */ 86 nochpoll, /* cb_chpoll */ 87 ddi_prop_op, /* cb_prop_op */ 88 NULL, /* cb_streamtab */ 89 D_MP, /* cb_flag */ 90 CB_REV, /* cb_rev */ 91 nodev, /* cb_aread */ 92 nodev, /* cb_awrite */ 93 }; 94 95 static struct dev_ops devops = { 96 DEVO_REV, /* devo_rev */ 97 0, /* devo_refcnt */ 98 smb_drv_getinfo, /* devo_getinfo */ 99 nulldev, /* devo_identify */ 100 nulldev, /* devo_probe */ 101 smb_drv_attach, /* devo_attach */ 102 smb_drv_detach, /* devo_detach */ 103 nodev, /* devo_reset */ 104 &cbops, /* devo_cb_ops */ 105 NULL, /* devo_bus_ops */ 106 NULL, /* devo_power */ 107 ddi_quiesce_not_needed, /* devo_quiesce */ 108 }; 109 110 static struct modldrv modldrv = { 111 &mod_driverops, /* drv_modops */ 112 "CIFS Server Protocol", /* drv_linkinfo */ 113 &devops, 114 }; 115 116 static struct modlinkage modlinkage = { 117 MODREV_1, /* revision of the module, must be: MODREV_1 */ 118 &modldrv, /* ptr to linkage structures */ 119 NULL, 120 }; 121 122 static dev_info_t *smb_drv_dip = NULL; 123 124 /* 125 * **************************************************************************** 126 * Module Interface 127 * **************************************************************************** 128 */ 129 130 int 131 _init(void) 132 { 133 int rc; 134 135 rc = smb_server_svc_init(); 136 if (rc == 0) { 137 rc = mod_install(&modlinkage); 138 if (rc != 0) 139 (void) smb_server_svc_fini(); 140 } 141 return (rc); 142 } 143 144 int 145 _info(struct modinfo *modinfop) 146 { 147 return (mod_info(&modlinkage, modinfop)); 148 } 149 150 int 151 _fini(void) 152 { 153 int rc; 154 155 rc = mod_remove(&modlinkage); 156 if (rc == 0) 157 rc = smb_server_svc_fini(); 158 return (rc); 159 } 160 161 /* 162 * **************************************************************************** 163 * Pseudo Device Entry Points 164 * **************************************************************************** 165 */ 166 /* ARGSUSED */ 167 static int 168 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 169 { 170 /* 171 * Check caller's privileges. 172 */ 173 if (secpolicy_smb(credp) != 0) 174 return (EPERM); 175 176 /* 177 * Start SMB service state machine 178 */ 179 return (smb_server_create()); 180 } 181 182 /* ARGSUSED */ 183 static int 184 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 185 { 186 return (smb_server_delete()); 187 } 188 189 /* ARGSUSED */ 190 static int 191 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred, 192 int *retval) 193 { 194 int rc = 0; 195 smb_io_t smb_io; 196 uint32_t crc1; 197 uint32_t crc2; 198 199 if (ddi_copyin((smb_io_t *)argp, &smb_io, sizeof (smb_io), flag) || 200 (smb_io.sio_version != SMB_IOC_VERSION)) 201 return (EFAULT); 202 203 crc1 = smb_io.sio_crc; 204 smb_io.sio_crc = 0; 205 crc2 = smb_crc_gen((uint8_t *)&smb_io, sizeof (smb_io_t)); 206 207 if (crc1 != crc2) 208 return (EFAULT); 209 210 switch (cmd) { 211 case SMB_IOC_CONFIG: 212 rc = smb_server_configure(&smb_io.sio_data.cfg); 213 break; 214 case SMB_IOC_START: 215 rc = smb_server_start(&smb_io.sio_data.start); 216 break; 217 case SMB_IOC_NBT_LISTEN: 218 rc = smb_server_nbt_listen(smb_io.sio_data.error); 219 break; 220 case SMB_IOC_TCP_LISTEN: 221 rc = smb_server_tcp_listen(smb_io.sio_data.error); 222 break; 223 case SMB_IOC_NBT_RECEIVE: 224 rc = smb_server_nbt_receive(); 225 break; 226 case SMB_IOC_TCP_RECEIVE: 227 rc = smb_server_tcp_receive(); 228 break; 229 case SMB_IOC_GMTOFF: 230 rc = smb_server_set_gmtoff(smb_io.sio_data.gmtoff); 231 break; 232 default: 233 rc = ENOTTY; 234 break; 235 } 236 237 return (rc); 238 } 239 240 /* 241 * **************************************************************************** 242 * Pseudo Device Operations 243 * **************************************************************************** 244 */ 245 static int 246 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 247 { 248 if (cmd == DDI_ATTACH) { 249 /* we only allow instance 0 to attach */ 250 if (ddi_get_instance(dip) == 0) { 251 /* create the minor node */ 252 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 253 DDI_PSEUDO, 0) == DDI_SUCCESS) { 254 smb_drv_dip = dip; 255 return (DDI_SUCCESS); 256 } else { 257 cmn_err(CE_WARN, "smb_drv_attach:" 258 " failed creating minor node"); 259 } 260 } 261 } 262 return (DDI_FAILURE); 263 } 264 265 static int 266 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 267 { 268 if (cmd == DDI_DETACH) { 269 ASSERT(dip == smb_drv_dip); 270 ddi_remove_minor_node(dip, NULL); 271 smb_drv_dip = NULL; 272 return (DDI_SUCCESS); 273 } 274 return (DDI_FAILURE); 275 } 276 277 /* ARGSUSED */ 278 static int 279 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 280 { 281 ulong_t instance = getminor((dev_t)arg); 282 283 switch (cmd) { 284 case DDI_INFO_DEVT2DEVINFO: 285 *result = smb_drv_dip; 286 return (DDI_SUCCESS); 287 288 case DDI_INFO_DEVT2INSTANCE: 289 *result = (void *)instance; 290 return (DDI_SUCCESS); 291 292 default: 293 break; 294 } 295 296 return (DDI_FAILURE); 297 } 298