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)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
re #11128 nsmb_close locking and teardown deadlock
*** 31,42 ****
*
* $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
*/
/*
! * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* various SMB requests. Most of the routines merely packs data into mbufs.
*/
--- 31,43 ----
*
* $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
*/
/*
! * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
* various SMB requests. Most of the routines merely packs data into mbufs.
*/
*** 47,56 ****
--- 48,58 ----
#include <sys/lock.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/random.h>
#include <sys/note.h>
+ #include <sys/errno.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
*** 59,98 ****
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#define STYPE_LEN 8 /* share type strings */
! /*
! * Largest size to use with LARGE_READ/LARGE_WRITE.
! * Specs say up to 64k data bytes, but Windows traffic
! * uses 60k... no doubt for some good reason.
! * (Probably to keep 4k block alignment.)
! * XXX: Move to smb.h maybe?
! */
! #define SMB_MAX_LARGE_RW_SIZE (60*1024)
/*
* Default timeout values, all in seconds.
* Make these tunable (only via mdb for now).
*/
int smb_timo_notice = 15;
int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
int smb_timo_open = 45;
int smb_timo_read = 45;
int smb_timo_write = 60; /* was SMBWRTTIMO */
int smb_timo_append = 90;
! static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
! uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
! static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
! uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
! static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
! uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
! static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
! uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
/*
* Get the string representation of a share "use" type,
* as needed for the "service" in tree connect.
*/
static const char *
--- 61,617 ----
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#define STYPE_LEN 8 /* share type strings */
! struct smb_dialect {
! int d_id;
! const char *d_name;
! };
+ static struct smb_dialect smb_dialects[3] = {
+ {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
+ {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+ #define NDIALECT_SMB1 2
+ {SMB_DIALECT_SMB2_FF, "SMB 2.???"},
+ #define NDIALECT_SMB2 3
+ };
+
+ static const uint32_t smb_clnt_caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
+
/*
* Default timeout values, all in seconds.
* Make these tunable (only via mdb for now).
*/
int smb_timo_notice = 15;
int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
+ int smb_timo_logon = 45;
int smb_timo_open = 45;
int smb_timo_read = 45;
int smb_timo_write = 60; /* was SMBWRTTIMO */
int smb_timo_append = 90;
! int
! smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
! {
! smb_sopt_t *sv = &vcp->vc_sopt;
! smbioc_ssn_work_t *wk = &vcp->vc_work;
! struct smb_rq *rqp = NULL;
! struct mbchain *mbp = NULL;
! struct mdchain *mdp = NULL;
! struct smb_dialect *dp;
! int err, sblen, tlen;
! uint8_t wc, eklen;
! uint16_t dindex, bc;
! uint16_t ndialects;
! boolean_t will_sign = B_FALSE;
! /*
! * Initialize: vc_hflags and vc_hflags2.
! * Note: vcp->vc_hflags* are copied into the
! * (per request) rqp->rq_hflags* by smb_rq_init.
! *
! * Like Windows, set FLAGS2_UNICODE in our first request,
! * even though technically we don't yet know whether the
! * server supports Unicode. Will clear this flag below
! * if we find out it doesn't. Need to do this because
! * some servers reject all non-Unicode requests.
! */
! vcp->vc_hflags =
! SMB_FLAGS_CASELESS |
! SMB_FLAGS_CANONICAL_PATHNAMES;
! vcp->vc_hflags2 =
! SMB_FLAGS2_KNOWS_LONG_NAMES |
! SMB_FLAGS2_KNOWS_EAS |
! SMB_FLAGS2_IS_LONG_NAME |
! SMB_FLAGS2_EXT_SEC |
! SMB_FLAGS2_ERR_STATUS |
! SMB_FLAGS2_UNICODE;
+ /*
+ * The initial UID needs to be zero,
+ */
+ vcp->vc_smbuid = 0;
+
+ /*
+ * (Re)init negotiated values
+ */
+ bzero(sv, sizeof (*sv));
+ sv->sv_maxmux = 1;
+ sv->sv_maxvcs = 1;
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Should we offer the magic SMB2 dialect?
+ */
+ if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
+ ndialects = NDIALECT_SMB2;
+ else
+ ndialects = NDIALECT_SMB1;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ for (dindex = 0; dindex < ndialects; dindex++) {
+ dp = &smb_dialects[dindex];
+ mb_put_uint8(mbp, SMB_DT_DIALECT);
+ tlen = strlen(dp->d_name) + 1;
+ mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
+ }
+ smb_rq_bend(rqp);
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb_rq_internal(rqp, smb_timo_default);
+ /*
+ * If it's an SMB1-to-SMB2 negotiate response,
+ * call the special handler and then skip the
+ * whole rest of this function.
+ */
+ if (err == EPROTO) {
+ err = smb2_parse_smb1nego_resp(rqp);
+ smb_rq_done(rqp);
+ return (err);
+ }
+ if (err) {
+ SMBSDEBUG("smb_rq_internal, err %d", err);
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the response
+ *
+ * Comments to right show names as described in
+ * The Microsoft SMB Protocol spec. [MS-SMB]
+ * section 2.2.3
+ */
+ smb_rq_getreply(rqp, &mdp);
+ (void) md_get_uint8(mdp, &wc);
+ err = md_get_uint16le(mdp, &dindex);
+ if (err != 0)
+ goto errout;
+ if (dindex >= ndialects) {
+ SMBERROR("Invalid dialect index from server: %s\n",
+ vcp->vc_srvname);
+ err = EBADRPC;
+ goto errout;
+ }
+ dp = smb_dialects + dindex;
+ sv->sv_proto = dp->d_id;
+ SMBSDEBUG("Dialect %s", dp->d_name);
+ if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+ SMBSDEBUG("old dialect %s", dp->d_name);
+ goto errout;
+ }
+ if (wc != 17) {
+ SMBSDEBUG("bad wc %d", (int)wc);
+ goto errout;
+ }
+ md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */
+ md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */
+ md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */
+ md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */
+ md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */
+ md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */
+ md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */
+ md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
+ md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
+ md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */
+ err = md_get_uint16le(mdp, &bc); /* ByteCount */
+ if (err)
+ goto errout;
+
+ /* BEGIN CSTYLED */
+ /*
+ * Will we do SMB signing? Or block the connection?
+ * The table below describes this logic. References:
+ * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+ * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+ * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+ *
+ * Srv/Cli | Required | Enabled | If Required | Disabled
+ * ------------+----------+------------+-------------+-----------
+ * Required | Signed | Signed | Signed | Blocked [1]
+ * ------------+----------+------------+-------------+-----------
+ * Enabled | Signed | Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * If Required | Signed | Not Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * Disabled | Blocked | Not Signed | Not Signed | Not Signed
+ *
+ * [1] Like Windows 2003 and later, we don't really implement
+ * the "Disabled" setting. Instead we implement "If Required",
+ * so we always sign if the server requires signing.
+ */
+ /* END CSTYLED */
+
+ if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+ /*
+ * Server requires signing. We will sign,
+ * even if local setting is "disabled".
+ */
+ will_sign = B_TRUE;
+ } else if (sv->sv_sm & SMB_SM_SIGS) {
+ /*
+ * Server enables signing (client's option).
+ * If enabled locally, do signing.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
+ will_sign = B_TRUE;
+ /* else not signing. */
+ } else {
+ /*
+ * Server does not support signing.
+ * If we "require" it, bail now.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ SMBERROR("Client requires signing "
+ "but server has it disabled.");
+ err = EBADRPC;
+ goto errout;
+ }
+ }
+
+ /*
+ * Anonymous sessions can't sign.
+ */
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) {
+ will_sign = B_FALSE;
+ }
+
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign) {
+ vcp->vc_flags |= SMBV_SIGNING;
+ vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+ /*
+ * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
+ * we should NOT use "large read/write" even though the
+ * server might offer those capabilities.
+ */
+ sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+ }
+
+ /* See comment above re. FLAGS2_UNICODE */
+ if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
+ vcp->vc_flags |= SMBV_UNICODE;
+ else
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
+
+ if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+ /* They don't do NT error codes. */
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+ }
+
+ /*
+ * Warn if they don't support SMB_CAP_NT_SMBS
+ * (We'll try to use NtCreate anyway)
+ */
+ if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+ cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
+ vcp->vc_srvname);
+ }
+
+ /*
+ * The rest of the message varies depending on
+ * whether we've negotiated "extended security".
+ *
+ * With extended security, we have:
+ * Server_GUID (length 16)
+ * Security_BLOB
+ * Otherwise we have:
+ * EncryptionKey (length is eklen)
+ * PrimaryDomain
+ */
+ if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+ SMBSDEBUG("Ext.Security: yes");
+
+ /*
+ * Skip the server GUID.
+ */
+ err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
+ if (err)
+ goto errout;
+ /*
+ * Remainder is the security blob.
+ * Note: eklen "must be ignored" [MS-SMB]
+ */
+ sblen = (int)bc - SMB_GUIDLEN;
+ if (sblen < 0)
+ goto errout;
+ /* Security blob (hint) is next */
+ } else {
+ SMBSDEBUG("Ext.Security: no");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sblen) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sblen;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sblen;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
+ if (err)
+ goto errout;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sv->sv_maxmux < 1)
+ sv->sv_maxmux = 1;
+ if (sv->sv_maxvcs < 1)
+ sv->sv_maxvcs = 1;
+ if (sv->sv_maxtx < 1024)
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Maximum transfer size.
+ * Sanity checks:
+ *
+ * Let's be conservative about an upper limit here.
+ * Win2k uses 16644 (and others) so 32k should be a
+ * reasonable sanity limit for this value.
+ *
+ * Note that this limit does NOT affect READX/WRITEX
+ * with CAP_LARGE_..., which we nearly always use.
+ */
+ vcp->vc_txmax = sv->sv_maxtx;
+ if (vcp->vc_txmax > 0x8000)
+ vcp->vc_txmax = 0x8000;
+
+ /*
+ * Max read/write sizes, WITHOUT overhead.
+ * This is just the payload size, so we must
+ * leave room for the SMB headers, etc.
+ * This is just the ct_txmax value, but
+ * reduced and rounded down. Tricky bit:
+ *
+ * Servers typically give us a value that's
+ * some nice "round" number, i.e 0x4000 plus
+ * some overhead, i.e. Win2k: 16644==0x4104
+ * Subtract for the SMB header (32) and the
+ * SMB command word and byte vectors (34?),
+ * then round down to a 512 byte multiple.
+ */
+ tlen = vcp->vc_txmax - 68;
+ tlen &= 0xFE00;
+
+ vcp->vc_rwmax = tlen;
+ vcp->vc_rxmax = tlen;
+ vcp->vc_wxmax = tlen;
+
+ /*
+ * Most of the "capability" bits we offer in session setup
+ * are just copied from those offered by the server.
+ */
+ sv->sv_caps &= smb_clnt_caps_mask;
+
+ smb_rq_done(rqp);
+ return (0);
+
+ errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+ }
+
+ static const char NativeOS[] = "illumos";
+ static const char LanMan[] = "NETSMB";
+
+ int
+ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+ {
+ smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint32_t caps;
+ uint16_t action, bc, sblen;
+ uint8_t wc;
+
+ caps = sv->sv_caps;
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+ scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Build the SMB Session Setup request.
+ * Always extended security form.
+ */
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
+ mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
+ mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
+ mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
+ mb_put_uint16le(mbp, 1); /* 4: VcNumber */
+ mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
+ mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */
+ mb_put_uint32le(mbp, 0); /* 8,9: reserved */
+ mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
+ smb_rq_wend(rqp); /* 12: Byte Count */
+ smb_rq_bstart(rqp);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
+ (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
+ smb_rq_bend(rqp);
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb_rq_internal(rqp, smb_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ if (vcp->vc_smbuid == 0)
+ vcp->vc_smbuid = rqp->sr_rpuid;
+
+ /*
+ * Parse the reply
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ err = md_get_uint8(mdp, &wc);
+ if (err != 0)
+ wc = 0;
+ if (wc != 4) {
+ ret = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* secondary cmd */
+ md_get_uint16le(mdp, NULL); /* andxoffset */
+ md_get_uint16le(mdp, &action); /* action XXX */
+ md_get_uint16le(mdp, &sblen); /* sec. blob len */
+ md_get_uint16le(mdp, &bc); /* byte count */
+ /*
+ * Get the security blob, after
+ * sanity-checking the length.
+ */
+ if (sblen == 0 || sblen > bc) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (sblen > wk->wk_u_auth_rlen) {
+ ret = EBADRPC;
+ goto out;
+ }
+ sb = wk->wk_u_auth_rbuf.lp_ptr;
+ err = md_get_mem(mdp, sb, sblen, MB_MUSER);
+ if (err) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Native OS, LANMGR, & Domain follow here.
+ * We don't need them and don't parse them.
+ */
+
+ out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* UID no longer valid. */
+ vcp->vc_smbuid = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+ }
+
+ int
+ smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+ {
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
+ if (error)
+ return (error);
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff);
+ mb_put_uint8(mbp, 0);
+ mb_put_uint16le(mbp, 0);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+ }
+
/*
* Get the string representation of a share "use" type,
* as needed for the "service" in tree connect.
*/
static const char *
*** 350,360 ****
/*
* Modern create/open of file or directory.
*/
int
! smb_smb_ntcreate(
struct smb_share *ssp,
struct mbchain *name_mb,
uint32_t cr_flags, /* create flags */
uint32_t req_acc, /* requested access */
uint32_t efa, /* ext. file attrs (DOS attr +) */
--- 869,879 ----
/*
* Modern create/open of file or directory.
*/
int
! smb1_smb_ntcreate(
struct smb_share *ssp,
struct mbchain *name_mb,
uint32_t cr_flags, /* create flags */
uint32_t req_acc, /* requested access */
uint32_t efa, /* ext. file attrs (DOS attr +) */
*** 473,483 ****
return (0);
}
int
! smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
struct mbchain *mbp;
long time;
--- 992,1002 ----
return (0);
}
int
! smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
struct mbchain *mbp;
long time;
*** 598,702 ****
error = smb_rq_simple(rqp);
smb_rq_done(rqp);
return (error);
}
- /*
- * Common function for read/write with UIO.
- * Called by netsmb smb_usr_rw,
- * smbfs_readvnode, smbfs_writevnode
- */
int
! smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
uio_t *uiop, smb_cred_t *scred, int timo)
{
! struct smb_vc *vcp = SSTOVC(ssp);
! ssize_t save_resid;
! uint32_t len, rlen, maxlen;
! int error = 0;
! int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
! uio_t *, smb_cred_t *, int);
!
! /*
! * Determine which function to use,
! * and the transfer size per call.
! */
! if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
! /*
! * Using NT LM 0.12, so readx, writex.
! * Make sure we can represent the offset.
! */
! if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
! (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
! return (EFBIG);
!
! if (rw == UIO_READ) {
! iofun = smb_smb_readx;
! if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
! maxlen = SMB_MAX_LARGE_RW_SIZE;
! else
! maxlen = vcp->vc_rxmax;
! } else { /* UIO_WRITE */
! iofun = smb_smb_writex;
! if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
! maxlen = SMB_MAX_LARGE_RW_SIZE;
! else
! maxlen = vcp->vc_wxmax;
! }
! } else {
! /*
! * Using the old SMB_READ and SMB_WRITE so
! * we're limited to 32-bit offsets, etc.
! * XXX: Someday, punt the old dialects.
! */
! if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
! return (EFBIG);
!
! if (rw == UIO_READ) {
! iofun = smb_smb_read;
! maxlen = vcp->vc_rxmax;
! } else { /* UIO_WRITE */
! iofun = smb_smb_write;
! maxlen = vcp->vc_wxmax;
! }
! }
!
! save_resid = uiop->uio_resid;
! while (uiop->uio_resid > 0) {
! /* Lint: uio_resid may be 64-bits */
! rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
! error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
!
! /*
! * Note: the iofun called uio_update, so
! * not doing that here as one might expect.
! *
! * Quit the loop either on error, or if we
! * transferred less then requested.
! */
! if (error || (rlen < len))
! break;
!
! timo = 0; /* only first I/O should wait */
! }
! if (error && (save_resid != uiop->uio_resid)) {
! /*
! * Stopped on an error after having
! * successfully transferred data.
! * Suppress this error.
! */
! SMBSDEBUG("error %d suppressed\n", error);
! error = 0;
! }
!
! return (error);
! }
!
! static int
! smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
! uio_t *uiop, smb_cred_t *scred, int timo)
! {
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
int error;
uint32_t offlo, offhi, rlen;
--- 1117,1131 ----
error = smb_rq_simple(rqp);
smb_rq_done(rqp);
return (error);
}
int
! smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
! struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
int error;
uint32_t offlo, offhi, rlen;
*** 714,724 ****
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
! mb_put_uint16le(mbp, fid);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
/* (only indicates blocking) */
mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */
--- 1143,1153 ----
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
! mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
/* (only indicates blocking) */
mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */
*** 784,797 ****
out:
smb_rq_done(rqp);
return (error);
}
! static int
! smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
int error;
uint32_t offlo, offhi, rlen;
--- 1213,1227 ----
out:
smb_rq_done(rqp);
return (error);
}
! int
! smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
int error;
uint32_t offlo, offhi, rlen;
*** 809,819 ****
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
! mb_put_uint16le(mbp, fid);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
mb_put_uint16le(mbp, 0);
mb_put_uint16le(mbp, lenhi);
--- 1239,1249 ----
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
! mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
mb_put_uint16le(mbp, 0);
mb_put_uint16le(mbp, lenhi);
*** 857,1008 ****
out:
smb_rq_done(rqp);
return (error);
}
- static int
- smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
- {
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t bc, cnt, dlen, rcnt, todo;
- uint8_t wc;
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned reads. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
-
- if (timo == 0)
- timo = smb_timo_read;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 5) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &rcnt); /* ret. count */
- md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */
- md_get_uint16le(mdp, &bc); /* byte count */
- md_get_uint8(mdp, NULL); /* buffer format */
- error = md_get_uint16le(mdp, &dlen); /* data len */
- if (error)
- goto out;
- if (dlen < rcnt) {
- SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
- (int)dlen, (int)rcnt);
- rcnt = dlen;
- }
- if (rcnt == 0) {
- *lenp = 0;
- goto out;
- }
- /* paranoid */
- if (rcnt > cnt) {
- SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
- (int)rcnt, (int)cnt);
- rcnt = cnt;
- }
- error = md_get_uio(mdp, uiop, (int)rcnt);
- if (error)
- goto out;
-
- /* success */
- *lenp = (int)rcnt;
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
- static int
- smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
- {
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t cnt, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned writes. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, cnt);
-
- error = mb_put_uio(mbp, uiop, *lenp);
- if (error)
- goto out;
- smb_rq_bend(rqp);
- if (timo == 0)
- timo = smb_timo_write;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, &rcnt);
- if (error)
- goto out;
- *lenp = rcnt;
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
-
static u_int32_t smbechoes = 0;
int
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
{
struct smb_rq *rqp;
struct mbchain *mbp;
--- 1287,1303 ----
out:
smb_rq_done(rqp);
return (error);
}
static u_int32_t smbechoes = 0;
+ /*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb_rq_internal)
+ */
int
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
{
struct smb_rq *rqp;
struct mbchain *mbp;
*** 1016,1031 ****
mb_put_uint16le(mbp, 1); /* echo count */
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
smb_rq_bend(rqp);
- /*
- * Note: the IOD calls this, so
- * this request must not wait for
- * connection state changes, etc.
- */
rqp->sr_flags |= SMBR_NORECONNECT;
! error = smb_rq_simple_timed(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
}
--- 1311,1321 ----
mb_put_uint16le(mbp, 1); /* echo count */
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
smb_rq_bend(rqp);
rqp->sr_flags |= SMBR_NORECONNECT;
! error = smb_rq_internal(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
}