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 2009 Sun Microsystems, Inc. All rights reserved.
37 * Use is subject to license terms.
38 *
39 * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
40 */
41
42 #include <sys/param.h>
43 #include <sys/kmem.h>
44 #include <sys/systm.h>
45 #include <sys/policy.h>
46 #include <sys/conf.h>
47 #include <sys/proc.h>
48 #include <sys/fcntl.h>
49 #include <sys/file.h>
50 #include <sys/socket.h>
51 #include <sys/sunddi.h>
52 #include <sys/cmn_err.h>
53
54 #include <netsmb/smb_osdep.h>
55
56 #include <smb/winioctl.h>
57 #include <netsmb/smb.h>
58 #include <netsmb/smb_conn.h>
59 #include <netsmb/smb_rq.h>
60 #include <netsmb/smb_subr.h>
61 #include <netsmb/smb_dev.h>
62
63 static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
64
65 /*
66 * Ioctl function for SMBIOC_GETSSNKEY
67 * Size copied out is SMBIOC_HASH_SZ.
68 *
69 * The RPC library needs this for encrypting things
70 * like "set password" requests. This is called
71 * with an active RPC binding, so the connection
72 * will already be active (but this checks).
73 */
74 int
smb_usr_get_ssnkey(smb_dev_t * sdp,intptr_t arg,int flags)75 smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
76 {
77 struct smb_vc *vcp = NULL;
78
79 /* This ioctl requires an active session. */
80 if ((vcp = sdp->sd_vc) == NULL)
81 return (ENOTCONN);
82 if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
83 return (ENOTCONN);
84
85 /*
86 * Return the session key.
87 */
88 if (vcp->vc_ssnkey == NULL ||
89 vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
90 return (EINVAL);
91 if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
92 SMBIOC_HASH_SZ, flags))
93 return (EFAULT);
94
95 return (0);
96 }
97
98 /*
99 * Ioctl function for SMBIOC_XACTNP (transact named pipe)
100 */
101 int
smb_usr_xnp(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)102 smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
103 {
104 struct smb_cred scred;
105 struct smb_share *ssp;
106 struct smb_fh *fhp;
107 smbioc_xnp_t *ioc = NULL;
108 struct mbchain send_mb;
109 struct mdchain recv_md;
110 uint32_t rdlen;
111 int err, mbseg;
112
113 /* This ioctl requires a file handle. */
114 if ((fhp = sdp->sd_fh) == NULL)
115 return (EINVAL);
116 ssp = FHTOSS(fhp);
117
118 /* After reconnect, force close+reopen */
119 if (fhp->fh_vcgenid != ssp->ss_vcgenid)
120 return (ESTALE);
121
122 bzero(&send_mb, sizeof (send_mb));
123 bzero(&recv_md, sizeof (recv_md));
124
125 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
126 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
127 err = EFAULT;
128 goto out;
129 }
130
131 /*
132 * Copyin the send data, into an mbchain,
133 * save output buffer size.
134 */
135 mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
136 err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
137 if (err)
138 goto out;
139 rdlen = ioc->ioc_rdlen;
140
141 /*
142 * Run the SMB2 ioctl or SMB1 trans2
143 */
144 smb_credinit(&scred, cr);
145 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
146 err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
147 &send_mb, &recv_md, &rdlen,
148 FSCTL_PIPE_TRANSCEIVE, &scred);
149 } else {
150 err = smb_t2_xnp(ssp, fhp->fh_fid1,
151 &send_mb, &recv_md, &rdlen,
152 &ioc->ioc_more, &scred);
153 }
154 smb_credrele(&scred);
155
156 /* Copyout returned data. */
157 if (err == 0 && recv_md.md_top != NULL) {
158 /* User's buffer large enough for copyout? */
159 size_t len = m_fixhdr(recv_md.md_top);
160 if (len > ioc->ioc_rdlen) {
161 err = EMSGSIZE;
162 goto out;
163 }
164 err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
165 if (err)
166 goto out;
167 } else
168 ioc->ioc_rdlen = 0;
169
170 /* Tell caller received length */
171 if (rdlen <= ioc->ioc_rdlen) {
172 /* Normal case */
173 ioc->ioc_rdlen = rdlen;
174 } else {
175 /* Buffer overlow. Leave ioc_rdlen */
176 ioc->ioc_more = 1;
177 }
178
179 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
180
181 out:
182 kmem_free(ioc, sizeof (*ioc));
183 md_done(&recv_md);
184 mb_done(&send_mb);
185
186 return (err);
187 }
188
189 /* helper for _t2request */
190 static int
smb_cpdatain(struct mbchain * mbp,int len,char * data,int mbseg)191 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
192 {
193 int error;
194
195 if (len == 0)
196 return (0);
197 error = mb_init(mbp);
198 if (error)
199 return (error);
200 return (mb_put_mem(mbp, data, len, mbseg));
201 }
202
203 /*
204 * Helper for nsmb_ioctl cases
205 * SMBIOC_READ, SMBIOC_WRITE
206 */
207 int
smb_usr_rw(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)208 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
209 {
210 struct smb_cred scred;
211 struct smb_share *ssp;
212 struct smb_fh *fhp;
213 smbioc_rw_t *ioc = NULL;
214 struct iovec aiov[1];
215 struct uio auio;
216 int err;
217 uio_rw_t rw;
218
219 /* This ioctl requires a file handle. */
220 if ((fhp = sdp->sd_fh) == NULL)
221 return (EINVAL);
222 ssp = FHTOSS(fhp);
223
224 /* After reconnect, force close+reopen */
225 if (fhp->fh_vcgenid != ssp->ss_vcgenid)
226 return (ESTALE);
227
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 switch (cmd) {
235 case SMBIOC_READ:
236 rw = UIO_READ;
237 break;
238 case SMBIOC_WRITE:
239 rw = UIO_WRITE;
240 break;
241 default:
242 err = ENODEV;
243 goto out;
244 }
245
246 aiov[0].iov_base = ioc->ioc_base;
247 aiov[0].iov_len = (size_t)ioc->ioc_cnt;
248
249 auio.uio_iov = aiov;
250 auio.uio_iovcnt = 1;
251 auio.uio_loffset = ioc->ioc_offset;
252 auio.uio_segflg = (flags & FKIOCTL) ?
253 UIO_SYSSPACE : UIO_USERSPACE;
254 auio.uio_fmode = 0;
255 auio.uio_resid = (size_t)ioc->ioc_cnt;
256
257 smb_credinit(&scred, cr);
258 err = smb_rwuio(fhp, rw, &auio, &scred, 0);
259 smb_credrele(&scred);
260
261 /*
262 * On return ioc_cnt holds the
263 * number of bytes transferred.
264 */
265 ioc->ioc_cnt -= auio.uio_resid;
266
267 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
268
269 out:
270 kmem_free(ioc, sizeof (*ioc));
271
272 return (err);
273 }
274
275 /*
276 * Helper for nsmb_ioctl case
277 * SMBIOC_NTCREATE
278 */
279 int
smb_usr_ntcreate(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)280 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
281 {
282 struct smb_cred scred;
283 struct mbchain name_mb;
284 struct smb_share *ssp;
285 struct smb_fh *fhp = NULL;
286 smbioc_ntcreate_t *ioc = NULL;
287 int err, nmlen;
288
289 mb_init(&name_mb);
290
291 /* This ioctl requires a share. */
292 if ((ssp = sdp->sd_share) == NULL)
293 return (ENOTCONN);
294
295 /* Must not already have a file handle. */
296 if (sdp->sd_fh != NULL)
297 return (EINVAL);
298
299 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
300 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
301 err = EFAULT;
302 goto out;
303 }
304
305 /* Build name_mb */
306 ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
307 nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
308 err = smb_put_dmem(&name_mb, SSTOVC(ssp),
309 ioc->ioc_name, nmlen,
310 SMB_CS_NONE, NULL);
311 if (err != 0)
312 goto out;
313
314 err = smb_fh_create(ssp, &fhp);
315 if (err != 0)
316 goto out;
317
318 /*
319 * Do the OtW open, save the FID.
320 */
321 smb_credinit(&scred, cr);
322 err = smb_smb_ntcreate(ssp, &name_mb,
323 0, /* create flags */
324 ioc->ioc_req_acc,
325 ioc->ioc_efattr,
326 ioc->ioc_share_acc,
327 ioc->ioc_open_disp,
328 ioc->ioc_creat_opts,
329 NTCREATEX_IMPERSONATION_IMPERSONATION,
330 &scred,
331 fhp,
332 NULL,
333 NULL);
334 smb_credrele(&scred);
335 if (err != 0)
336 goto out;
337
338 fhp->fh_rights = ioc->ioc_req_acc;
339 smb_fh_opened(fhp);
340 sdp->sd_fh = fhp;
341 fhp = NULL;
342
343 out:
344 if (fhp != NULL)
345 smb_fh_rele(fhp);
346 kmem_free(ioc, sizeof (*ioc));
347 mb_done(&name_mb);
348
349 return (err);
350 }
351
352 /*
353 * Helper for nsmb_ioctl case
354 * SMBIOC_PRINTJOB
355 */
356 int
smb_usr_printjob(smb_dev_t * sdp,intptr_t arg,int flags,cred_t * cr)357 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
358 {
359 static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
360 struct smb_cred scred;
361 struct mbchain name_mb;
362 struct smb_share *ssp;
363 struct smb_fh *fhp = NULL;
364 smbioc_printjob_t *ioc = NULL;
365 int err, cklen, nmlen;
366 uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
367 SA_RIGHT_FILE_READ_ATTRIBUTES;
368
369 mb_init(&name_mb);
370
371 /* This ioctl requires a share. */
372 if ((ssp = sdp->sd_share) == NULL)
373 return (ENOTCONN);
374
375 /* The share must be a print queue. */
376 if (ssp->ss_type != STYPE_PRINTQ)
377 return (EINVAL);
378
379 /* Must not already have a file handle. */
380 if (sdp->sd_fh != NULL)
381 return (EINVAL);
382
383 smb_credinit(&scred, cr);
384 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
385 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
386 err = EFAULT;
387 goto out;
388 }
389
390 /*
391 * Use the print job title as the file name to open, but
392 * check for invalid characters first. See the notes in
393 * libsmbfs/smb/print.c about job name sanitizing.
394 */
395 ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
396 nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
397 cklen = strcspn(ioc->ioc_title, invalid_chars);
398 if (cklen < nmlen) {
399 err = EINVAL;
400 goto out;
401 }
402
403 /* Build name_mb */
404 err = smb_put_dmem(&name_mb, SSTOVC(ssp),
405 ioc->ioc_title, nmlen,
406 SMB_CS_NONE, NULL);
407 if (err != 0)
408 goto out;
409
410 err = smb_fh_create(ssp, &fhp);
411 if (err != 0)
412 goto out;
413
414 /*
415 * Do the OtW open, save the FID.
416 */
417 smb_credinit(&scred, cr);
418 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
419 err = smb2_smb_ntcreate(ssp, &name_mb,
420 NULL, NULL, /* cctx in, out */
421 0, /* create flags */
422 access,
423 SMB_EFA_NORMAL,
424 NTCREATEX_SHARE_ACCESS_NONE,
425 NTCREATEX_DISP_CREATE,
426 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
427 NTCREATEX_IMPERSONATION_IMPERSONATION,
428 &scred,
429 &fhp->fh_fid2,
430 NULL,
431 NULL);
432 } else {
433 err = smb_smb_open_prjob(ssp, ioc->ioc_title,
434 ioc->ioc_setuplen, ioc->ioc_prmode,
435 &scred, &fhp->fh_fid1);
436 }
437 smb_credrele(&scred);
438 if (err != 0)
439 goto out;
440
441 fhp->fh_rights = access;
442 smb_fh_opened(fhp);
443 sdp->sd_fh = fhp;
444 fhp = NULL;
445
446 out:
447 if (fhp != NULL)
448 smb_fh_rele(fhp);
449 kmem_free(ioc, sizeof (*ioc));
450 mb_done(&name_mb);
451
452 return (err);
453 }
454
455 /*
456 * Helper for nsmb_ioctl case
457 * SMBIOC_CLOSEFH
458 */
459 /*ARGSUSED*/
460 int
smb_usr_closefh(smb_dev_t * sdp,cred_t * cr)461 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
462 {
463 struct smb_fh *fhp;
464
465 /* This ioctl requires a file handle. */
466 if ((fhp = sdp->sd_fh) == NULL)
467 return (EINVAL);
468 sdp->sd_fh = NULL;
469
470 smb_fh_close(fhp);
471 smb_fh_rele(fhp);
472
473 return (0);
474 }
475
476 /*
477 * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
478 * Find or create a session (a.k.a. "VC" in here)
479 */
480 int
smb_usr_get_ssn(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)481 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
482 {
483 struct smb_cred scred;
484 smbioc_ossn_t *ossn = NULL;
485 struct smb_vc *vcp = NULL;
486 int error = 0;
487 uid_t realuid;
488
489 /* Should be no VC */
490 if (sdp->sd_vc != NULL)
491 return (EISCONN);
492
493 smb_credinit(&scred, cr);
494 ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
495 if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
496 error = EFAULT;
497 goto out;
498 }
499
500 /*
501 * Only superuser can specify a UID or GID.
502 */
503 realuid = crgetruid(cr);
504 if (ossn->ssn_owner == SMBM_ANY_OWNER)
505 ossn->ssn_owner = realuid;
506 else {
507 /*
508 * Do we have the privilege to create with the
509 * specified uid? (does uid == cr->cr_uid, etc.)
510 */
511 if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
512 error = EPERM;
513 goto out;
514 }
515 /* ossn->ssn_owner is OK */
516 }
517
518 /*
519 * Make sure the strings are null terminated.
520 */
521 ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
522 ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
523 ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0';
524
525 if (cmd == SMBIOC_SSN_CREATE)
526 ossn->ssn_vopt |= SMBVOPT_CREATE;
527 else /* FIND */
528 ossn->ssn_vopt &= ~SMBVOPT_CREATE;
529
530 error = smb_vc_findcreate(ossn, &scred, &vcp);
531 if (error)
532 goto out;
533 ASSERT(vcp != NULL);
534
535 /*
536 * We have a VC, held, but not locked.
537 * If we're creating, mark this instance as
538 * an open from IOD so close can do cleanup.
539 *
540 * XXX: Would be nice to have a back pointer
541 * from the VC to this (IOD) sdp instance.
542 */
543 if (cmd == SMBIOC_SSN_CREATE) {
544 if (vcp->iod_thr != NULL) {
545 error = EEXIST;
546 goto out;
547 }
548 sdp->sd_flags |= NSMBFL_IOD;
549 } else {
550 /*
551 * Wait for it to finish connecting
552 * (or reconnect) if necessary.
553 */
554 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
555 error = smb_iod_reconnect(vcp);
556 if (error != 0)
557 goto out;
558 }
559 }
560
561 /*
562 * The VC has a hold from _findvc
563 * which we keep until _SSN_RELE
564 * or nsmb_close().
565 */
566 sdp->sd_level = SMBL_VC;
567 sdp->sd_vc = vcp;
568 vcp = NULL;
569 (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
570
571 out:
572 if (vcp) {
573 /* Error path: rele hold from _findcreate */
574 smb_vc_rele(vcp);
575 }
576 kmem_free(ossn, sizeof (*ossn));
577 smb_credrele(&scred);
578
579 return (error);
580 }
581
582 /*
583 * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
584 * Release or kill the current session.
585 */
586 int
smb_usr_drop_ssn(smb_dev_t * sdp,int cmd)587 smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
588 {
589 struct smb_vc *vcp = NULL;
590
591 /* Must have a VC. */
592 if ((vcp = sdp->sd_vc) == NULL)
593 return (ENOTCONN);
594
595 /* If we have a share ref, drop it too. */
596 if (sdp->sd_share) {
597 smb_share_rele(sdp->sd_share);
598 sdp->sd_share = NULL;
599 sdp->sd_level = SMBL_VC;
600 }
601
602 if (cmd == SMBIOC_SSN_KILL)
603 smb_vc_kill(vcp);
604
605 /* Drop the VC ref. */
606 smb_vc_rele(vcp);
607 sdp->sd_vc = NULL;
608 sdp->sd_level = 0;
609
610 return (0);
611 }
612
613 /*
614 * Find or create a tree (connected share)
615 */
616 int
smb_usr_get_tree(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)617 smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
618 {
619 struct smb_cred scred;
620 smbioc_tcon_t *tcon = NULL;
621 struct smb_vc *vcp = NULL;
622 struct smb_share *ssp = NULL;
623 int error = 0;
624
625 /* Must have a VC. */
626 if ((vcp = sdp->sd_vc) == NULL)
627 return (ENOTCONN);
628 /* Should not have a share. */
629 if (sdp->sd_share != NULL)
630 return (EISCONN);
631
632 smb_credinit(&scred, cr);
633 tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
634 if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
635 error = EFAULT;
636 goto out;
637 }
638
639 /*
640 * Make sure the strings are null terminated.
641 */
642 tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
643 tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
644
645 if (cmd == SMBIOC_TREE_CONNECT)
646 tcon->tc_opt |= SMBSOPT_CREATE;
647 else /* FIND */
648 tcon->tc_opt &= ~SMBSOPT_CREATE;
649
650 error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
651 if (error)
652 goto out;
653 ASSERT(ssp != NULL);
654
655 /*
656 * We have a share, held, but not locked.
657 * If we're creating, do tree connect now,
658 * otherwise let that wait for a request.
659 */
660 if (cmd == SMBIOC_TREE_CONNECT) {
661 error = smb_share_tcon(ssp, &scred);
662 if (error)
663 goto out;
664 }
665
666 /*
667 * Give caller the real share type from
668 * the tree connect response, so they can
669 * see if they got the requested type.
670 */
671 tcon->tc_sh.sh_type = ssp->ss_type;
672
673 /*
674 * The share has a hold from _tcon
675 * which we keep until nsmb_close()
676 * or the SMBIOC_TDIS below.
677 */
678 sdp->sd_level = SMBL_SHARE;
679 sdp->sd_share = ssp;
680 ssp = NULL;
681 (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
682
683 out:
684 if (ssp) {
685 /* Error path: rele hold from _findcreate */
686 smb_share_rele(ssp);
687 }
688 /*
689 * This structure may contain a
690 * cleartext password, so zap it.
691 */
692 bzero(tcon, sizeof (*tcon));
693 kmem_free(tcon, sizeof (*tcon));
694 smb_credrele(&scred);
695
696 return (error);
697 }
698
699 /*
700 * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
701 * Release or kill the current tree
702 */
703 int
smb_usr_drop_tree(smb_dev_t * sdp,int cmd)704 smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
705 {
706 struct smb_share *ssp = NULL;
707
708 /* Must have a VC and a share. */
709 if (sdp->sd_vc == NULL)
710 return (ENOTCONN);
711 if ((ssp = sdp->sd_share) == NULL)
712 return (ENOTCONN);
713
714 if (cmd == SMBIOC_TREE_KILL)
715 smb_share_kill(ssp);
716
717 /* Drop the share ref. */
718 smb_share_rele(sdp->sd_share);
719 sdp->sd_share = NULL;
720 sdp->sd_level = SMBL_VC;
721
722 return (0);
723 }
724
725 /*
726 * Ioctl handler for all SMBIOC_IOD_...
727 */
728 int
smb_usr_iod_ioctl(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)729 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
730 {
731 struct smb_vc *vcp;
732 int err = 0;
733
734 /* Must be the IOD. */
735 if ((sdp->sd_flags & NSMBFL_IOD) == 0)
736 return (EINVAL);
737 /* Must have a VC and no share. */
738 if ((vcp = sdp->sd_vc) == NULL)
739 return (EINVAL);
740 if (sdp->sd_share != NULL)
741 return (EINVAL);
742
743 /*
744 * Is there already an IOD for this VC?
745 * (Should never happen.)
746 */
747 SMB_VC_LOCK(vcp);
748 if (vcp->iod_thr == NULL)
749 vcp->iod_thr = curthread;
750 else
751 err = EEXIST;
752 SMB_VC_UNLOCK(vcp);
753 if (err)
754 return (err);
755
756 /*
757 * Copy the "work" state, etc. into the VC,
758 * and back to the caller on the way out.
759 * Clear the "out only" part.
760 */
761 if (ddi_copyin((void *)arg, &vcp->vc_work,
762 sizeof (smbioc_ssn_work_t), flags)) {
763 err = EFAULT;
764 goto out;
765 }
766 vcp->vc_work.wk_out_state = 0;
767
768 switch (cmd) {
769
770 case SMBIOC_IOD_CONNECT:
771 err = nsmb_iod_connect(vcp, cr);
772 break;
773
774 case SMBIOC_IOD_NEGOTIATE:
775 err = nsmb_iod_negotiate(vcp, cr);
776 break;
777
778 case SMBIOC_IOD_SSNSETUP:
779 err = nsmb_iod_ssnsetup(vcp, cr);
780 break;
781
782 case SMBIOC_IOD_WORK:
783 err = smb_iod_vc_work(vcp, flags, cr);
784 break;
785
786 case SMBIOC_IOD_IDLE:
787 err = smb_iod_vc_idle(vcp);
788 break;
789
790 case SMBIOC_IOD_RCFAIL:
791 err = smb_iod_vc_rcfail(vcp);
792 break;
793
794 default:
795 err = ENOTTY;
796 break;
797 }
798
799 out:
800 vcp->vc_work.wk_out_state = vcp->vc_state;
801 (void) ddi_copyout(&vcp->vc_work, (void *)arg,
802 sizeof (smbioc_ssn_work_t), flags);
803
804 /*
805 * The IOD thread is leaving the driver. Clear iod_thr,
806 * and wake up anybody waiting for us to quit.
807 */
808 SMB_VC_LOCK(vcp);
809 vcp->iod_thr = NULL;
810 cv_broadcast(&vcp->vc_statechg);
811 SMB_VC_UNLOCK(vcp);
812
813 return (err);
814 }
815
816 int
smb_usr_ioctl(smb_dev_t * sdp,int cmd,intptr_t arg,int flags,cred_t * cr)817 smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
818 {
819 int err;
820
821 /*
822 * Serialize ioctl calls. The smb_usr_... functions
823 * don't expect concurrent calls on a given sdp.
824 */
825 mutex_enter(&sdp->sd_lock);
826 if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
827 mutex_exit(&sdp->sd_lock);
828 return (EBUSY);
829 }
830 sdp->sd_flags |= NSMBFL_IOCTL;
831 mutex_exit(&sdp->sd_lock);
832
833 err = 0;
834 switch (cmd) {
835 case SMBIOC_GETVERS:
836 (void) ddi_copyout(&nsmb_version, (void *)arg,
837 sizeof (nsmb_version), flags);
838 break;
839
840 case SMBIOC_GETSSNKEY:
841 err = smb_usr_get_ssnkey(sdp, arg, flags);
842 break;
843
844 case SMBIOC_DUP_DEV:
845 err = smb_usr_dup_dev(sdp, arg, flags);
846 break;
847
848 case SMBIOC_XACTNP:
849 err = smb_usr_xnp(sdp, arg, flags, cr);
850 break;
851
852 case SMBIOC_READ:
853 case SMBIOC_WRITE:
854 err = smb_usr_rw(sdp, cmd, arg, flags, cr);
855 break;
856
857 case SMBIOC_NTCREATE:
858 err = smb_usr_ntcreate(sdp, arg, flags, cr);
859 break;
860
861 case SMBIOC_PRINTJOB:
862 err = smb_usr_printjob(sdp, arg, flags, cr);
863 break;
864
865 case SMBIOC_CLOSEFH:
866 err = smb_usr_closefh(sdp, cr);
867 break;
868
869 case SMBIOC_SSN_CREATE:
870 case SMBIOC_SSN_FIND:
871 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
872 break;
873
874 case SMBIOC_SSN_KILL:
875 case SMBIOC_SSN_RELE:
876 err = smb_usr_drop_ssn(sdp, cmd);
877 break;
878
879 case SMBIOC_TREE_CONNECT:
880 case SMBIOC_TREE_FIND:
881 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
882 break;
883
884 case SMBIOC_TREE_KILL:
885 case SMBIOC_TREE_RELE:
886 err = smb_usr_drop_tree(sdp, cmd);
887 break;
888
889 case SMBIOC_IOD_CONNECT:
890 case SMBIOC_IOD_NEGOTIATE:
891 case SMBIOC_IOD_SSNSETUP:
892 case SMBIOC_IOD_WORK:
893 case SMBIOC_IOD_IDLE:
894 case SMBIOC_IOD_RCFAIL:
895 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
896 break;
897
898 case SMBIOC_PK_ADD:
899 case SMBIOC_PK_DEL:
900 case SMBIOC_PK_CHK:
901 case SMBIOC_PK_DEL_OWNER:
902 case SMBIOC_PK_DEL_EVERYONE:
903 err = smb_pkey_ioctl(cmd, arg, flags, cr);
904 break;
905
906 default:
907 err = ENOTTY;
908 break;
909 }
910
911 mutex_enter(&sdp->sd_lock);
912 sdp->sd_flags &= ~NSMBFL_IOCTL;
913 mutex_exit(&sdp->sd_lock);
914
915 return (err);
916 }
917