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,30 ****
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Functions to setup connections (TCP and/or NetBIOS)
* This has the fall-back logic for IP6, IP4, NBT
--- 20,31 ----
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! *
! * 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,528 ****
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
#include "charsets.h"
#include "private.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 */
! 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 *);
! /*
! * 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)
{
! struct t_optmgmt oreq, ores;
! struct {
! struct t_opthdr oh;
! int ival;
! } opts;
! /* 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);
}
- if (ores.flags != T_SUCCESS) {
- DPRINT("flags 0x%x, status 0x%x",
- (int)ores.flags, (int)opts.oh.status);
- return (EPROTO);
- }
! return (0);
}
! static int
! smb_setopts(int fd)
! {
! int err;
!
! /*
! * Set various socket/TCP options.
! * Failures here are not fatal -
! * just log a complaint.
*
! * We don't need these two:
! * SO_RCVTIMEO, SO_SNDTIMEO
*/
-
- 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)
{
! struct sockaddr_in6 sin6;
! char *dev = "/dev/tcp6";
! char paddrbuf[INET6_ADDRSTRLEN];
! struct t_call sndcall;
! int fd, err;
! if (sa->sa_family != AF_INET6) {
! DPRINT("bad af %d", sa->sa_family);
return (EINVAL);
}
! bcopy(sa, &sin6, sizeof (sin6));
! sin6.sin6_port = htons(port);
! DPRINT("tcp6: %s (%d)",
! inet_ntop(AF_INET6, &sin6.sin6_addr,
! paddrbuf, sizeof (paddrbuf)), port);
! fd = t_open(dev, O_RDWR, NULL);
! if (fd < 0) {
! /* Assume t_errno = TSYSERR */
! err = errno;
! perror(dev);
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);
return (err);
! }
! /*
! * This is used for both SMB over TCP (port 445)
! * and NetBIOS - see conn_nbt().
*/
! 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;
! 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 */
err = errno;
! perror(dev);
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("tcp4: connected, fd=%d", fd);
! ctx->ct_tran_fd = fd;
! return (0);
! 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.
*/
! 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;
! bcopy(saarg, &sin, sizeof (sin));
! sa = (struct sockaddr *)&sin;
! 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);
}
- 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.
*/
! 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));
}
- }
/*
! * Establish the TCP connection.
! * Careful to close it on errors.
*/
! if ((err = conn_tcp4(ctx, sa, port)) != 0) {
! DPRINT("TCP connect: err=%d", err);
! goto out;
! }
- /* 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;
! }
! }
return (err);
}
/*
! * Make a new connection, or reconnect.
*/
int
! smb_iod_connect(smb_ctx_t *ctx)
{
! struct sockaddr *sa;
! int err, err2;
! struct mbdata blob;
! memset(&blob, 0, sizeof (blob));
! if (ctx->ct_srvname[0] == '\0') {
! DPRINT("sername not set!");
! return (EINVAL);
}
! DPRINT("server: %s", ctx->ct_srvname);
! if (smb_debug)
! dump_ctx("smb_iod_connect", ctx);
!
/*
! * This may be a reconnect, so
! * cleanup if necessary.
*/
! if (ctx->ct_tran_fd != -1) {
! close(ctx->ct_tran_fd);
! ctx->ct_tran_fd = -1;
}
/*
! * 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);
}
}
/*
! * We're called with each IP address
! * already copied into ct_srvaddr.
*/
! 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;
}
- 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;
! }
!
!
if (err) {
! DPRINT("connect, err=%d", err);
! return (err);
}
/*
! * Do SMB Negotiate Protocol.
*/
! err = smb_negprot(ctx, &blob);
! if (err)
! goto out;
/*
! * 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].
*/
- 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)
*
! * If the server negotiated extended security,
! * run the SPNEGO state machine, otherwise do
! * one of the old-style variants.
*/
! 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;
}
}
! out:
! mb_done(&blob);
! 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);
! }
return (err);
}
--- 49,396 ----
#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"
! static int
! smb__ssnsetup(struct smb_ctx *ctx,
! struct mbdata *mbc1, struct mbdata *mbc2);
! int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
! const char *
! smb_iod_state_name(enum smbiod_state st)
{
! const char *n = "(?)";
! 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;
}
! return (n);
}
! /*
! * Make a new connection, or reconnect.
*
! * 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).
*/
int
! smb_iod_connect(smb_ctx_t *ctx)
{
! 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;
! memset(&blob, 0, sizeof (blob));
!
! if (ctx->ct_srvname[0] == '\0') {
! DPRINT("sername not set!");
return (EINVAL);
}
! DPRINT("server: %s", ctx->ct_srvname);
! if (smb_debug)
! dump_ctx("smb_iod_connect", ctx);
! /*
! * 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);
}
}
! /*
! * 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;
! /*
! * We're called with each IP address
! * already copied into ct_srvaddr.
*/
! ctx->ct_flags |= SMBCF_RESOLVED;
! /*
! * Ask the drvier to connect.
! */
! DPRINT("Try ioctl connect...");
! if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
err = errno;
! smb_error(dgettext(TEXT_DOMAIN,
! "%s: connect failed"),
! err, ossn->ssn_srvname);
return (err);
}
! DPRINT("Connect OK, new state=%s",
! smb_iod_state_name(work->wk_out_state));
! /*
! * 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;
! /*
! * Ask the driver for SMB negotiate
*/
! 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));
! nego_len = work->wk_u_auth_rlen;
! blob.mb_top->m_len = nego_len;
! if (smb_debug) {
! DPRINT("Sec. blob: %d", nego_len);
! smb_hexdump(nego_buf, nego_len);
}
/*
! * Do SMB Session Setup (authenticate)
! * Always "extended security" now (SPNEGO)
*/
! DPRINT("Do session setup...");
! err = smb_ssnsetup_spnego(ctx, &blob);
! if (err != 0) {
! DPRINT("Session setup err=%d", err);
! goto out;
}
/*
! * 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.
*/
! DPRINT("Session setup OK");
out:
! mb_done(&blob);
!
return (err);
}
/*
! * 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_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
{
! struct mbdata send_mb, recv_mb;
! smbioc_ssn_work_t *work = &ctx->ct_work;
! int err;
! bzero(&send_mb, sizeof (send_mb));
! bzero(&recv_mb, sizeof (recv_mb));
! 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;
}
! 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 (err == 0) {
/*
! * Session setup complete w/ success.
! * Should have state AUTHOK
*/
! if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
! DPRINT("Wrong state (expected AUTHOK)");
}
+ break;
+ }
+ if (err != EINPROGRESS) {
/*
! * Session setup complete w/ failure.
! * Should have state AUTHFAIL
*/
! if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
! DPRINT("Wrong state (expected AUTHFAIL)");
}
+ goto out;
}
/*
! * err == EINPROGRESS
! * Session setup continuing.
! * Should have state AUTHCONT
*/
! if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
! DPRINT("Wrong state (expected AUTHCONT)");
}
! /* middle calls get both in, out */
! err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
if (err) {
! DPRINT("smb__ssnsetup, ssp next, err=%d", err);
! goto out;
}
+ }
/*
! * 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.
*/
! (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
/*
! * 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)
*/
! 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.
*
! * Args
! * send_mb: [in] outgoing blob data to send
! * recv_mb: [out] received blob data buffer
*/
! 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);
! /* Free the auth data we sent. */
! mb_done(send_mb);
! /* Setup length of received auth data */
! m = recv_mb->mb_top;
! m->m_len = work->wk_u_auth_rlen;
return (err);
}