xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_init.c (revision 02ac56e010f18fc0c5aafe47377586d8ba8c897c)
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  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
24  * Copyright 2015-2023 RackTop Systems, Inc.
25  * Copyright 2019 Joyent, Inc.
26  */
27 
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/ddi.h>
31 #include <sys/modctl.h>
32 #include <sys/cred.h>
33 #include <sys/disp.h>
34 #include <sys/id_space.h>
35 #include <sys/ioccom.h>
36 #include <sys/policy.h>
37 #include <sys/cmn_err.h>
38 #include <smbsrv/smb_kproto.h>
39 #include <smbsrv/smb_ioctl.h>
40 
41 #ifdef	_FAKE_KERNEL
42 #error	"See libfksmbsrv"
43 #endif	/* _FAKE_KERNEL */
44 
45 static int smb_drv_open(dev_t *, int, int, cred_t *);
46 static int smb_drv_open_ctl(dev_t *, int, int, cred_t *);
47 static int smb_drv_open_lib(dev_t *, int, int, cred_t *);
48 static int smb_drv_close(dev_t, int, int, cred_t *);
49 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
50 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
51 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
52 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
53 
54 
55 
56 /*
57  * *****************************************************************************
58  * ****************************** Global Variables *****************************
59  * *****************************************************************************
60  *
61  * These variables can only be changed through the /etc/system file.
62  */
63 
64 /*
65  * Maximum buffer size for NT: configurable based on the client environment.
66  * IR104720 Experiments with Windows 2000 indicate that we achieve better
67  * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used
68  * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory
69  * listing problems so this buffer size is configurable based on the end-user
70  * environment. When in doubt use 37KB.
71  */
72 int	smb_maxbufsize = SMB_NT_MAXBUF;
73 int	smb_flush_required = 1;
74 int	smb_dirsymlink_enable = 1;
75 int	smb_sign_debug = 0;
76 uint_t	smb_audit_flags =
77 #ifdef	DEBUG
78     SMB_AUDIT_NODE;
79 #else
80     0;
81 #endif
82 
83 int smb_allow_advisory_locks = 0;	/* See smb_vops.c */
84 
85 /*
86  * Maximum number of simultaneous authentication, share mapping, pipe open
87  * requests to be processed.
88  */
89 int	smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD;
90 int	smb_tcon_threshold = 1024;
91 int	smb_opipe_threshold = 1024;
92 int	smb_logoff_threshold = 1024;
93 
94 /*
95  * Number of milliseconds that a request will be stalled if it comes in after
96  * the maximum number of inflight operations are being proccessed.
97  */
98 int	smb_ssetup_timeout = (30 * 1000);
99 int	smb_tcon_timeout = (30 * 1000);
100 int	smb_opipe_timeout = (30 * 1000);
101 int	smb_logoff_timeout = (600 * 1000);
102 
103 /*
104  * Thread priorities used in smbsrv.
105  *
106  * The SMB server runs at a priority a little below the maximum for
107  * user-level process threads so it won't monopolize the CPU.
108  * Todo: make this configurable
109  *
110  * Aside from that, we want these relative priorities: (a) timers,
111  * (b) notify + oplock completions, (c) workers, (d) receivers, etc.
112  * The "base" is somewhat arbirary, and what shows up in prstat
113  * because it's used for the main thread in newproc().
114  */
115 int smbsrv_timer_pri	= MINCLSYSPRI;		/* smb_server_timers */
116 int smbsrv_base_pri	= MINCLSYSPRI - 1;	/* kshare thread, newproc */
117 int smbsrv_notify_pri	= MINCLSYSPRI - 1;	/* oplocks, notify */
118 /* Gap in which user-level administrative stuff runs. */
119 int smbsrv_worker_pri	= MINCLSYSPRI - 7;
120 int smbsrv_receive_pri	= MINCLSYSPRI - 8;
121 int smbsrv_listen_pri	= MINCLSYSPRI - 9;
122 
123 
124 /*
125  * *****************************************************************************
126  * ********************** Static Variables / Module Linkage ********************
127  * *****************************************************************************
128  */
129 
130 static struct cb_ops cbops = {
131 	smb_drv_open,		/* cb_open */
132 	smb_drv_close,		/* cb_close */
133 	nodev,			/* cb_strategy */
134 	nodev,			/* cb_print */
135 	nodev,			/* cb_dump */
136 	nodev,			/* cb_read */
137 	nodev,			/* cb_write */
138 	smb_drv_ioctl,		/* cb_ioctl */
139 	nodev,			/* cb_devmap */
140 	nodev,			/* cb_mmap */
141 	nodev,			/* cb_segmap */
142 	nochpoll,		/* cb_chpoll */
143 	ddi_prop_op,		/* cb_prop_op */
144 	NULL,			/* cb_streamtab */
145 	D_MP,			/* cb_flag */
146 	CB_REV,			/* cb_rev */
147 	nodev,			/* cb_aread */
148 	nodev,			/* cb_awrite */
149 };
150 
151 static struct dev_ops devops = {
152 	DEVO_REV,		/* devo_rev */
153 	0,			/* devo_refcnt */
154 	smb_drv_getinfo,	/* devo_getinfo */
155 	nulldev,		/* devo_identify */
156 	nulldev,		/* devo_probe */
157 	smb_drv_attach,		/* devo_attach */
158 	smb_drv_detach,		/* devo_detach */
159 	nodev,			/* devo_reset */
160 	&cbops,			/* devo_cb_ops */
161 	NULL,			/* devo_bus_ops */
162 	NULL,			/* devo_power */
163 	ddi_quiesce_not_needed,		/* devo_quiesce */
164 };
165 
166 static struct modldrv modldrv = {
167 	&mod_driverops,					/* drv_modops */
168 	"CIFS Server Protocol",				/* drv_linkinfo */
169 	&devops,
170 };
171 
172 static struct modlinkage modlinkage = {
173 	MODREV_1,	/* revision of the module, must be: MODREV_1	*/
174 	&modldrv,	/* ptr to linkage structures			*/
175 	NULL,
176 };
177 
178 static dev_info_t *smb_drv_dip = NULL;
179 static id_space_t *smb_drv_minors = NULL;
180 
181 /*
182  * ****************************************************************************
183  *				    Module Interface
184  * ****************************************************************************
185  */
186 
187 int
188 _init(void)
189 {
190 	int rc;
191 
192 	if ((rc = smb_server_g_init()) != 0) {
193 		return (rc);
194 	}
195 
196 	if ((rc = mod_install(&modlinkage)) != 0) {
197 		smb_server_g_fini();
198 	}
199 
200 	return (rc);
201 }
202 
203 int
204 _info(struct modinfo *modinfop)
205 {
206 	return (mod_info(&modlinkage, modinfop));
207 }
208 
209 int
210 _fini(void)
211 {
212 	int	rc;
213 
214 	if (smb_server_get_count() != 0)
215 		return (EBUSY);
216 
217 	if ((rc = mod_remove(&modlinkage)) == 0) {
218 		smb_server_g_fini();
219 	}
220 
221 	return (rc);
222 }
223 
224 /*
225  * ****************************************************************************
226  *				Pseudo Device Entry Points
227  * ****************************************************************************
228  */
229 /* ARGSUSED */
230 static int
231 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr)
232 {
233 	int rc;
234 	minor_t m = getminor(*devp);
235 
236 	/* See ddi_create_minor_node below */
237 	switch (m) {
238 	case 0: /* smbsrv (smbd only) */
239 		rc = smb_drv_open_ctl(devp, flag, otyp, cr);
240 		break;
241 	case 1: /* smbsrv1 (lib access) */
242 		rc = smb_drv_open_lib(devp, flag, otyp, cr);
243 		break;
244 	default:
245 		rc = ENXIO;
246 		break;
247 	}
248 	return (rc);
249 }
250 
251 /*
252  * The smbsrvctl device is exclusively for smbd.
253  * On open, this creates an smb_server_t instance.
254  * Always exclusive open here.
255  */
256 static int
257 smb_drv_open_ctl(dev_t *devp, int flag, int otyp, cred_t *cr)
258 {
259 	dev_t clone;
260 	minor_t mi;
261 	int rc;
262 
263 	/*
264 	 * Check caller's privileges.
265 	 */
266 	if (secpolicy_smb(cr) != 0)
267 		return (SET_ERROR(EPERM));
268 
269 	mi = id_allocff(smb_drv_minors);
270 	clone = makedevice(getmajor(*devp), mi);
271 
272 	/*
273 	 * Start SMB service state machine
274 	 * Note: sets sv->sv_dev = clone
275 	 */
276 	rc = smb_server_create(clone);
277 	if (rc == 0) {
278 		*devp = clone;
279 	} else {
280 		/* Open fails, eg EBUSY */
281 		id_free(smb_drv_minors, mi);
282 	}
283 
284 	return (rc);
285 }
286 
287 /*
288  * The smbsrv device is for library access to smbsrv state.
289  * Multiple open instances are allowed (clone-open).
290  */
291 static int
292 smb_drv_open_lib(dev_t *devp, int flag, int otyp, cred_t *cr)
293 {
294 	minor_t mi;
295 
296 	mi = id_allocff(smb_drv_minors);
297 	*devp = makedevice(getmajor(*devp), mi);
298 
299 	return (0);
300 }
301 
302 /*
303  * Close on unit zero (detected as: sv->sv_dev == dev)
304  * destroys the smb_server_t instance.
305  */
306 /*
307  * The smbd process keeps the control device open for the life of
308  * smbd (service process).  We know the control device is closing
309  * when the device passed to close matches the server sv_dev.
310  * When the control device closes, destroy the kernel smb_server_t
311  */
312 /* ARGSUSED */
313 static int
314 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
315 {
316 	smb_server_t	*sv;
317 
318 	if (smb_server_lookup(&sv) == 0) {
319 		if (sv->sv_dev == dev) {
320 			/* Note releases the ref on sv. */
321 			(void) smb_server_delete(sv);
322 		} else {
323 			smb_server_release(sv);
324 		}
325 	}
326 	id_free(smb_drv_minors, getminor(dev));
327 
328 	return (0);
329 }
330 
331 /* ARGSUSED */
332 static int
333 smb_drv_ioctl(dev_t dev, int cmd, intptr_t argp, int flags, cred_t *cred,
334     int *retval)
335 {
336 	smb_ioc_header_t ioc_hdr;
337 	smb_ioc_t	*ioc;
338 	smb_server_t	*sv = NULL;
339 	uint32_t	crc;
340 	boolean_t	copyout = B_FALSE;
341 	int		rc = 0;
342 	size_t		alloclen;
343 
344 	if (ddi_copyin((void *)argp, &ioc_hdr, sizeof (ioc_hdr), flags))
345 		return (SET_ERROR(EFAULT));
346 
347 	/*
348 	 * Check version and length.
349 	 *
350 	 * Note that some ioctls (i.e. SMB_IOC_SVCENUM) have payload
351 	 * data after the ioctl struct, in which case they specify a
352 	 * length much larger than sizeof smb_ioc_t.  The theoretical
353 	 * largest ioctl data is therefore the size of the union plus
354 	 * the max size of the payload (which is SMB_IOC_DATA_SIZE).
355 	 */
356 	if (ioc_hdr.version != SMB_IOC_VERSION ||
357 	    ioc_hdr.len < sizeof (ioc_hdr) ||
358 	    ioc_hdr.len > (sizeof (*ioc) + SMB_IOC_DATA_SIZE))
359 		return (SET_ERROR(EINVAL));
360 
361 	crc = ioc_hdr.crc;
362 	ioc_hdr.crc = 0;
363 	if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
364 		return (SET_ERROR(EINVAL));
365 
366 	/*
367 	 * Note that smb_ioc_t is a union, and callers set ioc_hdr.len
368 	 * to the size of the actual union arm.  If some caller were to
369 	 * set that size too small, we could end up passing under-sized
370 	 * memory to one of the type-specific handler functions.  Avoid
371 	 * that problem by allocating at least the size of the union,
372 	 * (zeroed out) and then copy in the caller specified length.
373 	 */
374 	alloclen = MAX(ioc_hdr.len, sizeof (*ioc));
375 	ioc = kmem_zalloc(alloclen, KM_SLEEP);
376 	if (ddi_copyin((void *)argp, ioc, ioc_hdr.len, flags)) {
377 		rc = SET_ERROR(EFAULT);
378 		goto out;
379 	}
380 
381 	/* Don't allow the request size to change mid-ioctl */
382 	if (ioc_hdr.len != ioc->ioc_hdr.len) {
383 		rc = SET_ERROR(EINVAL);
384 		goto out;
385 	}
386 
387 	rc = smb_server_lookup(&sv);
388 	if (rc != 0) {
389 		sv = NULL;
390 		goto out;
391 	}
392 
393 	/*
394 	 * Access control by category of ioctl codes, based on
395 	 * which device was opened, and privilege checks.
396 	 */
397 	switch (cmd) {
398 	case SMB_IOC_NUMOPEN:
399 	case SMB_IOC_SVCENUM:
400 		/*
401 		 * Non-modifying ops. no special priv.
402 		 * beyond dev open permissions.
403 		 */
404 		break;
405 
406 	case SMB_IOC_FILE_CLOSE:
407 	case SMB_IOC_SESSION_CLOSE:
408 		/*
409 		 * Modifying ops. Require privilege
410 		 * (chose one smbd normally has)
411 		 */
412 		if ((rc = secpolicy_basic_proc(cred)) != 0)
413 			goto out;
414 		break;
415 	default:
416 		/*
417 		 * The rest are only allowed on the control device.
418 		 * Note: secpolicy_smb checked in open.
419 		 */
420 		if (sv->sv_dev != dev) {
421 			rc = SET_ERROR(EPERM);
422 			goto out;
423 		}
424 		break;
425 	}
426 
427 	/*
428 	 * See similar in libfksmbrv fksmbsrv_drv_ioctl()
429 	 */
430 	switch (cmd) {
431 	case SMB_IOC_CONFIG:
432 		rc = smb_server_configure(sv, &ioc->ioc_cfg);
433 		break;
434 	case SMB_IOC_START:
435 		rc = smb_server_start(sv, &ioc->ioc_start);
436 		break;
437 	case SMB_IOC_STOP:
438 		rc = smb_server_stop(sv);
439 		break;
440 	case SMB_IOC_EVENT:
441 		rc = smb_server_notify_event(sv, &ioc->ioc_event);
442 		break;
443 	case SMB_IOC_GMTOFF:
444 		rc = smb_server_set_gmtoff(sv, &ioc->ioc_gmt);
445 		break;
446 	case SMB_IOC_SHARE:
447 		rc = smb_kshare_export_list(sv, &ioc->ioc_share);
448 		break;
449 	case SMB_IOC_UNSHARE:
450 		rc = smb_kshare_unexport_list(sv, &ioc->ioc_share);
451 		break;
452 	case SMB_IOC_SHAREINFO:
453 		rc = smb_kshare_info(sv, &ioc->ioc_shareinfo);
454 		copyout = B_TRUE;
455 		break;
456 	case SMB_IOC_SHAREACCESS:
457 		rc = smb_kshare_access(sv, &ioc->ioc_shareaccess);
458 		break;
459 	case SMB_IOC_NUMOPEN:
460 		rc = smb_server_numopen(sv, &ioc->ioc_opennum);
461 		copyout = B_TRUE;
462 		break;
463 	case SMB_IOC_SVCENUM:
464 		rc = smb_server_enum(sv, &ioc->ioc_svcenum);
465 		copyout = B_TRUE;
466 		break;
467 	case SMB_IOC_SESSION_CLOSE:
468 		rc = smb_server_session_close(sv, &ioc->ioc_session);
469 		break;
470 	case SMB_IOC_FILE_CLOSE:
471 		rc = smb_server_file_close(sv, &ioc->ioc_fileid);
472 		break;
473 	case SMB_IOC_SPOOLDOC:
474 		rc = smb_server_spooldoc(sv, &ioc->ioc_spooldoc);
475 		copyout = B_TRUE;
476 		break;
477 	default:
478 		rc = SET_ERROR(ENOTTY);
479 		break;
480 	}
481 	if ((rc == 0) && copyout) {
482 		if (ddi_copyout(ioc, (void *)argp, ioc_hdr.len, flags))
483 			rc = SET_ERROR(EFAULT);
484 	}
485 out:
486 	if (sv != NULL)
487 		smb_server_release(sv);
488 	kmem_free(ioc, alloclen);
489 	return (rc);
490 }
491 
492 /*
493  * ****************************************************************************
494  *				Pseudo Device Operations
495  * ****************************************************************************
496  */
497 static int
498 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
499 {
500 	if (cmd != DDI_ATTACH)
501 		return (DDI_FAILURE);
502 
503 	/* we only allow instance 0 to attach */
504 	if (ddi_get_instance(dip) != 0)
505 		return (DDI_FAILURE);
506 
507 	/* Create the minor nodes.  See smb_drv_open */
508 	if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
509 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
510 		cmn_err(CE_WARN, "smb_drv_attach:"
511 		    " failed creating minor node 0");
512 		return (DDI_FAILURE);
513 	}
514 	if (ddi_create_minor_node(dip, "smbsrv1", S_IFCHR, 1,
515 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
516 		cmn_err(CE_WARN, "smb_drv_attach:"
517 		    " failed creating minor node 1");
518 		ddi_remove_minor_node(dip, NULL);
519 		return (DDI_FAILURE);
520 	}
521 
522 	/* Reserved: control dev = 0, library dev = 1 */
523 	smb_drv_minors = id_space_create("smbsrv drv minors", 2, INT32_MAX);
524 	smb_drv_dip = dip;
525 
526 	return (DDI_SUCCESS);
527 }
528 
529 static int
530 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
531 {
532 	if (cmd != DDI_DETACH)
533 		return (DDI_FAILURE);
534 
535 	ASSERT(dip == smb_drv_dip);
536 	smb_drv_dip = NULL;
537 
538 	id_space_destroy(smb_drv_minors);
539 	smb_drv_minors = NULL;
540 
541 	ddi_remove_minor_node(dip, NULL);
542 
543 	return (DDI_SUCCESS);
544 }
545 
546 /* ARGSUSED */
547 static int
548 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
549 {
550 	ulong_t instance = getminor((dev_t)arg);
551 
552 	switch (cmd) {
553 	case DDI_INFO_DEVT2DEVINFO:
554 		*result = smb_drv_dip;
555 		return (DDI_SUCCESS);
556 
557 	case DDI_INFO_DEVT2INSTANCE:
558 		*result = (void *)instance;
559 		return (DDI_SUCCESS);
560 
561 	default:
562 		break;
563 	}
564 
565 	return (DDI_FAILURE);
566 }
567