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-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12394 rb3934 Even NULL sessions should use SPNEGO
@@ -20,11 +20,12 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Functions to setup connections (TCP and/or NetBIOS)
* This has the fall-back logic for IP6, IP4, NBT
@@ -48,481 +49,348 @@
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <uuid/uuid.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <cflib.h>
+
#include "charsets.h"
#include "private.h"
+#include "smb_crypt.h"
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-static int smb_connect_timeout = 30; /* seconds */
-int smb_recv_timeout = 30; /* seconds */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2);
-int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
-int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
-int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
-/*
- * Internal set sockopt for int-sized options.
- * Borrowed from: libnsl/rpc/ti_opts.c
- */
-static int
-smb_setopt_int(int fd, int level, int name, int val)
+const char *
+smb_iod_state_name(enum smbiod_state st)
{
- struct t_optmgmt oreq, ores;
- struct {
- struct t_opthdr oh;
- int ival;
- } opts;
+ const char *n = "(?)";
- /* opt header */
- opts.oh.len = sizeof (opts);
- opts.oh.level = level;
- opts.oh.name = name;
- opts.oh.status = 0;
- opts.ival = val;
-
- oreq.flags = T_NEGOTIATE;
- oreq.opt.buf = (void *)&opts;
- oreq.opt.len = sizeof (opts);
-
- ores.flags = 0;
- ores.opt.buf = NULL;
- ores.opt.maxlen = 0;
-
- if (t_optmgmt(fd, &oreq, &ores) < 0) {
- DPRINT("t_opgmgnt, t_errno = %d", t_errno);
- if (t_errno == TSYSERR)
- return (errno);
- return (EPROTO);
+ switch (st) {
+ case SMBIOD_ST_UNINIT:
+ n = "UNINIT!";
+ break;
+ case SMBIOD_ST_IDLE:
+ n = "IDLE";
+ break;
+ case SMBIOD_ST_RECONNECT:
+ n = "RECONNECT";
+ break;
+ case SMBIOD_ST_RCFAILED:
+ n = "RCFAILED";
+ break;
+ case SMBIOD_ST_CONNECTED:
+ n = "CONNECTED";
+ break;
+ case SMBIOD_ST_NEGOTIATED:
+ n = "NEGOTIATED";
+ break;
+ case SMBIOD_ST_AUTHCONT:
+ n = "AUTHCONT";
+ break;
+ case SMBIOD_ST_AUTHFAIL:
+ n = "AUTHFAIL";
+ break;
+ case SMBIOD_ST_AUTHOK:
+ n = "AUTHOK";
+ break;
+ case SMBIOD_ST_VCACTIVE:
+ n = "VCACTIVE";
+ break;
+ case SMBIOD_ST_DEAD:
+ n = "DEAD";
+ break;
}
- if (ores.flags != T_SUCCESS) {
- DPRINT("flags 0x%x, status 0x%x",
- (int)ores.flags, (int)opts.oh.status);
- return (EPROTO);
- }
- return (0);
+ return (n);
}
-static int
-smb_setopts(int fd)
-{
- int err;
-
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
+/*
+ * Make a new connection, or reconnect.
*
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
+ * This is called first from the door service thread in smbiod
+ * (so that can report success or failure to the door client)
+ * and thereafter it's called when we need to reconnect after a
+ * network outage (or whatever might cause connection loss).
*/
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
- if (err) {
- DPRINT("set SO_SNDBUF, err %d", err);
- }
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
- if (err) {
- DPRINT("set SO_RCVBUF, err %d", err);
- }
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (err) {
- DPRINT("set SO_KEEPALIVE, err %d", err);
- }
-
- err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
- if (err) {
- DPRINT("set TCP_NODELAY, err %d", err);
- }
-
- /* Set the connect timeout (in milliseconds). */
- err = smb_setopt_int(fd, IPPROTO_TCP,
- TCP_CONN_ABORT_THRESHOLD,
- smb_connect_timeout * 1000);
- if (err) {
- DPRINT("set connect timeout, err %d", err);
- }
- return (0);
-}
-
-
int
-conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+smb_iod_connect(smb_ctx_t *ctx)
{
- struct sockaddr_in6 sin6;
- char *dev = "/dev/tcp6";
- char paddrbuf[INET6_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ char *uuid_str;
+ int err;
+ struct mbdata blob;
+ char *nego_buf = NULL;
+ uint32_t nego_len;
- if (sa->sa_family != AF_INET6) {
- DPRINT("bad af %d", sa->sa_family);
+ memset(&blob, 0, sizeof (blob));
+
+ if (ctx->ct_srvname[0] == '\0') {
+ DPRINT("sername not set!");
return (EINVAL);
}
- bcopy(sa, &sin6, sizeof (sin6));
- sin6.sin6_port = htons(port);
+ DPRINT("server: %s", ctx->ct_srvname);
- DPRINT("tcp6: %s (%d)",
- inet_ntop(AF_INET6, &sin6.sin6_addr,
- paddrbuf, sizeof (paddrbuf)), port);
+ if (smb_debug)
+ dump_ctx("smb_iod_connect", ctx);
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
+ /*
+ * Get local machine name.
+ * Full name - not a NetBIOS name.
+ */
+ if (ctx->ct_locname == NULL) {
+ err = smb_getlocalname(&ctx->ct_locname);
+ if (err) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local name"), err);
return (err);
}
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
}
- sndcall.addr.maxlen = sizeof (sin6);
- sndcall.addr.len = sizeof (sin6);
- sndcall.addr.buf = (void *) &sin6;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
- DPRINT("tcp6: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
+ /*
+ * Get local machine uuid.
+ */
+ uuid_str = cf_get_client_uuid();
+ if (uuid_str == NULL) {
+ err = EINVAL;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local UUID"), err);
return (err);
-}
+ }
+ (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid);
+ free(uuid_str);
+ uuid_str = NULL;
-/*
- * This is used for both SMB over TCP (port 445)
- * and NetBIOS - see conn_nbt().
+ /*
+ * We're called with each IP address
+ * already copied into ct_srvaddr.
*/
-int
-conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
-{
- struct sockaddr_in sin;
- char *dev = "/dev/tcp";
- char paddrbuf[INET_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
+ ctx->ct_flags |= SMBCF_RESOLVED;
- if (sa->sa_family != AF_INET) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin, sizeof (sin));
- sin.sin_port = htons(port);
-
- DPRINT("tcp4: %s (%d)",
- inet_ntop(AF_INET, &sin.sin_addr,
- paddrbuf, sizeof (paddrbuf)), port);
-
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
+ /*
+ * Ask the drvier to connect.
+ */
+ DPRINT("Try ioctl connect...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
err = errno;
- perror(dev);
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: connect failed"),
+ err, ossn->ssn_srvname);
return (err);
}
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin);
- sndcall.addr.len = sizeof (sin);
- sndcall.addr.buf = (void *) &sin;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
+ DPRINT("Connect OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
- DPRINT("tcp4: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
+ /*
+ * Setup a buffer to recv the nego. hint.
+ */
+ nego_len = 4096;
+ err = mb_init_sz(&blob, nego_len);
+ if (err)
+ goto out;
+ nego_buf = blob.mb_top->m_data;
+ work->wk_u_auth_rbuf.lp_ptr = nego_buf;
+ work->wk_u_auth_rlen = nego_len;
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * Open a NetBIOS connection (session, port 139)
- *
- * The optional name parameter, if passed, means
- * we found the sockaddr via NetBIOS name lookup,
- * and can just use that for our session request.
- * Otherwise (if name is NULL), we're connecting
- * by IP address, and need to come up with the
- * NetBIOS name by other means.
+ /*
+ * Ask the driver for SMB negotiate
*/
-int
-conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
-{
- struct sockaddr_in sin;
- struct sockaddr *sa;
- char server[NB_NAMELEN];
- char workgroup[NB_NAMELEN];
- int err, nberr, port;
+ DPRINT("Try ioctl negotiate...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: negotiate failed"),
+ err, ossn->ssn_srvname);
+ goto out;
+ }
+ DPRINT("Negotiate OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
- bcopy(saarg, &sin, sizeof (sin));
- sa = (struct sockaddr *)&sin;
+ nego_len = work->wk_u_auth_rlen;
+ blob.mb_top->m_len = nego_len;
- switch (sin.sin_family) {
- case AF_NETBIOS: /* our fake AF */
- sin.sin_family = AF_INET;
- break;
- case AF_INET:
- break;
- default:
- DPRINT("bad af %d", sin.sin_family);
- return (EINVAL);
+ if (smb_debug) {
+ DPRINT("Sec. blob: %d", nego_len);
+ smb_hexdump(nego_buf, nego_len);
}
- port = IPPORT_NETBIOS_SSN;
/*
- * If we have a NetBIOS name, just use it.
- * This is the path taken when we've done a
- * NetBIOS name lookup on this name to get
- * the IP address in the passed sa. Otherwise,
- * we're connecting by IP address, and need to
- * figure out what NetBIOS name to use.
+ * Do SMB Session Setup (authenticate)
+ * Always "extended security" now (SPNEGO)
*/
- if (name) {
- strlcpy(server, name, sizeof (server));
- DPRINT("given name: %s", server);
- } else {
- /*
- *
- * Try a NetBIOS node status query,
- * which searches for a type=[20] name.
- * If that doesn't work, just use the
- * (fake) "*SMBSERVER" name.
- */
- DPRINT("try node status");
- server[0] = '\0';
- nberr = nbns_getnodestatus(ctx->ct_nb,
- &sin.sin_addr, server, workgroup);
- if (nberr == 0 && server[0] != '\0') {
- /* Found the name. Save for reconnect. */
- DPRINT("found name: %s", server);
- strlcpy(ctx->ct_srvname, server,
- sizeof (ctx->ct_srvname));
- } else {
- DPRINT("getnodestatus, nberr %d", nberr);
- strlcpy(server, "*SMBSERVER", sizeof (server));
+ DPRINT("Do session setup...");
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ if (err != 0) {
+ DPRINT("Session setup err=%d", err);
+ goto out;
}
- }
/*
- * Establish the TCP connection.
- * Careful to close it on errors.
+ * Success! We return zero now, and our caller (normally
+ * the smbiod program) will then call smb_iod_work in a
+ * new thread to service this VC as long as necessary.
*/
- if ((err = conn_tcp4(ctx, sa, port)) != 0) {
- DPRINT("TCP connect: err=%d", err);
- goto out;
- }
+ DPRINT("Session setup OK");
- /* Connected. Do NetBIOS session request. */
- err = nb_ssn_request(ctx, server);
- if (err)
- DPRINT("ssn_rq, err %d", err);
-
out:
- if (err) {
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
- }
+ mb_done(&blob);
+
return (err);
}
/*
- * Make a new connection, or reconnect.
+ * smb_ssnsetup_spnego
+ *
+ * This does an SMB session setup sequence using SPNEGO.
+ * The state changes seen during this sequence are there
+ * just to help track what's going on.
*/
int
-smb_iod_connect(smb_ctx_t *ctx)
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
{
- struct sockaddr *sa;
- int err, err2;
- struct mbdata blob;
+ struct mbdata send_mb, recv_mb;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int err;
- memset(&blob, 0, sizeof (blob));
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_mb, sizeof (recv_mb));
- if (ctx->ct_srvname[0] == '\0') {
- DPRINT("sername not set!");
- return (EINVAL);
+ err = ssp_ctx_create_client(ctx, hint_mb);
+ if (err)
+ goto out;
+
+ /* NULL input indicates first call. */
+ err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
}
- DPRINT("server: %s", ctx->ct_srvname);
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
+ DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
+ smb_iod_state_name(work->wk_out_state));
- if (smb_debug)
- dump_ctx("smb_iod_connect", ctx);
-
+ if (err == 0) {
/*
- * This may be a reconnect, so
- * cleanup if necessary.
+ * Session setup complete w/ success.
+ * Should have state AUTHOK
*/
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
+ if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
+ DPRINT("Wrong state (expected AUTHOK)");
}
+ break;
+ }
+ if (err != EINPROGRESS) {
/*
- * Get local machine name.
- * Full name - not a NetBIOS name.
+ * Session setup complete w/ failure.
+ * Should have state AUTHFAIL
*/
- if (ctx->ct_locname == NULL) {
- err = smb_getlocalname(&ctx->ct_locname);
- if (err) {
- smb_error(dgettext(TEXT_DOMAIN,
- "can't get local name"), err);
- return (err);
+ if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
+ DPRINT("Wrong state (expected AUTHFAIL)");
}
+ goto out;
}
/*
- * We're called with each IP address
- * already copied into ct_srvaddr.
+ * err == EINPROGRESS
+ * Session setup continuing.
+ * Should have state AUTHCONT
*/
- ctx->ct_flags |= SMBCF_RESOLVED;
-
- sa = &ctx->ct_srvaddr.sa;
- switch (sa->sa_family) {
-
- case AF_INET6:
- err = conn_tcp6(ctx, sa, IPPORT_SMB);
- break;
-
- case AF_INET:
- err = conn_tcp4(ctx, sa, IPPORT_SMB);
- /*
- * If port 445 was not listening, try port 139.
- * Note: Not doing NetBIOS name lookup here.
- * We already have the IP address.
- */
- switch (err) {
- case ECONNRESET:
- case ECONNREFUSED:
- err2 = conn_nbt(ctx, sa, NULL);
- if (err2 == 0)
- err = 0;
+ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
+ DPRINT("Wrong state (expected AUTHCONT)");
}
- break;
- case AF_NETBIOS:
- /* Like AF_INET, but use NetBIOS ssn. */
- err = conn_nbt(ctx, sa, ctx->ct_srvname);
- break;
-
- default:
- DPRINT("skipped family %d", sa->sa_family);
- err = EPROTONOSUPPORT;
- break;
- }
-
-
+ /* middle calls get both in, out */
+ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
if (err) {
- DPRINT("connect, err=%d", err);
- return (err);
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
}
+ }
/*
- * Do SMB Negotiate Protocol.
+ * Only get here via break in the err==0 case above,
+ * so we're finalizing a successful session setup.
+ *
+ * NULL output token here indicates the final call.
*/
- err = smb_negprot(ctx, &blob);
- if (err)
- goto out;
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
/*
- * Empty user name means an explicit request for
- * NULL session setup, which is a special case.
- * If negotiate determined that we want to do
- * SMB signing, we have to turn that off for a
- * NULL session. [MS-SMB 3.3.5.3].
+ * The signing key is in ctx->ct_mackey
+ * (a.k.a. ct_work.wk_iods.is_u_mackey)
+ * and session key is in ctx->ct_ssn_key
+ * (a.k.a. ct_work.wk_iods.is_ssn_key)
*/
- if (ctx->ct_user[0] == '\0') {
- /* Null user should have null domain too. */
- ctx->ct_domain[0] = '\0';
- ctx->ct_authflags = SMB_AT_ANON;
- ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
- ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
- }
- /*
- * Do SMB Session Setup (authenticate)
+out:
+ /* Done with ctx->ct_ssp_ctx */
+ ssp_ctx_destroy(ctx);
+
+ return (err);
+}
+
+int smb_max_authtok_sz = 0x10000;
+
+/*
+ * Session Setup function, calling the nsmb driver.
*
- * If the server negotiated extended security,
- * run the SPNEGO state machine, otherwise do
- * one of the old-style variants.
+ * Args
+ * send_mb: [in] outgoing blob data to send
+ * recv_mb: [out] received blob data buffer
*/
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
- } else {
- /*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1, or ANON (if enabled).
- */
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- err = smb_ssnsetup_ntlm2(ctx);
- } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
- err = smb_ssnsetup_ntlm1(ctx);
- } else if (ctx->ct_authflags & SMB_AT_ANON) {
- err = smb_ssnsetup_null(ctx);
- } else {
- /*
- * Don't return EAUTH, because a new
- * password prompt will not help.
- */
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *send_mb, struct mbdata *recv_mb)
+{
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ mbuf_t *m;
+ int err;
+
+ /* Setup receive buffer for the auth data. */
+ err = mb_init_sz(recv_mb, smb_max_authtok_sz);
+ if (err != 0)
+ return (err);
+ m = recv_mb->mb_top;
+ work->wk_u_auth_rbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_rlen = m->m_maxlen;
+
+ /* ... and the auth data to send. */
+ m = send_mb->mb_top;
+ work->wk_u_auth_wbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_wlen = m->m_len;
+
+ DPRINT("Session setup ioctl...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
+ err = errno;
+ if (err != 0 && err != EINPROGRESS) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: session setup "),
+ err, ossn->ssn_srvname);
}
}
+ DPRINT("Session setup ret %d", err);
-out:
- mb_done(&blob);
+ /* Free the auth data we sent. */
+ mb_done(send_mb);
- if (err) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- } else {
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- DPRINT("tran_fd = %d", ctx->ct_tran_fd);
- }
+ /* Setup length of received auth data */
+ m = recv_mb->mb_top;
+ m->m_len = work->wk_u_auth_rlen;
return (err);
}