Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)

*** 31,43 **** * * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <sys/param.h> #include <sys/kmem.h> #include <sys/systm.h> --- 31,44 ---- * * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> #include <sys/kmem.h> #include <sys/systm.h>
*** 50,90 **** #include <sys/sunddi.h> #include <sys/cmn_err.h> #include <netsmb/smb_osdep.h> #include <netsmb/smb.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_rq.h> #include <netsmb/smb_subr.h> #include <netsmb/smb_dev.h> static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); /* - * Ioctl function for SMBIOC_FLAGS2 - */ - int - smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags) - { - struct smb_vc *vcp = NULL; - - /* This ioctl requires a session. */ - if ((vcp = sdp->sd_vc) == NULL) - return (ENOTCONN); - - /* - * Return the flags2 value. - */ - if (ddi_copyout(&vcp->vc_hflags2, (void *)arg, - sizeof (u_int16_t), flags)) - return (EFAULT); - - return (0); - } - - /* * Ioctl function for SMBIOC_GETSSNKEY * Size copied out is SMBIOC_HASH_SZ. * * The RPC library needs this for encrypting things * like "set password" requests. This is called --- 51,70 ---- #include <sys/sunddi.h> #include <sys/cmn_err.h> #include <netsmb/smb_osdep.h> + #include <smb/winioctl.h> #include <netsmb/smb.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_rq.h> #include <netsmb/smb_subr.h> #include <netsmb/smb_dev.h> static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); /* * Ioctl function for SMBIOC_GETSSNKEY * Size copied out is SMBIOC_HASH_SZ. * * The RPC library needs this for encrypting things * like "set password" requests. This is called
*** 103,338 **** return (ENOTCONN); /* * Return the session key. */ ! if (ddi_copyout(vcp->vc_ssn_key, (void *)arg, SMBIOC_HASH_SZ, flags)) return (EFAULT); return (0); } /* ! * Ioctl function for SMBIOC_REQUEST */ int ! smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; ! smbioc_rq_t *ioc = NULL; ! struct smb_rq *rqp = NULL; ! struct mbchain *mbp; ! struct mdchain *mdp; ! uint32_t rsz; int err, mbseg; ! /* This ioctl requires a share. */ ! if ((ssp = sdp->sd_share) == NULL) ! return (ENOTCONN); ! smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } - /* See ddi_copyin, ddi_copyout */ - mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; - /* ! * Lots of SMB commands could be safe, but ! * these are the only ones used by libsmbfs. */ ! switch (ioc->ioc_cmd) { ! /* These are OK */ ! case SMB_COM_CLOSE: ! case SMB_COM_FLUSH: ! case SMB_COM_NT_CREATE_ANDX: ! case SMB_COM_OPEN_PRINT_FILE: ! case SMB_COM_CLOSE_PRINT_FILE: ! break; ! ! default: ! err = EPERM; ! goto out; ! } ! ! err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp); if (err) goto out; - mbp = &rqp->sr_rq; - err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg); - - err = smb_rq_simple(rqp); - if (err == 0) { /* ! * This may have been an open, so save the ! * generation ID of the share, which we ! * check before trying read or write. */ ! sdp->sd_vcgenid = ssp->ss_vcgenid; ! ! /* ! * Have reply data. to copyout. ! * SMB header already parsed. ! */ ! mdp = &rqp->sr_rp; ! rsz = msgdsize(mdp->md_top) - SMB_HDRLEN; ! if (ioc->ioc_rbufsz < rsz) { ! err = EOVERFLOW; ! goto out; } - ioc->ioc_rbufsz = rsz; - err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg); - if (err) - goto out; - - } - - ioc->ioc_errclass = rqp->sr_errclass; - ioc->ioc_serror = rqp->sr_serror; - ioc->ioc_error = rqp->sr_error; - (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); - - out: - if (rqp != NULL) - smb_rq_done(rqp); /* free rqp */ - kmem_free(ioc, sizeof (*ioc)); smb_credrele(&scred); ! return (err); ! ! } ! ! /* ! * Ioctl function for SMBIOC_T2RQ ! */ ! int ! smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) ! { ! struct smb_cred scred; ! struct smb_share *ssp; ! smbioc_t2rq_t *ioc = NULL; ! struct smb_t2rq *t2p = NULL; ! struct mdchain *mdp; ! int err, len, mbseg; ! ! /* This ioctl requires a share. */ ! if ((ssp = sdp->sd_share) == NULL) ! return (ENOTCONN); ! ! smb_credinit(&scred, cr); ! ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); ! if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { ! err = EFAULT; ! goto out; ! } ! ! /* See ddi_copyin, ddi_copyout */ ! mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; ! ! if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) { ! err = EINVAL; ! goto out; ! } ! ! /* ! * Fill in the FID for libsmbfs transact named pipe. ! */ ! if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) { ! if (sdp->sd_vcgenid != ssp->ss_vcgenid) { ! err = ESTALE; ! goto out; ! } ! ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid; ! } ! ! t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); ! err = smb_t2_init(t2p, SSTOCP(ssp), ! ioc->ioc_setup, ioc->ioc_setupcnt, &scred); ! if (err) ! goto out; ! t2p->t2_setupcount = ioc->ioc_setupcnt; ! t2p->t2_setupdata = ioc->ioc_setup; ! ! /* This ioc member is a fixed-size array. */ ! if (ioc->ioc_name[0]) { ! /* Get the name length - carefully! */ ! ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0'; ! t2p->t_name_len = strlen(ioc->ioc_name); ! t2p->t_name = ioc->ioc_name; ! } ! t2p->t2_maxscount = 0; ! t2p->t2_maxpcount = ioc->ioc_rparamcnt; ! t2p->t2_maxdcount = ioc->ioc_rdatacnt; ! ! /* Transmit parameters */ ! err = smb_cpdatain(&t2p->t2_tparam, ! ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg); ! if (err) ! goto out; ! ! /* Transmit data */ ! err = smb_cpdatain(&t2p->t2_tdata, ! ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg); ! if (err) ! goto out; ! ! err = smb_t2_request(t2p); ! ! /* Copyout returned parameters. */ ! mdp = &t2p->t2_rparam; ! if (err == 0 && mdp->md_top != NULL) { ! /* User's buffer large enough? */ ! len = m_fixhdr(mdp->md_top); ! if (len > ioc->ioc_rparamcnt) { err = EMSGSIZE; goto out; } ! ioc->ioc_rparamcnt = (ushort_t)len; ! err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg); if (err) goto out; } else ! ioc->ioc_rparamcnt = 0; ! /* Copyout returned data. */ ! mdp = &t2p->t2_rdata; ! if (err == 0 && mdp->md_top != NULL) { ! /* User's buffer large enough? */ ! len = m_fixhdr(mdp->md_top); ! if (len > ioc->ioc_rdatacnt) { ! err = EMSGSIZE; ! goto out; } - ioc->ioc_rdatacnt = (ushort_t)len; - err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); - if (err) - goto out; - } else - ioc->ioc_rdatacnt = 0; - ioc->ioc_errclass = t2p->t2_sr_errclass; - ioc->ioc_serror = t2p->t2_sr_serror; - ioc->ioc_error = t2p->t2_sr_error; - ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; - (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); - out: - if (t2p != NULL) { - /* Note: t2p->t_name no longer allocated */ - smb_t2_done(t2p); - kmem_free(t2p, sizeof (*t2p)); - } kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); return (err); } /* helper for _t2request */ --- 83,187 ---- return (ENOTCONN); /* * Return the session key. */ ! if (vcp->vc_ssnkey == NULL || ! vcp->vc_ssnkeylen < SMBIOC_HASH_SZ) ! return (EINVAL); ! if (ddi_copyout(vcp->vc_ssnkey, (void *)arg, SMBIOC_HASH_SZ, flags)) return (EFAULT); return (0); } /* ! * Ioctl function for SMBIOC_XACTNP (transact named pipe) */ int ! smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; ! struct smb_fh *fhp; ! smbioc_xnp_t *ioc = NULL; ! struct mbchain send_mb; ! struct mdchain recv_md; ! uint32_t rdlen; int err, mbseg; ! /* This ioctl requires a file handle. */ ! if ((fhp = sdp->sd_fh) == NULL) ! return (EINVAL); ! ssp = FHTOSS(fhp); ! /* After reconnect, force close+reopen */ ! if (fhp->fh_vcgenid != ssp->ss_vcgenid) ! return (ESTALE); ! ! bzero(&send_mb, sizeof (send_mb)); ! bzero(&recv_md, sizeof (recv_md)); ! ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } /* ! * Copyin the send data, into an mbchain, ! * save output buffer size. */ ! mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; ! err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg); if (err) goto out; + rdlen = ioc->ioc_rdlen; /* ! * Run the SMB2 ioctl or SMB1 trans2 */ ! smb_credinit(&scred, cr); ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! err = smb2_smb_ioctl(ssp, &fhp->fh_fid2, ! &send_mb, &recv_md, &rdlen, ! FSCTL_PIPE_TRANSCEIVE, &scred); ! } else { ! err = smb_t2_xnp(ssp, fhp->fh_fid1, ! &send_mb, &recv_md, &rdlen, ! &ioc->ioc_more, &scred); } smb_credrele(&scred); ! /* Copyout returned data. */ ! if (err == 0 && recv_md.md_top != NULL) { ! /* User's buffer large enough for copyout? */ ! size_t len = m_fixhdr(recv_md.md_top); ! if (len > ioc->ioc_rdlen) { err = EMSGSIZE; goto out; } ! err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg); if (err) goto out; } else ! ioc->ioc_rdlen = 0; ! /* Tell caller received length */ ! if (rdlen <= ioc->ioc_rdlen) { ! /* Normal case */ ! ioc->ioc_rdlen = rdlen; ! } else { ! /* Buffer overlow. Leave ioc_rdlen */ ! ioc->ioc_more = 1; } (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); out: kmem_free(ioc, sizeof (*ioc)); return (err); } /* helper for _t2request */
*** 356,381 **** int smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; smbioc_rw_t *ioc = NULL; struct iovec aiov[1]; struct uio auio; - uint16_t fh; int err; uio_rw_t rw; ! /* This ioctl requires a share. */ ! if ((ssp = sdp->sd_share) == NULL) ! return (ENOTCONN); /* After reconnect, force close+reopen */ ! if (sdp->sd_vcgenid != ssp->ss_vcgenid) return (ESTALE); - smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } --- 205,230 ---- int smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; + struct smb_fh *fhp; smbioc_rw_t *ioc = NULL; struct iovec aiov[1]; struct uio auio; int err; uio_rw_t rw; ! /* This ioctl requires a file handle. */ ! if ((fhp = sdp->sd_fh) == NULL) ! return (EINVAL); ! ssp = FHTOSS(fhp); /* After reconnect, force close+reopen */ ! if (fhp->fh_vcgenid != ssp->ss_vcgenid) return (ESTALE); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; }
*** 390,408 **** default: err = ENODEV; goto out; } - /* - * If caller passes -1 in ioc_fh, then - * use the FID from SMBIOC_NTCREATE. - */ - if (ioc->ioc_fh == -1) - fh = (uint16_t)sdp->sd_smbfid; - else - fh = (uint16_t)ioc->ioc_fh; - aiov[0].iov_base = ioc->ioc_base; aiov[0].iov_len = (size_t)ioc->ioc_cnt; auio.uio_iov = aiov; auio.uio_iovcnt = 1; --- 239,248 ----
*** 410,420 **** auio.uio_segflg = (flags & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; auio.uio_fmode = 0; auio.uio_resid = (size_t)ioc->ioc_cnt; ! err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); /* * On return ioc_cnt holds the * number of bytes transferred. */ --- 250,262 ---- auio.uio_segflg = (flags & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; auio.uio_fmode = 0; auio.uio_resid = (size_t)ioc->ioc_cnt; ! smb_credinit(&scred, cr); ! err = smb_rwuio(fhp, rw, &auio, &scred, 0); ! smb_credrele(&scred); /* * On return ioc_cnt holds the * number of bytes transferred. */
*** 422,432 **** (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); out: kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); return (err); } /* --- 264,273 ----
*** 437,460 **** smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct mbchain name_mb; struct smb_share *ssp; smbioc_ntcreate_t *ioc = NULL; - uint16_t fid; int err, nmlen; /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) return (ENOTCONN); ! /* Must not be already open. */ ! if (sdp->sd_smbfid != -1) return (EINVAL); - mb_init(&name_mb); - smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } --- 278,301 ---- smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct mbchain name_mb; struct smb_share *ssp; + struct smb_fh *fhp = NULL; smbioc_ntcreate_t *ioc = NULL; int err, nmlen; + mb_init(&name_mb); + /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) return (ENOTCONN); ! /* Must not already have a file handle. */ ! if (sdp->sd_fh != NULL) return (EINVAL); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; }
*** 466,497 **** ioc->ioc_name, nmlen, SMB_CS_NONE, NULL); if (err != 0) goto out; ! /* Do the OtW open, save the FID. */ err = smb_smb_ntcreate(ssp, &name_mb, 0, /* create flags */ ioc->ioc_req_acc, ioc->ioc_efattr, ioc->ioc_share_acc, ioc->ioc_open_disp, ioc->ioc_creat_opts, NTCREATEX_IMPERSONATION_IMPERSONATION, &scred, ! &fid, NULL, NULL); if (err != 0) goto out; ! sdp->sd_smbfid = fid; ! sdp->sd_vcgenid = ssp->ss_vcgenid; out: kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); mb_done(&name_mb); return (err); } --- 307,349 ---- ioc->ioc_name, nmlen, SMB_CS_NONE, NULL); if (err != 0) goto out; ! err = smb_fh_create(ssp, &fhp); ! if (err != 0) ! goto out; ! ! /* ! * Do the OtW open, save the FID. ! */ ! smb_credinit(&scred, cr); err = smb_smb_ntcreate(ssp, &name_mb, 0, /* create flags */ ioc->ioc_req_acc, ioc->ioc_efattr, ioc->ioc_share_acc, ioc->ioc_open_disp, ioc->ioc_creat_opts, NTCREATEX_IMPERSONATION_IMPERSONATION, &scred, ! fhp, NULL, NULL); + smb_credrele(&scred); if (err != 0) goto out; ! fhp->fh_rights = ioc->ioc_req_acc; ! smb_fh_opened(fhp); ! sdp->sd_fh = fhp; ! fhp = NULL; out: + if (fhp != NULL) + smb_fh_rele(fhp); kmem_free(ioc, sizeof (*ioc)); mb_done(&name_mb); return (err); }
*** 500,581 **** * SMBIOC_PRINTJOB */ int smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; smbioc_printjob_t *ioc = NULL; ! uint16_t fid; ! int err; /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) return (ENOTCONN); /* The share must be a print queue. */ if (ssp->ss_type != STYPE_PRINTQ) return (EINVAL); ! /* Must not be already open. */ ! if (sdp->sd_smbfid != -1) return (EINVAL); smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0'; ! /* Do the OtW open, save the FID. */ err = smb_smb_open_prjob(ssp, ioc->ioc_title, ioc->ioc_setuplen, ioc->ioc_prmode, ! &scred, &fid); if (err != 0) goto out; ! sdp->sd_smbfid = fid; ! sdp->sd_vcgenid = ssp->ss_vcgenid; out: kmem_free(ioc, sizeof (*ioc)); ! smb_credrele(&scred); return (err); } /* * Helper for nsmb_ioctl case * SMBIOC_CLOSEFH */ int smb_usr_closefh(smb_dev_t *sdp, cred_t *cr) { ! struct smb_cred scred; ! struct smb_share *ssp; ! uint16_t fid; ! int err; ! /* This ioctl requires a share. */ ! if ((ssp = sdp->sd_share) == NULL) ! return (ENOTCONN); ! if (sdp->sd_smbfid == -1) ! return (0); ! fid = (uint16_t)sdp->sd_smbfid; ! sdp->sd_smbfid = -1; ! smb_credinit(&scred, cr); ! if (ssp->ss_type == STYPE_PRINTQ) ! err = smb_smb_close_prjob(ssp, fid, &scred); ! else ! err = smb_smb_close(ssp, fid, NULL, &scred); ! smb_credrele(&scred); ! ! return (err); } /* * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE * Find or create a session (a.k.a. "VC" in here) --- 352,476 ---- * SMBIOC_PRINTJOB */ int smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { + static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS; struct smb_cred scred; + struct mbchain name_mb; struct smb_share *ssp; + struct smb_fh *fhp = NULL; smbioc_printjob_t *ioc = NULL; ! int err, cklen, nmlen; ! uint32_t access = SA_RIGHT_FILE_WRITE_DATA | ! SA_RIGHT_FILE_READ_ATTRIBUTES; + mb_init(&name_mb); + /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) return (ENOTCONN); /* The share must be a print queue. */ if (ssp->ss_type != STYPE_PRINTQ) return (EINVAL); ! /* Must not already have a file handle. */ ! if (sdp->sd_fh != NULL) return (EINVAL); smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } + + /* + * Use the print job title as the file name to open, but + * check for invalid characters first. See the notes in + * libsmbfs/smb/print.c about job name sanitizing. + */ ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0'; + nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1); + cklen = strcspn(ioc->ioc_title, invalid_chars); + if (cklen < nmlen) { + err = EINVAL; + goto out; + } ! /* Build name_mb */ ! err = smb_put_dmem(&name_mb, SSTOVC(ssp), ! ioc->ioc_title, nmlen, ! SMB_CS_NONE, NULL); ! if (err != 0) ! goto out; ! ! err = smb_fh_create(ssp, &fhp); ! if (err != 0) ! goto out; ! ! /* ! * Do the OtW open, save the FID. ! */ ! smb_credinit(&scred, cr); ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! err = smb2_smb_ntcreate(ssp, &name_mb, ! NULL, NULL, /* cctx in, out */ ! 0, /* create flags */ ! access, ! SMB_EFA_NORMAL, ! NTCREATEX_SHARE_ACCESS_NONE, ! NTCREATEX_DISP_CREATE, ! NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, ! NTCREATEX_IMPERSONATION_IMPERSONATION, ! &scred, ! &fhp->fh_fid2, ! NULL, ! NULL); ! } else { err = smb_smb_open_prjob(ssp, ioc->ioc_title, ioc->ioc_setuplen, ioc->ioc_prmode, ! &scred, &fhp->fh_fid1); ! } ! smb_credrele(&scred); if (err != 0) goto out; ! fhp->fh_rights = access; ! smb_fh_opened(fhp); ! sdp->sd_fh = fhp; ! fhp = NULL; out: + if (fhp != NULL) + smb_fh_rele(fhp); kmem_free(ioc, sizeof (*ioc)); ! mb_done(&name_mb); return (err); } /* * Helper for nsmb_ioctl case * SMBIOC_CLOSEFH */ + /*ARGSUSED*/ int smb_usr_closefh(smb_dev_t *sdp, cred_t *cr) { ! struct smb_fh *fhp; ! /* This ioctl requires a file handle. */ ! if ((fhp = sdp->sd_fh) == NULL) ! return (EINVAL); ! sdp->sd_fh = NULL; ! smb_fh_close(fhp); ! smb_fh_rele(fhp); ! return (0); } /* * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE * Find or create a session (a.k.a. "VC" in here)
*** 823,850 **** sdp->sd_level = SMBL_VC; return (0); } - /* ! * Ioctl function: SMBIOC_IOD_WORK ! * ! * Become the reader (IOD) thread, until either the connection is ! * reset by the server, or until the connection is idle longer than ! * some max time. (max idle time not yet implemented) */ int ! smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { ! struct smb_vc *vcp = NULL; int err = 0; ! /* Must have a valid session. */ if ((vcp = sdp->sd_vc) == NULL) return (EINVAL); ! if (vcp->vc_flags & SMBV_GONE) return (EINVAL); /* * Is there already an IOD for this VC? * (Should never happen.) --- 718,743 ---- sdp->sd_level = SMBL_VC; return (0); } /* ! * Ioctl handler for all SMBIOC_IOD_... */ int ! smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { ! struct smb_vc *vcp; int err = 0; ! /* Must be the IOD. */ ! if ((sdp->sd_flags & NSMBFL_IOD) == 0) ! return (EINVAL); ! /* Must have a VC and no share. */ if ((vcp = sdp->sd_vc) == NULL) return (EINVAL); ! if (sdp->sd_share != NULL) return (EINVAL); /* * Is there already an IOD for this VC? * (Should never happen.)
*** 857,899 **** SMB_VC_UNLOCK(vcp); if (err) return (err); /* ! * Copy the "work" state, etc. into the VC ! * The MAC key is copied separately. */ if (ddi_copyin((void *)arg, &vcp->vc_work, sizeof (smbioc_ssn_work_t), flags)) { err = EFAULT; goto out; } ! if (vcp->vc_u_maclen) { ! vcp->vc_mackeylen = vcp->vc_u_maclen; ! vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP); ! if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey, ! vcp->vc_mackeylen, flags)) { ! err = EFAULT; ! goto out; ! } ! } ! err = smb_iod_vc_work(vcp, cr); ! /* Caller wants state here. */ ! vcp->vc_work.wk_out_state = vcp->vc_state; ! (void) ddi_copyout(&vcp->vc_work, (void *)arg, ! sizeof (smbioc_ssn_work_t), flags); ! out: ! if (vcp->vc_mackey) { ! kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); ! vcp->vc_mackey = NULL; ! vcp->vc_mackeylen = 0; } /* * The IOD thread is leaving the driver. Clear iod_thr, * and wake up anybody waiting for us to quit. */ SMB_VC_LOCK(vcp); --- 750,806 ---- SMB_VC_UNLOCK(vcp); if (err) return (err); /* ! * Copy the "work" state, etc. into the VC, ! * and back to the caller on the way out. ! * Clear the "out only" part. */ if (ddi_copyin((void *)arg, &vcp->vc_work, sizeof (smbioc_ssn_work_t), flags)) { err = EFAULT; goto out; } ! vcp->vc_work.wk_out_state = 0; ! switch (cmd) { ! case SMBIOC_IOD_CONNECT: ! err = nsmb_iod_connect(vcp, cr); ! break; ! case SMBIOC_IOD_NEGOTIATE: ! err = nsmb_iod_negotiate(vcp, cr); ! break; ! case SMBIOC_IOD_SSNSETUP: ! err = nsmb_iod_ssnsetup(vcp, cr); ! break; ! ! case SMBIOC_IOD_WORK: ! err = smb_iod_vc_work(vcp, flags, cr); ! break; ! ! case SMBIOC_IOD_IDLE: ! err = smb_iod_vc_idle(vcp); ! break; ! ! case SMBIOC_IOD_RCFAIL: ! err = smb_iod_vc_rcfail(vcp); ! break; ! ! default: ! err = ENOTTY; ! break; } + out: + vcp->vc_work.wk_out_state = vcp->vc_state; + (void) ddi_copyout(&vcp->vc_work, (void *)arg, + sizeof (smbioc_ssn_work_t), flags); + /* * The IOD thread is leaving the driver. Clear iod_thr, * and wake up anybody waiting for us to quit. */ SMB_VC_LOCK(vcp);
*** 902,970 **** SMB_VC_UNLOCK(vcp); return (err); } - /* - * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL - * - * Wait for user-level requests to be enqueued on this session, - * and then return to the user-space helper, which will then - * initiate a reconnect, etc. - */ int ! smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags) { ! struct smb_vc *vcp = NULL; ! int err = 0; - /* Must have a valid session. */ - if ((vcp = sdp->sd_vc) == NULL) - return (EINVAL); - if (vcp->vc_flags & SMBV_GONE) - return (EINVAL); - /* ! * Is there already an IOD for this VC? ! * (Should never happen.) */ ! SMB_VC_LOCK(vcp); ! if (vcp->iod_thr == NULL) ! vcp->iod_thr = curthread; ! else ! err = EEXIST; ! SMB_VC_UNLOCK(vcp); ! if (err) ! return (err); ! /* nothing to copyin */ ! switch (cmd) { ! case SMBIOC_IOD_IDLE: ! err = smb_iod_vc_idle(vcp); break; case SMBIOC_IOD_RCFAIL: ! err = smb_iod_vc_rcfail(vcp); break; default: err = ENOTTY; ! goto out; } ! /* Both of these ioctls copy out the new state. */ ! (void) ddi_copyout(&vcp->vc_state, (void *)arg, ! sizeof (int), flags); - out: - /* - * The IOD thread is leaving the driver. Clear iod_thr, - * and wake up anybody waiting for us to quit. - */ - SMB_VC_LOCK(vcp); - vcp->iod_thr = NULL; - cv_broadcast(&vcp->vc_statechg); - SMB_VC_UNLOCK(vcp); - return (err); } --- 809,914 ---- SMB_VC_UNLOCK(vcp); return (err); } int ! smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { ! int err; /* ! * Serialize ioctl calls. The smb_usr_... functions ! * don't expect concurrent calls on a given sdp. */ ! mutex_enter(&sdp->sd_lock); ! if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) { ! mutex_exit(&sdp->sd_lock); ! return (EBUSY); ! } ! sdp->sd_flags |= NSMBFL_IOCTL; ! mutex_exit(&sdp->sd_lock); ! err = 0; switch (cmd) { ! case SMBIOC_GETVERS: ! (void) ddi_copyout(&nsmb_version, (void *)arg, ! sizeof (nsmb_version), flags); break; + case SMBIOC_GETSSNKEY: + err = smb_usr_get_ssnkey(sdp, arg, flags); + break; + + case SMBIOC_DUP_DEV: + err = smb_usr_dup_dev(sdp, arg, flags); + break; + + case SMBIOC_XACTNP: + err = smb_usr_xnp(sdp, arg, flags, cr); + break; + + case SMBIOC_READ: + case SMBIOC_WRITE: + err = smb_usr_rw(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_NTCREATE: + err = smb_usr_ntcreate(sdp, arg, flags, cr); + break; + + case SMBIOC_PRINTJOB: + err = smb_usr_printjob(sdp, arg, flags, cr); + break; + + case SMBIOC_CLOSEFH: + err = smb_usr_closefh(sdp, cr); + break; + + case SMBIOC_SSN_CREATE: + case SMBIOC_SSN_FIND: + err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_SSN_KILL: + case SMBIOC_SSN_RELE: + err = smb_usr_drop_ssn(sdp, cmd); + break; + + case SMBIOC_TREE_CONNECT: + case SMBIOC_TREE_FIND: + err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_TREE_KILL: + case SMBIOC_TREE_RELE: + err = smb_usr_drop_tree(sdp, cmd); + break; + + case SMBIOC_IOD_CONNECT: + case SMBIOC_IOD_NEGOTIATE: + case SMBIOC_IOD_SSNSETUP: + case SMBIOC_IOD_WORK: + case SMBIOC_IOD_IDLE: case SMBIOC_IOD_RCFAIL: ! err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr); break; + case SMBIOC_PK_ADD: + case SMBIOC_PK_DEL: + case SMBIOC_PK_CHK: + case SMBIOC_PK_DEL_OWNER: + case SMBIOC_PK_DEL_EVERYONE: + err = smb_pkey_ioctl(cmd, arg, flags, cr); + break; + default: err = ENOTTY; ! break; } ! mutex_enter(&sdp->sd_lock); ! sdp->sd_flags &= ~NSMBFL_IOCTL; ! mutex_exit(&sdp->sd_lock); return (err); }