FreeBSD/Linux Kernel Cross Reference
sys/netsmb/smb_dev.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: releng/12.0/sys/netsmb/smb_dev.c 333425 2018-05-09 18:47:24Z mmacy $");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/capsicum.h>
35 #include <sys/module.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/fcntl.h>
39 #include <sys/ioccom.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/file.h> /* Must come after sys/malloc.h */
43 #include <sys/filedesc.h>
44 #include <sys/mbuf.h>
45 #include <sys/poll.h>
46 #include <sys/proc.h>
47 #include <sys/select.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
51 #include <sys/uio.h>
52 #include <sys/vnode.h>
53
54 #include <net/if.h>
55
56 #include <netsmb/smb.h>
57 #include <netsmb/smb_conn.h>
58 #include <netsmb/smb_subr.h>
59 #include <netsmb/smb_dev.h>
60
61 static struct cdev *nsmb_dev;
62
63 static d_open_t nsmb_dev_open;
64 static d_ioctl_t nsmb_dev_ioctl;
65
66 MODULE_DEPEND(netsmb, libiconv, 1, 1, 2);
67 MODULE_VERSION(netsmb, NSMB_VERSION);
68
69 static int smb_version = NSMB_VERSION;
70 struct sx smb_lock;
71
72
73 SYSCTL_DECL(_net_smb);
74 SYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, "");
75
76 static MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device");
77
78 static struct cdevsw nsmb_cdevsw = {
79 .d_version = D_VERSION,
80 .d_open = nsmb_dev_open,
81 .d_ioctl = nsmb_dev_ioctl,
82 .d_name = NSMB_NAME
83 };
84
85 static int
86 nsmb_dev_init(void)
87 {
88
89 nsmb_dev = make_dev(&nsmb_cdevsw, 0, UID_ROOT, GID_OPERATOR,
90 0600, "nsmb");
91 if (nsmb_dev == NULL)
92 return (ENOMEM);
93 return (0);
94 }
95
96 static void
97 nsmb_dev_destroy(void)
98 {
99
100 MPASS(nsmb_dev != NULL);
101 destroy_dev(nsmb_dev);
102 nsmb_dev = NULL;
103 }
104
105 static struct smb_dev *
106 smbdev_alloc(struct cdev *dev)
107 {
108 struct smb_dev *sdp;
109
110 sdp = malloc(sizeof(struct smb_dev), M_NSMBDEV, M_WAITOK | M_ZERO);
111 sdp->dev = dev;
112 sdp->sd_level = -1;
113 sdp->sd_flags |= NSMBFL_OPEN;
114 sdp->refcount = 1;
115 return (sdp);
116 }
117
118 void
119 sdp_dtor(void *arg)
120 {
121 struct smb_dev *dev;
122
123 dev = (struct smb_dev *)arg;
124 SMB_LOCK();
125 sdp_trydestroy(dev);
126 SMB_UNLOCK();
127 }
128
129 static int
130 nsmb_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
131 {
132 struct smb_dev *sdp;
133 int error;
134
135 sdp = smbdev_alloc(dev);
136 error = devfs_set_cdevpriv(sdp, sdp_dtor);
137 if (error) {
138 free(sdp, M_NSMBDEV);
139 return (error);
140 }
141 return (0);
142 }
143
144 void
145 sdp_trydestroy(struct smb_dev *sdp)
146 {
147 struct smb_vc *vcp;
148 struct smb_share *ssp;
149 struct smb_cred *scred;
150
151 SMB_LOCKASSERT();
152 if (!sdp)
153 panic("No smb_dev upon device close");
154 MPASS(sdp->refcount > 0);
155 sdp->refcount--;
156 if (sdp->refcount)
157 return;
158 scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK);
159 smb_makescred(scred, curthread, NULL);
160 ssp = sdp->sd_share;
161 if (ssp != NULL) {
162 smb_share_lock(ssp);
163 smb_share_rele(ssp, scred);
164 }
165 vcp = sdp->sd_vc;
166 if (vcp != NULL) {
167 smb_vc_lock(vcp);
168 smb_vc_rele(vcp, scred);
169 }
170 free(scred, M_NSMBDEV);
171 free(sdp, M_NSMBDEV);
172 return;
173 }
174
175
176 static int
177 nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
178 {
179 struct smb_dev *sdp;
180 struct smb_vc *vcp;
181 struct smb_share *ssp;
182 struct smb_cred *scred;
183 int error = 0;
184
185 error = devfs_get_cdevpriv((void **)&sdp);
186 if (error)
187 return (error);
188 scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK);
189 SMB_LOCK();
190 smb_makescred(scred, td, NULL);
191 switch (cmd) {
192 case SMBIOC_OPENSESSION:
193 if (sdp->sd_vc) {
194 error = EISCONN;
195 goto out;
196 }
197 error = smb_usr_opensession((struct smbioc_ossn*)data,
198 scred, &vcp);
199 if (error)
200 break;
201 sdp->sd_vc = vcp;
202 smb_vc_unlock(vcp);
203 sdp->sd_level = SMBL_VC;
204 break;
205 case SMBIOC_OPENSHARE:
206 if (sdp->sd_share) {
207 error = EISCONN;
208 goto out;
209 }
210 if (sdp->sd_vc == NULL) {
211 error = ENOTCONN;
212 goto out;
213 }
214 error = smb_usr_openshare(sdp->sd_vc,
215 (struct smbioc_oshare*)data, scred, &ssp);
216 if (error)
217 break;
218 sdp->sd_share = ssp;
219 smb_share_unlock(ssp);
220 sdp->sd_level = SMBL_SHARE;
221 break;
222 case SMBIOC_REQUEST:
223 if (sdp->sd_share == NULL) {
224 error = ENOTCONN;
225 goto out;
226 }
227 error = smb_usr_simplerequest(sdp->sd_share,
228 (struct smbioc_rq*)data, scred);
229 break;
230 case SMBIOC_T2RQ:
231 if (sdp->sd_share == NULL) {
232 error = ENOTCONN;
233 goto out;
234 }
235 error = smb_usr_t2request(sdp->sd_share,
236 (struct smbioc_t2rq*)data, scred);
237 break;
238 case SMBIOC_SETFLAGS: {
239 struct smbioc_flags *fl = (struct smbioc_flags*)data;
240 int on;
241
242 if (fl->ioc_level == SMBL_VC) {
243 if (fl->ioc_mask & SMBV_PERMANENT) {
244 on = fl->ioc_flags & SMBV_PERMANENT;
245 if ((vcp = sdp->sd_vc) == NULL) {
246 error = ENOTCONN;
247 goto out;
248 }
249 error = smb_vc_get(vcp, scred);
250 if (error)
251 break;
252 if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
253 vcp->obj.co_flags |= SMBV_PERMANENT;
254 smb_vc_ref(vcp);
255 } else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) {
256 vcp->obj.co_flags &= ~SMBV_PERMANENT;
257 smb_vc_rele(vcp, scred);
258 }
259 smb_vc_put(vcp, scred);
260 } else
261 error = EINVAL;
262 } else if (fl->ioc_level == SMBL_SHARE) {
263 if (fl->ioc_mask & SMBS_PERMANENT) {
264 on = fl->ioc_flags & SMBS_PERMANENT;
265 if ((ssp = sdp->sd_share) == NULL) {
266 error = ENOTCONN;
267 goto out;
268 }
269 error = smb_share_get(ssp, scred);
270 if (error)
271 break;
272 if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
273 ssp->obj.co_flags |= SMBS_PERMANENT;
274 smb_share_ref(ssp);
275 } else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) {
276 ssp->obj.co_flags &= ~SMBS_PERMANENT;
277 smb_share_rele(ssp, scred);
278 }
279 smb_share_put(ssp, scred);
280 } else
281 error = EINVAL;
282 break;
283 } else
284 error = EINVAL;
285 break;
286 }
287 case SMBIOC_LOOKUP:
288 if (sdp->sd_vc || sdp->sd_share) {
289 error = EISCONN;
290 goto out;
291 }
292 vcp = NULL;
293 ssp = NULL;
294 error = smb_usr_lookup((struct smbioc_lookup*)data, scred, &vcp, &ssp);
295 if (error)
296 break;
297 if (vcp) {
298 sdp->sd_vc = vcp;
299 smb_vc_unlock(vcp);
300 sdp->sd_level = SMBL_VC;
301 }
302 if (ssp) {
303 sdp->sd_share = ssp;
304 smb_share_unlock(ssp);
305 sdp->sd_level = SMBL_SHARE;
306 }
307 break;
308 case SMBIOC_READ: case SMBIOC_WRITE: {
309 struct smbioc_rw *rwrq = (struct smbioc_rw*)data;
310 struct uio auio;
311 struct iovec iov;
312
313 if ((ssp = sdp->sd_share) == NULL) {
314 error = ENOTCONN;
315 goto out;
316 }
317 iov.iov_base = rwrq->ioc_base;
318 iov.iov_len = rwrq->ioc_cnt;
319 auio.uio_iov = &iov;
320 auio.uio_iovcnt = 1;
321 auio.uio_offset = rwrq->ioc_offset;
322 auio.uio_resid = rwrq->ioc_cnt;
323 auio.uio_segflg = UIO_USERSPACE;
324 auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE;
325 auio.uio_td = td;
326 if (cmd == SMBIOC_READ)
327 error = smb_read(ssp, rwrq->ioc_fh, &auio, scred);
328 else
329 error = smb_write(ssp, rwrq->ioc_fh, &auio, scred);
330 rwrq->ioc_cnt -= auio.uio_resid;
331 break;
332 }
333 default:
334 error = ENODEV;
335 }
336 out:
337 free(scred, M_NSMBDEV);
338 SMB_UNLOCK();
339 return error;
340 }
341
342 static int
343 nsmb_dev_load(module_t mod, int cmd, void *arg)
344 {
345 int error = 0;
346
347 switch (cmd) {
348 case MOD_LOAD:
349 error = smb_sm_init();
350 if (error)
351 break;
352 error = smb_iod_init();
353 if (error) {
354 smb_sm_done();
355 break;
356 }
357 error = nsmb_dev_init();
358 if (error)
359 break;
360 sx_init(&smb_lock, "samba device lock");
361 break;
362 case MOD_UNLOAD:
363 smb_iod_done();
364 error = smb_sm_done();
365 if (error)
366 break;
367 nsmb_dev_destroy();
368 sx_destroy(&smb_lock);
369 break;
370 default:
371 error = EINVAL;
372 break;
373 }
374 return error;
375 }
376
377 DEV_MODULE (dev_netsmb, nsmb_dev_load, 0);
378
379 int
380 smb_dev2share(int fd, int mode, struct smb_cred *scred,
381 struct smb_share **sspp, struct smb_dev **ssdp)
382 {
383 struct file *fp, *fptmp;
384 struct smb_dev *sdp;
385 struct smb_share *ssp;
386 struct thread *td;
387 int error;
388
389 td = curthread;
390 error = fget(td, fd, &cap_read_rights, &fp);
391 if (error)
392 return (error);
393 fptmp = td->td_fpop;
394 td->td_fpop = fp;
395 error = devfs_get_cdevpriv((void **)&sdp);
396 td->td_fpop = fptmp;
397 fdrop(fp, td);
398 if (error || sdp == NULL)
399 return (error);
400 SMB_LOCK();
401 *ssdp = sdp;
402 ssp = sdp->sd_share;
403 if (ssp == NULL) {
404 SMB_UNLOCK();
405 return (ENOTCONN);
406 }
407 error = smb_share_get(ssp, scred);
408 if (error == 0) {
409 sdp->refcount++;
410 *sspp = ssp;
411 }
412 SMB_UNLOCK();
413 return error;
414 }
415
Cache object: 7d10ff5e9ada61ecee166963b8fee161
|