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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/ddi.h> 27 #include <sys/modctl.h> 28 #include <sys/cred.h> 29 #include <sys/ioccom.h> 30 #include <sys/policy.h> 31 #include <sys/cmn_err.h> 32 #include <smbsrv/smb_kproto.h> 33 #include <smbsrv/smb_ioctl.h> 34 35 static int smb_drv_open(dev_t *, int, int, cred_t *); 36 static int smb_drv_close(dev_t, int, int, cred_t *); 37 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 38 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 39 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 40 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 41 42 /* 43 * ***************************************************************************** 44 * ****************************** Global Variables ***************************** 45 * ***************************************************************************** 46 * 47 * These variables can only be changed through the /etc/system file. 48 */ 49 50 /* 51 * Maximum buffer size for NT: configurable based on the client environment. 52 * IR104720 Experiments with Windows 2000 indicate that we achieve better 53 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 54 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 55 * listing problems so this buffer size is configurable based on the end-user 56 * environment. When in doubt use 37KB. 57 * 58 * smb_raw_mode: read_raw and write_raw supported (1) or NOT supported (0). 59 */ 60 int smb_maxbufsize = SMB_NT_MAXBUF; 61 int smb_oplock_levelII = 1; 62 int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 63 int smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT; 64 int smb_flush_required = 1; 65 int smb_dirsymlink_enable = 1; 66 int smb_sign_debug = 0; 67 int smb_raw_mode = 1; 68 int smb_shortnames = 1; 69 uint_t smb_audit_flags = 70 #ifdef DEBUG 71 SMB_AUDIT_NODE; 72 #else 73 0; 74 #endif 75 76 /* 77 * Maximum number of simultaneous authentication, share mapping, pipe open 78 * requests to be processed. 79 */ 80 int smb_ssetup_threshold = 256; 81 int smb_tcon_threshold = 1024; 82 int smb_opipe_threshold = 1024; 83 84 /* 85 * Number of milliseconds that a request will be stalled if it comes in after 86 * the maximum number of inflight operations are being proccessed. 87 */ 88 int smb_ssetup_timeout = (30 * 1000); 89 int smb_tcon_timeout = (30 * 1000); 90 int smb_opipe_timeout = (30 * 1000); 91 92 int smb_threshold_debug = 0; 93 94 95 /* 96 * ***************************************************************************** 97 * ********************** Static Variables / Module Linkage ******************** 98 * ***************************************************************************** 99 */ 100 101 static struct cb_ops cbops = { 102 smb_drv_open, /* cb_open */ 103 smb_drv_close, /* cb_close */ 104 nodev, /* cb_strategy */ 105 nodev, /* cb_print */ 106 nodev, /* cb_dump */ 107 nodev, /* cb_read */ 108 nodev, /* cb_write */ 109 smb_drv_ioctl, /* cb_ioctl */ 110 nodev, /* cb_devmap */ 111 nodev, /* cb_mmap */ 112 nodev, /* cb_segmap */ 113 nochpoll, /* cb_chpoll */ 114 ddi_prop_op, /* cb_prop_op */ 115 NULL, /* cb_streamtab */ 116 D_MP, /* cb_flag */ 117 CB_REV, /* cb_rev */ 118 nodev, /* cb_aread */ 119 nodev, /* cb_awrite */ 120 }; 121 122 static struct dev_ops devops = { 123 DEVO_REV, /* devo_rev */ 124 0, /* devo_refcnt */ 125 smb_drv_getinfo, /* devo_getinfo */ 126 nulldev, /* devo_identify */ 127 nulldev, /* devo_probe */ 128 smb_drv_attach, /* devo_attach */ 129 smb_drv_detach, /* devo_detach */ 130 nodev, /* devo_reset */ 131 &cbops, /* devo_cb_ops */ 132 NULL, /* devo_bus_ops */ 133 NULL, /* devo_power */ 134 ddi_quiesce_not_needed, /* devo_quiesce */ 135 }; 136 137 static struct modldrv modldrv = { 138 &mod_driverops, /* drv_modops */ 139 "CIFS Server Protocol", /* drv_linkinfo */ 140 &devops, 141 }; 142 143 static struct modlinkage modlinkage = { 144 MODREV_1, /* revision of the module, must be: MODREV_1 */ 145 &modldrv, /* ptr to linkage structures */ 146 NULL, 147 }; 148 149 static dev_info_t *smb_drv_dip = NULL; 150 151 /* 152 * **************************************************************************** 153 * Module Interface 154 * **************************************************************************** 155 */ 156 157 int 158 _init(void) 159 { 160 int rc; 161 162 if ((rc = smb_kshare_init()) != 0) 163 return (rc); 164 165 if ((rc = smb_server_svc_init()) != 0) { 166 smb_kshare_fini(); 167 return (rc); 168 } 169 170 if ((rc = mod_install(&modlinkage)) != 0) { 171 smb_kshare_fini(); 172 (void) smb_server_svc_fini(); 173 } 174 175 return (rc); 176 } 177 178 int 179 _info(struct modinfo *modinfop) 180 { 181 return (mod_info(&modlinkage, modinfop)); 182 } 183 184 int 185 _fini(void) 186 { 187 int rc; 188 189 if ((rc = mod_remove(&modlinkage)) == 0) { 190 rc = smb_server_svc_fini(); 191 smb_kshare_fini(); 192 } 193 194 return (rc); 195 } 196 197 /* 198 * **************************************************************************** 199 * Pseudo Device Entry Points 200 * **************************************************************************** 201 */ 202 /* ARGSUSED */ 203 static int 204 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 205 { 206 /* 207 * Check caller's privileges. 208 */ 209 if (secpolicy_smb(credp) != 0) 210 return (EPERM); 211 212 /* 213 * Start SMB service state machine 214 */ 215 return (smb_server_create()); 216 } 217 218 /* ARGSUSED */ 219 static int 220 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 221 { 222 return (smb_server_delete()); 223 } 224 225 /* ARGSUSED */ 226 static int 227 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 228 int *retval) 229 { 230 smb_ioc_t *ioc; 231 smb_ioc_header_t ioc_hdr; 232 uint32_t crc; 233 boolean_t copyout = B_FALSE; 234 int rc = 0; 235 236 if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t), 237 flags) || (ioc_hdr.version != SMB_IOC_VERSION)) 238 return (EFAULT); 239 240 crc = ioc_hdr.crc; 241 ioc_hdr.crc = 0; 242 if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 243 return (EFAULT); 244 245 ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP); 246 if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) { 247 kmem_free(ioc, ioc_hdr.len); 248 return (EFAULT); 249 } 250 251 switch (cmd) { 252 case SMB_IOC_CONFIG: 253 rc = smb_server_configure(&ioc->ioc_cfg); 254 break; 255 case SMB_IOC_START: 256 rc = smb_server_start(&ioc->ioc_start); 257 break; 258 case SMB_IOC_STOP: 259 rc = smb_server_stop(); 260 break; 261 case SMB_IOC_EVENT: 262 rc = smb_server_notify_event(&ioc->ioc_event); 263 break; 264 case SMB_IOC_NBT_LISTEN: 265 rc = smb_server_nbt_listen(&ioc->ioc_listen); 266 break; 267 case SMB_IOC_TCP_LISTEN: 268 rc = smb_server_tcp_listen(&ioc->ioc_listen); 269 break; 270 case SMB_IOC_NBT_RECEIVE: 271 rc = smb_server_nbt_receive(); 272 break; 273 case SMB_IOC_TCP_RECEIVE: 274 rc = smb_server_tcp_receive(); 275 break; 276 case SMB_IOC_GMTOFF: 277 rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 278 break; 279 case SMB_IOC_SHARE: 280 rc = smb_kshare_export_list(&ioc->ioc_share); 281 break; 282 case SMB_IOC_UNSHARE: 283 rc = smb_kshare_unexport_list(&ioc->ioc_share); 284 break; 285 case SMB_IOC_SHAREINFO: 286 rc = smb_kshare_info(&ioc->ioc_shareinfo); 287 copyout = B_TRUE; 288 break; 289 case SMB_IOC_NUMOPEN: 290 rc = smb_server_numopen(&ioc->ioc_opennum); 291 copyout = B_TRUE; 292 break; 293 case SMB_IOC_SVCENUM: 294 rc = smb_server_enum(&ioc->ioc_svcenum); 295 copyout = B_TRUE; 296 break; 297 case SMB_IOC_SESSION_CLOSE: 298 rc = smb_server_session_close(&ioc->ioc_session); 299 break; 300 case SMB_IOC_FILE_CLOSE: 301 rc = smb_server_file_close(&ioc->ioc_fileid); 302 break; 303 case SMB_IOC_SPOOLDOC: 304 rc = smb_server_spooldoc(&ioc->ioc_spooldoc); 305 copyout = B_TRUE; 306 break; 307 default: 308 rc = ENOTTY; 309 break; 310 } 311 if ((rc == 0) && copyout) { 312 if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len, 313 flags)) 314 rc = EFAULT; 315 } 316 kmem_free(ioc, ioc_hdr.len); 317 return (rc); 318 } 319 320 /* 321 * **************************************************************************** 322 * Pseudo Device Operations 323 * **************************************************************************** 324 */ 325 static int 326 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 327 { 328 if (cmd == DDI_ATTACH) { 329 /* we only allow instance 0 to attach */ 330 if (ddi_get_instance(dip) == 0) { 331 /* create the minor node */ 332 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 333 DDI_PSEUDO, 0) == DDI_SUCCESS) { 334 smb_drv_dip = dip; 335 return (DDI_SUCCESS); 336 } else { 337 cmn_err(CE_WARN, "smb_drv_attach:" 338 " failed creating minor node"); 339 } 340 } 341 } 342 return (DDI_FAILURE); 343 } 344 345 static int 346 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 347 { 348 if (cmd == DDI_DETACH) { 349 ASSERT(dip == smb_drv_dip); 350 ddi_remove_minor_node(dip, NULL); 351 smb_drv_dip = NULL; 352 return (DDI_SUCCESS); 353 } 354 return (DDI_FAILURE); 355 } 356 357 /* ARGSUSED */ 358 static int 359 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 360 { 361 ulong_t instance = getminor((dev_t)arg); 362 363 switch (cmd) { 364 case DDI_INFO_DEVT2DEVINFO: 365 *result = smb_drv_dip; 366 return (DDI_SUCCESS); 367 368 case DDI_INFO_DEVT2INSTANCE: 369 *result = (void *)instance; 370 return (DDI_SUCCESS); 371 372 default: 373 break; 374 } 375 376 return (DDI_FAILURE); 377 } 378