1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
33 */
34
35 /*
36 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
37 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
38 * Use is subject to license terms.
39 */
40
41 #include <sys/param.h>
42 #include <sys/kmem.h>
43 #include <sys/systm.h>
44 #include <sys/policy.h>
45 #include <sys/conf.h>
46 #include <sys/proc.h>
47 #include <sys/fcntl.h>
48 #include <sys/file.h>
49 #include <sys/socket.h>
50 #include <sys/sunddi.h>
51 #include <sys/cmn_err.h>
52
53 #include <netsmb/smb_osdep.h>
54
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_conn.h>
57 #include <netsmb/smb_rq.h>
58 #include <netsmb/smb_subr.h>
59 #include <netsmb/smb_dev.h>
60
61 static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
62
63 /*
64 * Ioctl function for SMBIOC_FLAGS2
65 */
66 int
smb_usr_get_flags2(smb_dev_t * sdp,intptr_t arg,int flags)67 smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
68 {
69 struct smb_vc *vcp = NULL;
70
71 /* This ioctl requires a session. */
72 if ((vcp = sdp->sd_vc) == NULL)
73 return (ENOTCONN);
74
75 /*
76 * Return the flags2 value.
77 */
78 if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
79 sizeof (u_int16_t), flags))
80 return (EFAULT);
81
82 return (0);
83 }
84
85 /*
86 * Ioctl function for SMBIOC_GETSSNKEY
87 * Size copied out is SMBIOC_HASH_SZ.
88 *
89 * The RPC library needs this for encrypting things
90 * like "set password" requests. This is called
91 * with an active RPC binding, so the connection
92 * will already be active (but this checks).
93 */
94 int
smb_usr_get_ssnkey(smb_dev_t * sdp,intptr_t arg,int flags)95 smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
96 {
97 struct smb_vc *vcp = NULL;
98
99 /* This ioctl requires an active session. */
100 if ((vcp = sdp->sd_vc) == NULL)
101 return (ENOTCONN);
102 if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
103 return (ENOTCONN);
104
105 /*
106 * Return the session key.
107 */
108 if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
109 SMBIOC_HASH_SZ, flags))
110 return (EFAULT);
111
112 return (0);
113 }
114
115 /*
116 * Ioctl function for SMBIOC_REQUEST
117 */
118 int
smb_usr_simplerq(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)119 smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
120 {
121 struct smb_cred scred;
122 struct smb_share *ssp;
123 smbioc_rq_t *ioc = NULL;
124 struct smb_rq *rqp = NULL;
125 struct mbchain *mbp;
126 struct mdchain *mdp;
127 uint32_t rsz;
128 int err, mbseg;
129
130 /* This ioctl requires a share. */
131 if ((ssp = sdp->sd_share) == NULL)
132 return (ENOTCONN);
133
134 smb_credinit(&scred, cr);
135 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
136 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
137 err = EFAULT;
138 goto out;
139 }
140
141 /* See ddi_copyin, ddi_copyout */
142 mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
143
144 /*
145 * Lots of SMB commands could be safe, but
146 * these are the only ones used by libsmbfs.
147 */
148 switch (ioc->ioc_cmd) {
149 /* These are OK */
150 case SMB_COM_CLOSE:
151 case SMB_COM_FLUSH:
152 case SMB_COM_NT_CREATE_ANDX:
153 case SMB_COM_OPEN_PRINT_FILE:
154 case SMB_COM_CLOSE_PRINT_FILE:
155 break;
156
157 default:
158 err = EPERM;
159 goto out;
160 }
161
162 err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
163 if (err)
164 goto out;
165
166 mbp = &rqp->sr_rq;
167 err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
168
169 err = smb_rq_simple(rqp);
170 if (err == 0) {
171 /*
172 * This may have been an open, so save the
173 * generation ID of the share, which we
174 * check before trying read or write.
175 */
176 sdp->sd_vcgenid = ssp->ss_vcgenid;
177
178 /*
179 * Have reply data. to copyout.
180 * SMB header already parsed.
181 */
182 mdp = &rqp->sr_rp;
183 rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
184 if (ioc->ioc_rbufsz < rsz) {
185 err = EOVERFLOW;
186 goto out;
187 }
188 ioc->ioc_rbufsz = rsz;
189 err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
190 if (err)
191 goto out;
192
193 }
194
195 ioc->ioc_errclass = rqp->sr_errclass;
196 ioc->ioc_serror = rqp->sr_serror;
197 ioc->ioc_error = rqp->sr_error;
198 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
199
200 out:
201 if (rqp != NULL)
202 smb_rq_done(rqp); /* free rqp */
203 kmem_free(ioc, sizeof (*ioc));
204 smb_credrele(&scred);
205
206 return (err);
207
208 }
209
210 /*
211 * Ioctl function for SMBIOC_T2RQ
212 */
213 int
smb_usr_t2request(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)214 smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
215 {
216 struct smb_cred scred;
217 struct smb_share *ssp;
218 smbioc_t2rq_t *ioc = NULL;
219 struct smb_t2rq *t2p = NULL;
220 struct mdchain *mdp;
221 int err, len, mbseg;
222
223 /* This ioctl requires a share. */
224 if ((ssp = sdp->sd_share) == NULL)
225 return (ENOTCONN);
226
227 smb_credinit(&scred, cr);
228 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
229 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
230 err = EFAULT;
231 goto out;
232 }
233
234 /* See ddi_copyin, ddi_copyout */
235 mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
236
237 if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
238 err = EINVAL;
239 goto out;
240 }
241
242 /*
243 * Fill in the FID for libsmbfs transact named pipe.
244 */
245 if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
246 if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
247 err = ESTALE;
248 goto out;
249 }
250 ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
251 }
252
253 t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
254 err = smb_t2_init(t2p, SSTOCP(ssp),
255 ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
256 if (err)
257 goto out;
258 t2p->t2_setupcount = ioc->ioc_setupcnt;
259 t2p->t2_setupdata = ioc->ioc_setup;
260
261 /* This ioc member is a fixed-size array. */
262 if (ioc->ioc_name[0]) {
263 /* Get the name length - carefully! */
264 ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
265 t2p->t_name_len = strlen(ioc->ioc_name);
266 t2p->t_name = ioc->ioc_name;
267 }
268 t2p->t2_maxscount = 0;
269 t2p->t2_maxpcount = ioc->ioc_rparamcnt;
270 t2p->t2_maxdcount = ioc->ioc_rdatacnt;
271
272 /* Transmit parameters */
273 err = smb_cpdatain(&t2p->t2_tparam,
274 ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
275 if (err)
276 goto out;
277
278 /* Transmit data */
279 err = smb_cpdatain(&t2p->t2_tdata,
280 ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
281 if (err)
282 goto out;
283
284 err = smb_t2_request(t2p);
285
286 /* Copyout returned parameters. */
287 mdp = &t2p->t2_rparam;
288 if (err == 0 && mdp->md_top != NULL) {
289 /* User's buffer large enough? */
290 len = m_fixhdr(mdp->md_top);
291 if (len > ioc->ioc_rparamcnt) {
292 err = EMSGSIZE;
293 goto out;
294 }
295 ioc->ioc_rparamcnt = (ushort_t)len;
296 err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
297 if (err)
298 goto out;
299 } else
300 ioc->ioc_rparamcnt = 0;
301
302 /* Copyout returned data. */
303 mdp = &t2p->t2_rdata;
304 if (err == 0 && mdp->md_top != NULL) {
305 /* User's buffer large enough? */
306 len = m_fixhdr(mdp->md_top);
307 if (len > ioc->ioc_rdatacnt) {
308 err = EMSGSIZE;
309 goto out;
310 }
311 ioc->ioc_rdatacnt = (ushort_t)len;
312 err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
313 if (err)
314 goto out;
315 } else
316 ioc->ioc_rdatacnt = 0;
317
318 ioc->ioc_errclass = t2p->t2_sr_errclass;
319 ioc->ioc_serror = t2p->t2_sr_serror;
320 ioc->ioc_error = t2p->t2_sr_error;
321 ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
322
323 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
324
325
326 out:
327 if (t2p != NULL) {
328 /* Note: t2p->t_name no longer allocated */
329 smb_t2_done(t2p);
330 kmem_free(t2p, sizeof (*t2p));
331 }
332 kmem_free(ioc, sizeof (*ioc));
333 smb_credrele(&scred);
334
335 return (err);
336 }
337
338 /* helper for _t2request */
339 static int
smb_cpdatain(struct mbchain * mbp,int len,char * data,int mbseg)340 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
341 {
342 int error;
343
344 if (len == 0)
345 return (0);
346 error = mb_init(mbp);
347 if (error)
348 return (error);
349 return (mb_put_mem(mbp, data, len, mbseg));
350 }
351
352 /*
353 * Helper for nsmb_ioctl cases
354 * SMBIOC_READ, SMBIOC_WRITE
355 */
356 int
smb_usr_rw(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)357 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
358 {
359 struct smb_cred scred;
360 struct smb_share *ssp;
361 smbioc_rw_t *ioc = NULL;
362 struct iovec aiov[1];
363 struct uio auio;
364 uint16_t fh;
365 int err;
366 uio_rw_t rw;
367
368 /* This ioctl requires a share. */
369 if ((ssp = sdp->sd_share) == NULL)
370 return (ENOTCONN);
371
372 /* After reconnect, force close+reopen */
373 if (sdp->sd_vcgenid != ssp->ss_vcgenid)
374 return (ESTALE);
375
376 smb_credinit(&scred, cr);
377 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
378 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
379 err = EFAULT;
380 goto out;
381 }
382
383 switch (cmd) {
384 case SMBIOC_READ:
385 rw = UIO_READ;
386 break;
387 case SMBIOC_WRITE:
388 rw = UIO_WRITE;
389 break;
390 default:
391 err = ENODEV;
392 goto out;
393 }
394
395 /*
396 * If caller passes -1 in ioc_fh, then
397 * use the FID from SMBIOC_NTCREATE.
398 */
399 if (ioc->ioc_fh == -1)
400 fh = (uint16_t)sdp->sd_smbfid;
401 else
402 fh = (uint16_t)ioc->ioc_fh;
403
404 aiov[0].iov_base = ioc->ioc_base;
405 aiov[0].iov_len = (size_t)ioc->ioc_cnt;
406
407 auio.uio_iov = aiov;
408 auio.uio_iovcnt = 1;
409 auio.uio_loffset = ioc->ioc_offset;
410 auio.uio_segflg = (flags & FKIOCTL) ?
411 UIO_SYSSPACE : UIO_USERSPACE;
412 auio.uio_fmode = 0;
413 auio.uio_resid = (size_t)ioc->ioc_cnt;
414
415 err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
416
417 /*
418 * On return ioc_cnt holds the
419 * number of bytes transferred.
420 */
421 ioc->ioc_cnt -= auio.uio_resid;
422
423 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
424
425 out:
426 kmem_free(ioc, sizeof (*ioc));
427 smb_credrele(&scred);
428
429 return (err);
430 }
431
432 /*
433 * Helper for nsmb_ioctl case
434 * SMBIOC_NTCREATE
435 */
436 int
smb_usr_ntcreate(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)437 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
438 {
439 struct smb_cred scred;
440 struct mbchain name_mb;
441 struct smb_share *ssp;
442 smbioc_ntcreate_t *ioc = NULL;
443 uint16_t fid;
444 int err, nmlen;
445
446 /* This ioctl requires a share. */
447 if ((ssp = sdp->sd_share) == NULL)
448 return (ENOTCONN);
449
450 /* Must not be already open. */
451 if (sdp->sd_smbfid != -1)
452 return (EINVAL);
453
454 mb_init(&name_mb);
455 smb_credinit(&scred, cr);
456 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
457 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
458 err = EFAULT;
459 goto out;
460 }
461
462 /* Build name_mb */
463 ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
464 nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
465 err = smb_put_dmem(&name_mb, SSTOVC(ssp),
466 ioc->ioc_name, nmlen,
467 SMB_CS_NONE, NULL);
468 if (err != 0)
469 goto out;
470
471 /* Do the OtW open, save the FID. */
472 err = smb_smb_ntcreate(ssp, &name_mb,
473 0, /* create flags */
474 ioc->ioc_req_acc,
475 ioc->ioc_efattr,
476 ioc->ioc_share_acc,
477 ioc->ioc_open_disp,
478 ioc->ioc_creat_opts,
479 NTCREATEX_IMPERSONATION_IMPERSONATION,
480 &scred,
481 &fid,
482 NULL,
483 NULL);
484 if (err != 0)
485 goto out;
486
487 sdp->sd_smbfid = fid;
488 sdp->sd_vcgenid = ssp->ss_vcgenid;
489
490 out:
491 kmem_free(ioc, sizeof (*ioc));
492 smb_credrele(&scred);
493 mb_done(&name_mb);
494
495 return (err);
496 }
497
498 /*
499 * Helper for nsmb_ioctl case
500 * SMBIOC_PRINTJOB
501 */
502 int
smb_usr_printjob(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)503 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
504 {
505 struct smb_cred scred;
506 struct smb_share *ssp;
507 smbioc_printjob_t *ioc = NULL;
508 uint16_t fid;
509 int err;
510
511 /* This ioctl requires a share. */
512 if ((ssp = sdp->sd_share) == NULL)
513 return (ENOTCONN);
514
515 /* The share must be a print queue. */
516 if (ssp->ss_type != STYPE_PRINTQ)
517 return (EINVAL);
518
519 /* Must not be already open. */
520 if (sdp->sd_smbfid != -1)
521 return (EINVAL);
522
523 smb_credinit(&scred, cr);
524 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
525 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
526 err = EFAULT;
527 goto out;
528 }
529 ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
530
531 /* Do the OtW open, save the FID. */
532 err = smb_smb_open_prjob(ssp, ioc->ioc_title,
533 ioc->ioc_setuplen, ioc->ioc_prmode,
534 &scred, &fid);
535 if (err != 0)
536 goto out;
537
538 sdp->sd_smbfid = fid;
539 sdp->sd_vcgenid = ssp->ss_vcgenid;
540
541 out:
542 kmem_free(ioc, sizeof (*ioc));
543 smb_credrele(&scred);
544
545 return (err);
546 }
547
548 /*
549 * Helper for nsmb_ioctl case
550 * SMBIOC_CLOSEFH
551 */
552 int
smb_usr_closefh(smb_dev_t * sdp,cred_t * cr)553 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
554 {
555 struct smb_cred scred;
556 struct smb_share *ssp;
557 uint16_t fid;
558 int err;
559
560 /* This ioctl requires a share. */
561 if ((ssp = sdp->sd_share) == NULL)
562 return (ENOTCONN);
563
564 if (sdp->sd_smbfid == -1)
565 return (0);
566 fid = (uint16_t)sdp->sd_smbfid;
567 sdp->sd_smbfid = -1;
568
569 smb_credinit(&scred, cr);
570 if (ssp->ss_type == STYPE_PRINTQ)
571 err = smb_smb_close_prjob(ssp, fid, &scred);
572 else
573 err = smb_smb_close(ssp, fid, NULL, &scred);
574 smb_credrele(&scred);
575
576 return (err);
577 }
578
579 /*
580 * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
581 * Find or create a session (a.k.a. "VC" in here)
582 */
583 int
smb_usr_get_ssn(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)584 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
585 {
586 struct smb_cred scred;
587 smbioc_ossn_t *ossn = NULL;
588 struct smb_vc *vcp = NULL;
589 int error = 0;
590 uid_t realuid;
591
592 /* Should be no VC */
593 if (sdp->sd_vc != NULL)
594 return (EISCONN);
595
596 smb_credinit(&scred, cr);
597 ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
598 if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
599 error = EFAULT;
600 goto out;
601 }
602
603 /*
604 * Only superuser can specify a UID or GID.
605 */
606 realuid = crgetruid(cr);
607 if (ossn->ssn_owner == SMBM_ANY_OWNER)
608 ossn->ssn_owner = realuid;
609 else {
610 /*
611 * Do we have the privilege to create with the
612 * specified uid? (does uid == cr->cr_uid, etc.)
613 */
614 if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
615 error = EPERM;
616 goto out;
617 }
618 /* ossn->ssn_owner is OK */
619 }
620
621 /*
622 * Make sure the strings are null terminated.
623 */
624 ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
625 ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
626 ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0';
627
628 if (cmd == SMBIOC_SSN_CREATE)
629 ossn->ssn_vopt |= SMBVOPT_CREATE;
630 else /* FIND */
631 ossn->ssn_vopt &= ~SMBVOPT_CREATE;
632
633 error = smb_vc_findcreate(ossn, &scred, &vcp);
634 if (error)
635 goto out;
636 ASSERT(vcp != NULL);
637
638 /*
639 * We have a VC, held, but not locked.
640 * If we're creating, mark this instance as
641 * an open from IOD so close can do cleanup.
642 *
643 * XXX: Would be nice to have a back pointer
644 * from the VC to this (IOD) sdp instance.
645 */
646 if (cmd == SMBIOC_SSN_CREATE) {
647 if (vcp->iod_thr != NULL) {
648 error = EEXIST;
649 goto out;
650 }
651 sdp->sd_flags |= NSMBFL_IOD;
652 } else {
653 /*
654 * Wait for it to finish connecting
655 * (or reconnect) if necessary.
656 */
657 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
658 error = smb_iod_reconnect(vcp);
659 if (error != 0)
660 goto out;
661 }
662 }
663
664 /*
665 * The VC has a hold from _findvc
666 * which we keep until _SSN_RELE
667 * or nsmb_close().
668 */
669 sdp->sd_level = SMBL_VC;
670 sdp->sd_vc = vcp;
671 vcp = NULL;
672 (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
673
674 out:
675 if (vcp) {
676 /* Error path: rele hold from _findcreate */
677 smb_vc_rele(vcp);
678 }
679 kmem_free(ossn, sizeof (*ossn));
680 smb_credrele(&scred);
681
682 return (error);
683 }
684
685 /*
686 * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
687 * Release or kill the current session.
688 */
689 int
smb_usr_drop_ssn(smb_dev_t * sdp,int cmd)690 smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
691 {
692 struct smb_vc *vcp = NULL;
693
694 /* Must have a VC. */
695 if ((vcp = sdp->sd_vc) == NULL)
696 return (ENOTCONN);
697
698 /* If we have a share ref, drop it too. */
699 if (sdp->sd_share) {
700 smb_share_rele(sdp->sd_share);
701 sdp->sd_share = NULL;
702 sdp->sd_level = SMBL_VC;
703 }
704
705 if (cmd == SMBIOC_SSN_KILL)
706 smb_vc_kill(vcp);
707
708 /* Drop the VC ref. */
709 smb_vc_rele(vcp);
710 sdp->sd_vc = NULL;
711 sdp->sd_level = 0;
712
713 return (0);
714 }
715
716 /*
717 * Find or create a tree (connected share)
718 */
719 int
smb_usr_get_tree(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)720 smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
721 {
722 struct smb_cred scred;
723 smbioc_tcon_t *tcon = NULL;
724 struct smb_vc *vcp = NULL;
725 struct smb_share *ssp = NULL;
726 int error = 0;
727
728 /* Must have a VC. */
729 if ((vcp = sdp->sd_vc) == NULL)
730 return (ENOTCONN);
731 /* Should not have a share. */
732 if (sdp->sd_share != NULL)
733 return (EISCONN);
734
735 smb_credinit(&scred, cr);
736 tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
737 if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
738 error = EFAULT;
739 goto out;
740 }
741
742 /*
743 * Make sure the strings are null terminated.
744 */
745 tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
746 tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
747
748 if (cmd == SMBIOC_TREE_CONNECT)
749 tcon->tc_opt |= SMBSOPT_CREATE;
750 else /* FIND */
751 tcon->tc_opt &= ~SMBSOPT_CREATE;
752
753 error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
754 if (error)
755 goto out;
756 ASSERT(ssp != NULL);
757
758 /*
759 * We have a share, held, but not locked.
760 * If we're creating, do tree connect now,
761 * otherwise let that wait for a request.
762 */
763 if (cmd == SMBIOC_TREE_CONNECT) {
764 error = smb_share_tcon(ssp, &scred);
765 if (error)
766 goto out;
767 }
768
769 /*
770 * Give caller the real share type from
771 * the tree connect response, so they can
772 * see if they got the requested type.
773 */
774 tcon->tc_sh.sh_type = ssp->ss_type;
775
776 /*
777 * The share has a hold from _tcon
778 * which we keep until nsmb_close()
779 * or the SMBIOC_TDIS below.
780 */
781 sdp->sd_level = SMBL_SHARE;
782 sdp->sd_share = ssp;
783 ssp = NULL;
784 (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
785
786 out:
787 if (ssp) {
788 /* Error path: rele hold from _findcreate */
789 smb_share_rele(ssp);
790 }
791 /*
792 * This structure may contain a
793 * cleartext password, so zap it.
794 */
795 bzero(tcon, sizeof (*tcon));
796 kmem_free(tcon, sizeof (*tcon));
797 smb_credrele(&scred);
798
799 return (error);
800 }
801
802 /*
803 * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
804 * Release or kill the current tree
805 */
806 int
smb_usr_drop_tree(smb_dev_t * sdp,int cmd)807 smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
808 {
809 struct smb_share *ssp = NULL;
810
811 /* Must have a VC and a share. */
812 if (sdp->sd_vc == NULL)
813 return (ENOTCONN);
814 if ((ssp = sdp->sd_share) == NULL)
815 return (ENOTCONN);
816
817 if (cmd == SMBIOC_TREE_KILL)
818 smb_share_kill(ssp);
819
820 /* Drop the share ref. */
821 smb_share_rele(sdp->sd_share);
822 sdp->sd_share = NULL;
823 sdp->sd_level = SMBL_VC;
824
825 return (0);
826 }
827
828
829 /*
830 * Ioctl function: SMBIOC_IOD_WORK
831 *
832 * Become the reader (IOD) thread, until either the connection is
833 * reset by the server, or until the connection is idle longer than
834 * some max time. (max idle time not yet implemented)
835 */
836 int
smb_usr_iod_work(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)837 smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
838 {
839 struct smb_vc *vcp = NULL;
840 int err = 0;
841
842 /* Must have a valid session. */
843 if ((vcp = sdp->sd_vc) == NULL)
844 return (EINVAL);
845 if (vcp->vc_flags & SMBV_GONE)
846 return (EINVAL);
847
848 /*
849 * Is there already an IOD for this VC?
850 * (Should never happen.)
851 */
852 SMB_VC_LOCK(vcp);
853 if (vcp->iod_thr == NULL)
854 vcp->iod_thr = curthread;
855 else
856 err = EEXIST;
857 SMB_VC_UNLOCK(vcp);
858 if (err)
859 return (err);
860
861 /*
862 * Copy the "work" state, etc. into the VC
863 * The MAC key is copied separately.
864 */
865 if (ddi_copyin((void *)arg, &vcp->vc_work,
866 sizeof (smbioc_ssn_work_t), flags)) {
867 err = EFAULT;
868 goto out;
869 }
870 if (vcp->vc_u_maclen) {
871 vcp->vc_mackeylen = vcp->vc_u_maclen;
872 vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
873 if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
874 vcp->vc_mackeylen, flags)) {
875 err = EFAULT;
876 goto out;
877 }
878 }
879
880 err = smb_iod_vc_work(vcp, cr);
881
882 /* Caller wants state here. */
883 vcp->vc_work.wk_out_state = vcp->vc_state;
884
885 (void) ddi_copyout(&vcp->vc_work, (void *)arg,
886 sizeof (smbioc_ssn_work_t), flags);
887
888 out:
889 if (vcp->vc_mackey) {
890 kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
891 vcp->vc_mackey = NULL;
892 vcp->vc_mackeylen = 0;
893 }
894
895 /*
896 * The IOD thread is leaving the driver. Clear iod_thr,
897 * and wake up anybody waiting for us to quit.
898 */
899 SMB_VC_LOCK(vcp);
900 vcp->iod_thr = NULL;
901 cv_broadcast(&vcp->vc_statechg);
902 SMB_VC_UNLOCK(vcp);
903
904 return (err);
905 }
906
907 /*
908 * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
909 *
910 * Wait for user-level requests to be enqueued on this session,
911 * and then return to the user-space helper, which will then
912 * initiate a reconnect, etc.
913 */
914 int
smb_usr_iod_ioctl(smb_dev_t * sdp,int cmd,intptr_t arg,int flags)915 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
916 {
917 struct smb_vc *vcp = NULL;
918 int err = 0;
919
920 /* Must have a valid session. */
921 if ((vcp = sdp->sd_vc) == NULL)
922 return (EINVAL);
923 if (vcp->vc_flags & SMBV_GONE)
924 return (EINVAL);
925
926 /*
927 * Is there already an IOD for this VC?
928 * (Should never happen.)
929 */
930 SMB_VC_LOCK(vcp);
931 if (vcp->iod_thr == NULL)
932 vcp->iod_thr = curthread;
933 else
934 err = EEXIST;
935 SMB_VC_UNLOCK(vcp);
936 if (err)
937 return (err);
938
939 /* nothing to copyin */
940
941 switch (cmd) {
942 case SMBIOC_IOD_IDLE:
943 err = smb_iod_vc_idle(vcp);
944 break;
945
946 case SMBIOC_IOD_RCFAIL:
947 err = smb_iod_vc_rcfail(vcp);
948 break;
949
950 default:
951 err = ENOTTY;
952 goto out;
953 }
954
955 /* Both of these ioctls copy out the new state. */
956 (void) ddi_copyout(&vcp->vc_state, (void *)arg,
957 sizeof (int), flags);
958
959 out:
960 /*
961 * The IOD thread is leaving the driver. Clear iod_thr,
962 * and wake up anybody waiting for us to quit.
963 */
964 SMB_VC_LOCK(vcp);
965 vcp->iod_thr = NULL;
966 cv_broadcast(&vcp->vc_statechg);
967 SMB_VC_UNLOCK(vcp);
968
969 return (err);
970 }
971