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
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
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
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
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
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
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
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
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
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
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);
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
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
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 }
|
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 2018 Nexenta Systems, 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
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
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
184 return (err);
185 }
186
187 /* helper for _t2request */
188 static int
189 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
190 {
191 int error;
192
193 if (len == 0)
194 return (0);
195 error = mb_init(mbp);
196 if (error)
197 return (error);
198 return (mb_put_mem(mbp, data, len, mbseg));
199 }
200
201 /*
202 * Helper for nsmb_ioctl cases
203 * SMBIOC_READ, SMBIOC_WRITE
204 */
205 int
206 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
207 {
208 struct smb_cred scred;
209 struct smb_share *ssp;
210 struct smb_fh *fhp;
211 smbioc_rw_t *ioc = NULL;
212 struct iovec aiov[1];
213 struct uio auio;
214 int err;
215 uio_rw_t rw;
216
217 /* This ioctl requires a file handle. */
218 if ((fhp = sdp->sd_fh) == NULL)
219 return (EINVAL);
220 ssp = FHTOSS(fhp);
221
222 /* After reconnect, force close+reopen */
223 if (fhp->fh_vcgenid != ssp->ss_vcgenid)
224 return (ESTALE);
225
226 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
227 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
228 err = EFAULT;
229 goto out;
230 }
231
232 switch (cmd) {
233 case SMBIOC_READ:
234 rw = UIO_READ;
235 break;
236 case SMBIOC_WRITE:
237 rw = UIO_WRITE;
238 break;
239 default:
240 err = ENODEV;
241 goto out;
242 }
243
244 aiov[0].iov_base = ioc->ioc_base;
245 aiov[0].iov_len = (size_t)ioc->ioc_cnt;
246
247 auio.uio_iov = aiov;
248 auio.uio_iovcnt = 1;
249 auio.uio_loffset = ioc->ioc_offset;
250 auio.uio_segflg = (flags & FKIOCTL) ?
251 UIO_SYSSPACE : UIO_USERSPACE;
252 auio.uio_fmode = 0;
253 auio.uio_resid = (size_t)ioc->ioc_cnt;
254
255 smb_credinit(&scred, cr);
256 err = smb_rwuio(fhp, rw, &auio, &scred, 0);
257 smb_credrele(&scred);
258
259 /*
260 * On return ioc_cnt holds the
261 * number of bytes transferred.
262 */
263 ioc->ioc_cnt -= auio.uio_resid;
264
265 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
266
267 out:
268 kmem_free(ioc, sizeof (*ioc));
269
270 return (err);
271 }
272
273 /*
274 * Helper for nsmb_ioctl case
275 * SMBIOC_NTCREATE
276 */
277 int
278 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
279 {
280 struct smb_cred scred;
281 struct mbchain name_mb;
282 struct smb_share *ssp;
283 struct smb_fh *fhp = NULL;
284 smbioc_ntcreate_t *ioc = NULL;
285 int err, nmlen;
286
287 mb_init(&name_mb);
288
289 /* This ioctl requires a share. */
290 if ((ssp = sdp->sd_share) == NULL)
291 return (ENOTCONN);
292
293 /* Must not already have a file handle. */
294 if (sdp->sd_fh != NULL)
295 return (EINVAL);
296
297 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
298 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
299 err = EFAULT;
300 goto out;
301 }
302
303 /* Build name_mb */
304 ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
305 nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
306 err = smb_put_dmem(&name_mb, SSTOVC(ssp),
307 ioc->ioc_name, nmlen,
308 SMB_CS_NONE, NULL);
309 if (err != 0)
310 goto out;
311
312 err = smb_fh_create(ssp, &fhp);
313 if (err != 0)
314 goto out;
315
316 /*
317 * Do the OtW open, save the FID.
318 */
319 smb_credinit(&scred, cr);
320 err = smb_smb_ntcreate(ssp, &name_mb,
321 0, /* create flags */
322 ioc->ioc_req_acc,
323 ioc->ioc_efattr,
324 ioc->ioc_share_acc,
325 ioc->ioc_open_disp,
326 ioc->ioc_creat_opts,
327 NTCREATEX_IMPERSONATION_IMPERSONATION,
328 &scred,
329 fhp,
330 NULL,
331 NULL);
332 smb_credrele(&scred);
333 if (err != 0)
334 goto out;
335
336 fhp->fh_rights = ioc->ioc_req_acc;
337 smb_fh_opened(fhp);
338 sdp->sd_fh = fhp;
339 fhp = NULL;
340
341 out:
342 if (fhp != NULL)
343 smb_fh_rele(fhp);
344 kmem_free(ioc, sizeof (*ioc));
345 mb_done(&name_mb);
346
347 return (err);
348 }
349
350 /*
351 * Helper for nsmb_ioctl case
352 * SMBIOC_PRINTJOB
353 */
354 int
355 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
356 {
357 static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
358 struct smb_cred scred;
359 struct mbchain name_mb;
360 struct smb_share *ssp;
361 struct smb_fh *fhp = NULL;
362 smbioc_printjob_t *ioc = NULL;
363 int err, cklen, nmlen;
364 uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
365 SA_RIGHT_FILE_READ_ATTRIBUTES;
366
367 mb_init(&name_mb);
368
369 /* This ioctl requires a share. */
370 if ((ssp = sdp->sd_share) == NULL)
371 return (ENOTCONN);
372
373 /* The share must be a print queue. */
374 if (ssp->ss_type != STYPE_PRINTQ)
375 return (EINVAL);
376
377 /* Must not already have a file handle. */
378 if (sdp->sd_fh != NULL)
379 return (EINVAL);
380
381 smb_credinit(&scred, cr);
382 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
383 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
384 err = EFAULT;
385 goto out;
386 }
387
388 /*
389 * Use the print job title as the file name to open, but
390 * check for invalid characters first. See the notes in
391 * libsmbfs/smb/print.c about job name sanitizing.
392 */
393 ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
394 nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
395 cklen = strcspn(ioc->ioc_title, invalid_chars);
396 if (cklen < nmlen) {
397 err = EINVAL;
398 goto out;
399 }
400
401 /* Build name_mb */
402 err = smb_put_dmem(&name_mb, SSTOVC(ssp),
403 ioc->ioc_title, nmlen,
404 SMB_CS_NONE, NULL);
405 if (err != 0)
406 goto out;
407
408 err = smb_fh_create(ssp, &fhp);
409 if (err != 0)
410 goto out;
411
412 /*
413 * Do the OtW open, save the FID.
414 */
415 smb_credinit(&scred, cr);
416 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
417 err = smb2_smb_ntcreate(ssp, &name_mb,
418 NULL, NULL, /* cctx in, out */
419 0, /* create flags */
420 access,
421 SMB_EFA_NORMAL,
422 NTCREATEX_SHARE_ACCESS_NONE,
423 NTCREATEX_DISP_CREATE,
424 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
425 NTCREATEX_IMPERSONATION_IMPERSONATION,
426 &scred,
427 &fhp->fh_fid2,
428 NULL,
429 NULL);
430 } else {
431 err = smb_smb_open_prjob(ssp, ioc->ioc_title,
432 ioc->ioc_setuplen, ioc->ioc_prmode,
433 &scred, &fhp->fh_fid1);
434 }
435 smb_credrele(&scred);
436 if (err != 0)
437 goto out;
438
439 fhp->fh_rights = access;
440 smb_fh_opened(fhp);
441 sdp->sd_fh = fhp;
442 fhp = NULL;
443
444 out:
445 if (fhp != NULL)
446 smb_fh_rele(fhp);
447 kmem_free(ioc, sizeof (*ioc));
448 mb_done(&name_mb);
449
450 return (err);
451 }
452
453 /*
454 * Helper for nsmb_ioctl case
455 * SMBIOC_CLOSEFH
456 */
457 /*ARGSUSED*/
458 int
459 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
460 {
461 struct smb_fh *fhp;
462
463 /* This ioctl requires a file handle. */
464 if ((fhp = sdp->sd_fh) == NULL)
465 return (EINVAL);
466 sdp->sd_fh = NULL;
467
468 smb_fh_close(fhp);
469 smb_fh_rele(fhp);
470
471 return (0);
472 }
473
474 /*
475 * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
476 * Find or create a session (a.k.a. "VC" in here)
477 */
478 int
479 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
480 {
481 struct smb_cred scred;
482 smbioc_ossn_t *ossn = NULL;
483 struct smb_vc *vcp = NULL;
484 int error = 0;
485 uid_t realuid;
486
487 /* Should be no VC */
488 if (sdp->sd_vc != NULL)
489 return (EISCONN);
490
491 smb_credinit(&scred, cr);
703 {
704 struct smb_share *ssp = NULL;
705
706 /* Must have a VC and a share. */
707 if (sdp->sd_vc == NULL)
708 return (ENOTCONN);
709 if ((ssp = sdp->sd_share) == NULL)
710 return (ENOTCONN);
711
712 if (cmd == SMBIOC_TREE_KILL)
713 smb_share_kill(ssp);
714
715 /* Drop the share ref. */
716 smb_share_rele(sdp->sd_share);
717 sdp->sd_share = NULL;
718 sdp->sd_level = SMBL_VC;
719
720 return (0);
721 }
722
723 /*
724 * Ioctl handler for all SMBIOC_IOD_...
725 */
726 int
727 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
728 {
729 struct smb_vc *vcp;
730 int err = 0;
731
732 /* Must be the IOD. */
733 if ((sdp->sd_flags & NSMBFL_IOD) == 0)
734 return (EINVAL);
735 /* Must have a VC and no share. */
736 if ((vcp = sdp->sd_vc) == NULL)
737 return (EINVAL);
738 if (sdp->sd_share != NULL)
739 return (EINVAL);
740
741 /*
742 * Is there already an IOD for this VC?
743 * (Should never happen.)
744 */
745 SMB_VC_LOCK(vcp);
746 if (vcp->iod_thr == NULL)
747 vcp->iod_thr = curthread;
748 else
749 err = EEXIST;
750 SMB_VC_UNLOCK(vcp);
751 if (err)
752 return (err);
753
754 /*
755 * Copy the "work" state, etc. into the VC,
756 * and back to the caller on the way out.
757 * Clear the "out only" part.
758 */
759 if (ddi_copyin((void *)arg, &vcp->vc_work,
760 sizeof (smbioc_ssn_work_t), flags)) {
761 err = EFAULT;
762 goto out;
763 }
764 vcp->vc_work.wk_out_state = 0;
765
766 switch (cmd) {
767
768 case SMBIOC_IOD_CONNECT:
769 err = nsmb_iod_connect(vcp, cr);
770 break;
771
772 case SMBIOC_IOD_NEGOTIATE:
773 err = nsmb_iod_negotiate(vcp, cr);
774 break;
775
776 case SMBIOC_IOD_SSNSETUP:
777 err = nsmb_iod_ssnsetup(vcp, cr);
778 break;
779
780 case SMBIOC_IOD_WORK:
781 err = smb_iod_vc_work(vcp, flags, cr);
782 break;
783
784 case SMBIOC_IOD_IDLE:
785 err = smb_iod_vc_idle(vcp);
786 break;
787
788 case SMBIOC_IOD_RCFAIL:
789 err = smb_iod_vc_rcfail(vcp);
790 break;
791
792 default:
793 err = ENOTTY;
794 break;
795 }
796
797 out:
798 vcp->vc_work.wk_out_state = vcp->vc_state;
799 (void) ddi_copyout(&vcp->vc_work, (void *)arg,
800 sizeof (smbioc_ssn_work_t), flags);
801
802 /*
803 * The IOD thread is leaving the driver. Clear iod_thr,
804 * and wake up anybody waiting for us to quit.
805 */
806 SMB_VC_LOCK(vcp);
807 vcp->iod_thr = NULL;
808 cv_broadcast(&vcp->vc_statechg);
809 SMB_VC_UNLOCK(vcp);
810
811 return (err);
812 }
813
814 int
815 smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
816 {
817 int err;
818
819 /*
820 * Serialize ioctl calls. The smb_usr_... functions
821 * don't expect concurrent calls on a given sdp.
822 */
823 mutex_enter(&sdp->sd_lock);
824 if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
825 mutex_exit(&sdp->sd_lock);
826 return (EBUSY);
827 }
828 sdp->sd_flags |= NSMBFL_IOCTL;
829 mutex_exit(&sdp->sd_lock);
830
831 err = 0;
832 switch (cmd) {
833 case SMBIOC_GETVERS:
834 (void) ddi_copyout(&nsmb_version, (void *)arg,
835 sizeof (nsmb_version), flags);
836 break;
837
838 case SMBIOC_GETSSNKEY:
839 err = smb_usr_get_ssnkey(sdp, arg, flags);
840 break;
841
842 case SMBIOC_DUP_DEV:
843 err = smb_usr_dup_dev(sdp, arg, flags);
844 break;
845
846 case SMBIOC_XACTNP:
847 err = smb_usr_xnp(sdp, arg, flags, cr);
848 break;
849
850 case SMBIOC_READ:
851 case SMBIOC_WRITE:
852 err = smb_usr_rw(sdp, cmd, arg, flags, cr);
853 break;
854
855 case SMBIOC_NTCREATE:
856 err = smb_usr_ntcreate(sdp, arg, flags, cr);
857 break;
858
859 case SMBIOC_PRINTJOB:
860 err = smb_usr_printjob(sdp, arg, flags, cr);
861 break;
862
863 case SMBIOC_CLOSEFH:
864 err = smb_usr_closefh(sdp, cr);
865 break;
866
867 case SMBIOC_SSN_CREATE:
868 case SMBIOC_SSN_FIND:
869 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
870 break;
871
872 case SMBIOC_SSN_KILL:
873 case SMBIOC_SSN_RELE:
874 err = smb_usr_drop_ssn(sdp, cmd);
875 break;
876
877 case SMBIOC_TREE_CONNECT:
878 case SMBIOC_TREE_FIND:
879 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
880 break;
881
882 case SMBIOC_TREE_KILL:
883 case SMBIOC_TREE_RELE:
884 err = smb_usr_drop_tree(sdp, cmd);
885 break;
886
887 case SMBIOC_IOD_CONNECT:
888 case SMBIOC_IOD_NEGOTIATE:
889 case SMBIOC_IOD_SSNSETUP:
890 case SMBIOC_IOD_WORK:
891 case SMBIOC_IOD_IDLE:
892 case SMBIOC_IOD_RCFAIL:
893 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
894 break;
895
896 case SMBIOC_PK_ADD:
897 case SMBIOC_PK_DEL:
898 case SMBIOC_PK_CHK:
899 case SMBIOC_PK_DEL_OWNER:
900 case SMBIOC_PK_DEL_EVERYONE:
901 err = smb_pkey_ioctl(cmd, arg, flags, cr);
902 break;
903
904 default:
905 err = ENOTTY;
906 break;
907 }
908
909 mutex_enter(&sdp->sd_lock);
910 sdp->sd_flags &= ~NSMBFL_IOCTL;
911 mutex_exit(&sdp->sd_lock);
912
913 return (err);
914 }
|