summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2018-01-20 12:23:17 -0500
committerGordon Ross <gwr@nexenta.com>2019-03-14 10:38:30 -0400
commit40c0e2317898b8c774791bdc2b30bd50111ab1fa (patch)
treef19033aaf4c50e0e14c5b4a0b826616bea923534 /usr/src
parent8329232e00f1048795bae53acb230316243aadb5 (diff)
downloadillumos-gate-40c0e2317898b8c774791bdc2b30bd50111ab1fa.tar.gz
9875 SMB client connection setup rework
Reviewed by: Evan Layton <evan.layton@nexenta.com> Reviewed by: Matt Barden <matt.barden@nexenta.com> Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c143
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/view.c19
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com8
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h34
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c603
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c52
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c38
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c3
-rw-r--r--usr/src/lib/libsmbfs/smb/getaddr.c17
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c71
-rw-r--r--usr/src/lib/libsmbfs/smb/krb5ssp.c61
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers12
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_ssn.c336
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c457
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c47
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h20
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c113
-rw-r--r--usr/src/lib/libsmbfs/smb/private.h68
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c446
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c470
-rw-r--r--usr/src/lib/libsmbfs/smb/signing.c263
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c459
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in75
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c9
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h107
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c128
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c398
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c60
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h12
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c27
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c466
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h9
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c109
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h13
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c177
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h3
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c404
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h156
-rw-r--r--usr/src/uts/common/sys/t_kuser.h1
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref75
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref75
43 files changed, 1848 insertions, 4207 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
index ae9dd15817..3a852c6978 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
@@ -23,7 +23,7 @@
# 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.
# Copyright (c) 2018, Joyent, Inc.
#
@@ -34,7 +34,7 @@
PROG= smbutil
OBJS= smbutil.o discon.o info.o login.o lookup.o print.o status.o view.o \
- shares_rap.o shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
+ shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
SRCS= $(OBJS:%.o=%.c)
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c b/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
deleted file mode 100644
index f2235e2880..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2000-2002, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: Id: view.c,v 1.9 2002/02/20 09:26:42 bp Exp
- */
-
-/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <netsmb/mchain.h> /* letohs, etc. */
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-
-#include "common.h"
-
-/*
- * Enumerate shares using Remote Administration Protocol (RAP)
- * Was in libsmbfs netshareenum.c
- */
-
-struct smb_share_info_1 {
- char shi1_netname[13];
- char shi1_pad;
- uint16_t shi1_type;
- uint32_t shi1_remark; /* char * */
-};
-
-static int
-smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
- int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
-{
- struct smb_rap *rap;
- long lval = -1;
- int error;
-
- error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
- if (error)
- return (error);
- smb_rap_setNparam(rap, sLevel); /* W - sLevel */
- smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
- smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
- error = smb_rap_request(rap, ctx);
- if (error == 0) {
- *pcEntriesRead = rap->r_entries;
- error = smb_rap_getNparam(rap, &lval);
- *pcTotalAvail = lval;
- /* Copy the data length into the IN/OUT variable. */
- *cbBuffer = rap->r_rcvbuflen;
- }
- error = smb_rap_error(rap, error);
- smb_rap_done(rap);
- return (error);
-}
-
-int
-share_enum_rap(smb_ctx_t *ctx)
-{
- struct smb_share_info_1 *shi;
- void *rpbuf;
- char *cp;
- int error, bufsize, i, rcnt, total;
- int lbound, rbound;
- uint16_t type;
-
- bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
- rpbuf = malloc(bufsize);
- if (rpbuf == NULL)
- return (errno);
-
- error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &rcnt, &total);
- if (error &&
- error != (ERROR_MORE_DATA | SMB_RAP_ERROR))
- goto out;
-
- /*
- * Bounds for offsets to comments strings.
- * After the array, and before the end.
- */
- lbound = rcnt * (sizeof (struct smb_share_info_1));
- rbound = bufsize;
-
- /* Print the header line. */
- view_print_share(NULL, 0, NULL);
-
- for (shi = rpbuf, i = 0; i < rcnt; i++, shi++) {
- type = letohs(shi->shi1_type);
-
- shi->shi1_pad = '\0'; /* ensure null termination */
-
- /*
- * Offsets to comment strings can be trash.
- * Only print when the offset is valid.
- */
- if (shi->shi1_remark >= lbound &&
- shi->shi1_remark < rbound) {
- cp = (char *)rpbuf + shi->shi1_remark;
- } else
- cp = NULL;
-
- /* Convert from OEM to local codeset? */
- view_print_share(shi->shi1_netname, type, cp);
- }
- error = 0;
-
-out:
- free(rpbuf);
- return (error);
-}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
index bf3397c166..18f0488ad3 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -51,8 +51,6 @@
#include <netsmb/smb_lib.h>
#include "common.h"
-static int use_rap;
-
void
view_usage(void)
{
@@ -86,15 +84,6 @@ cmd_view(int argc, char *argv[])
while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
if (opt == '?')
view_usage();
- /*
- * This is an undocumented option, just for testing.
- * Use the old LanMan Remote API Protocol (RAP) for
- * enumerating shares.
- */
- if (opt == 'B') {
- use_rap++;
- continue;
- }
error = smb_ctx_opt(ctx, opt, optarg);
if (error)
goto out;
@@ -137,12 +126,8 @@ again:
/*
* Have IPC$ tcon, now list shares.
- * Try RPC; if that fails, do RAP.
*/
- if (!use_rap)
- error = share_enum_rpc(ctx, ctx->ct_fullserver);
- if (error || use_rap)
- error = share_enum_rap(ctx);
+ error = share_enum_rpc(ctx, ctx->ct_fullserver);
out:
smb_ctx_free(ctx);
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index 3a5c62c46c..e69b199ad0 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -24,7 +24,7 @@
# Use is subject to license terms.
# Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com>
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -57,21 +57,15 @@ OBJ_LIB=\
nb.o \
nb_name.o \
nb_net.o \
- nb_ssn.o \
nbns_rq.o \
- negprot.o \
newvc.o \
nls.o \
ntlm.o \
ntlmssp.o \
print.o \
- rap.o \
rcfile.o \
- rq.o \
- signing.o \
spnego.o \
spnegoparse.o \
- ssnsetup.o \
ssp.o \
subr.o \
ui-sun.o \
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index 1f6e062e74..c9aa810c91 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -103,28 +103,21 @@ struct smb_ctx {
struct addrinfo *ct_addrinfo; /* IP addresses of the server */
struct nb_ctx *ct_nb; /* NetBIOS info. */
char *ct_locname; /* local (machine) name */
- smb_iod_ssn_t ct_iod_ssn;
- /* smbioc_oshare_t ct_sh; XXX */
int ct_minauth;
int ct_shtype_req; /* share type wanted */
char *ct_origshare;
char *ct_home;
char *ct_rpath; /* remote file name */
- /* Connection setup SMB stuff. */
- /* Strings from the SMB negotiate response. */
- char *ct_srv_OS;
- char *ct_srv_LM;
- uint32_t ct_clnt_caps;
+ /* See ssp.c */
+ void *ct_ssp_ctx;
+ smbioc_ssn_work_t ct_work;
+ smb_iod_ssn_t ct_iod_ssn;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
-
- /* See ssp.c */
- void *ct_ssp_ctx;
- smbioc_ssn_work_t ct_work;
};
@@ -142,16 +135,9 @@ struct smb_ctx {
#define ct_nthash ct_iod_ssn.iod_nthash
#define ct_lmhash ct_iod_ssn.iod_lmhash
-#define ct_sopt ct_work.wk_sopt
-#define ct_iods ct_work.wk_iods
-#define ct_tran_fd ct_work.wk_iods.is_tran_fd
-#define ct_hflags ct_work.wk_iods.is_hflags
-#define ct_hflags2 ct_work.wk_iods.is_hflags2
-#define ct_vcflags ct_work.wk_iods.is_vcflags
-#define ct_ssn_key ct_work.wk_iods.is_ssn_key
-#define ct_mac_seqno ct_work.wk_iods.is_next_seq
-#define ct_mackeylen ct_work.wk_iods.is_u_maclen
-#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr
+#define ct_vcflags ct_work.wk_vcflags
+#define ct_ssnkey_len ct_work.wk_u_ssnkey_len
+#define ct_ssnkey_buf ct_work.wk_u_ssnkey_buf.lp_ptr
/*
@@ -169,9 +155,7 @@ struct smb_ctx {
#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */
#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */
#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */
-#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */
-#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */
-#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */
+#define SMBCF_KCDOMAIN 0x01000000 /* use domain in KC lookup */
/*
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index c2ccc3361d..a45fa90958 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,7 +22,8 @@
/*
* 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.
*/
/*
@@ -53,322 +54,63 @@
#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 "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 */
-
-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);
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2);
-errout:
- close(fd);
- return (err);
-}
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
-/*
- * 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)
+const char *
+smb_iod_state_name(enum smbiod_state st)
{
- 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);
+ const char *n = "(?)";
- 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;
+ switch (st) {
+ case SMBIOD_ST_UNINIT:
+ n = "UNINIT!";
break;
- case AF_INET:
+ 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;
- 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);
+ return (n);
}
/*
@@ -377,9 +119,12 @@ out:
int
smb_iod_connect(smb_ctx_t *ctx)
{
- struct sockaddr *sa;
- int err, err2;
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int err;
struct mbdata blob;
+ char *nego_buf = NULL;
+ uint32_t nego_len;
memset(&blob, 0, sizeof (blob));
@@ -393,15 +138,6 @@ smb_iod_connect(smb_ctx_t *ctx)
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.
*/
@@ -420,109 +156,190 @@ smb_iod_connect(smb_ctx_t *ctx)
*/
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);
+ /*
+ * 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));
/*
- * Do SMB Negotiate Protocol.
+ * Setup a buffer to recv the nego. hint.
*/
- err = smb_negprot(ctx, &blob);
+ 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;
/*
- * 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].
+ * Ask the driver for SMB negotiate
*/
- 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;
+ 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)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine, otherwise do
- * one of the old-style variants.
+ * Always "extended security" now (SPNEGO)
*/
- 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;
- }
+ 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);
+}
+
+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) {
- 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);
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
+ }
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
+ if (err != 0 && err != EINPROGRESS) {
+ DPRINT("smb__ssnsetup, err=%d", err);
+ goto out;
+ }
+ DPRINT("smb__ssnsetup, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
+ if (work->wk_out_state == SMBIOD_ST_AUTHOK) {
+ err = 0;
+ break;
+ }
+ if (work->wk_out_state == SMBIOD_ST_AUTHFAIL) {
+ err = EAUTH;
+ goto out;
+ }
+ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
+ err = EPROTO;
+ goto out;
+ }
+ /* state == SMBIOD_ST_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;
+ }
+ }
+
+ /* NULL output indicates last call. */
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+ /*
+ * The session key is in ctx->ct_ssnkey_buf
+ * (a.k.a. ct_work.wk_u_ssn_key_buf)
+ */
+
+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);
}
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index e28599e28f..43ca516f81 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -148,10 +148,6 @@ dump_ctx_flags(int flags)
printf("AUTHREQ ");
if (flags & SMBCF_KCSAVE)
printf("KCSAVE ");
- if (flags & SMBCF_XXX)
- printf("XXX ");
- if (flags & SMBCF_SSNACTIVE)
- printf("SSNACTIVE ");
if (flags & SMBCF_KCDOMAIN)
printf("KCDOMAIN ");
printf("\n");
@@ -254,13 +250,12 @@ smb_ctx_init(struct smb_ctx *ctx)
ctx->ct_dev_fd = -1;
ctx->ct_door_fd = -1;
- ctx->ct_tran_fd = -1;
ctx->ct_parsedlevel = SMBL_NONE;
ctx->ct_minlevel = SMBL_NONE;
ctx->ct_maxlevel = SMBL_PATH;
/* Fill in defaults */
- ctx->ct_vopt = SMBVOPT_EXT_SEC;
+ ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
ctx->ct_owner = SMBM_ANY_OWNER;
ctx->ct_authflags = SMB_AT_DEFAULT;
ctx->ct_minauth = SMB_AT_MINAUTH;
@@ -410,10 +405,6 @@ smb_ctx_done(struct smb_ctx *ctx)
close(ctx->ct_door_fd);
ctx->ct_door_fd = -1;
}
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_srvaddr_s) {
free(ctx->ct_srvaddr_s);
ctx->ct_srvaddr_s = NULL;
@@ -446,17 +437,9 @@ smb_ctx_done(struct smb_ctx *ctx)
free(ctx->ct_rpath);
ctx->ct_rpath = NULL;
}
- if (ctx->ct_srv_OS) {
- free(ctx->ct_srv_OS);
- ctx->ct_srv_OS = NULL;
- }
- if (ctx->ct_srv_LM) {
- free(ctx->ct_srv_LM);
- ctx->ct_srv_LM = NULL;
- }
- if (ctx->ct_mackey) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
+ if (ctx->ct_ssnkey_buf) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
}
@@ -904,12 +887,11 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
}
/*
- * Suport a securty options arg, i.e. -S noext,lm,ntlm
+ * Suport a securty options arg, i.e. -S lm,ntlm
* for testing various type of authenticators.
*/
static struct nv
sectype_table[] = {
- /* noext - handled below */
{ "anon", SMB_AT_ANON },
{ "lm", SMB_AT_LM1 },
{ "ntlm", SMB_AT_NTLM1 },
@@ -935,13 +917,6 @@ smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
if (nlen == 0)
break;
- if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
- /* Don't offer extended security. */
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- p += nlen;
- continue;
- }
-
/* This is rarely called, so not optimized. */
for (nv = sectype_table; nv->name; nv++) {
tlen = strlen(nv->name);
@@ -1122,6 +1097,19 @@ smb_ctx_resolve(struct smb_ctx *ctx)
assert(ctx->ct_addrinfo != NULL);
/*
+ * Empty user name means an explicit request for
+ * NULL session setup, which is a special case.
+ * (No SMB signing, per [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_vopt |= SMBVOPT_ANONYMOUS;
+ ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
+ }
+
+ /*
* If we have a user name but no password,
* check for a keychain entry.
* XXX: Only for auth NTLM?
@@ -1139,6 +1127,7 @@ smb_ctx_resolve(struct smb_ctx *ctx)
*/
ctx->ct_authflags &= ctx->ct_minauth;
}
+
if (ctx->ct_authflags == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"no valid auth. types"), 0);
@@ -1195,7 +1184,6 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
rpc_cleanup_smbctx(ctx);
nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
- ctx->ct_flags &= ~SMBCF_SSNACTIVE;
}
fd = smb_open_driver();
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index b104502d9c..1c4e2dc236 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* 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>
@@ -62,9 +63,15 @@
#include "private.h"
+/*
+ * It's not actually necessary to call the CLOSEFH ioctl, but doing it
+ * makes debugging a little easier. If we were to skip the ioctl,
+ * nsmb_close would cleanup the handle, here or in process exit.
+ */
int
smb_fh_close(int fd)
{
+ (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL);
return (nsmb_close(fd));
}
@@ -251,21 +258,24 @@ smb_fh_xactnp(int fd,
int *rdlen, char *rdata, /* receive */
int *more)
{
- int err, rparamcnt;
- uint16_t setup[2];
-
- setup[0] = TRANS_TRANSACT_NAMED_PIPE;
- setup[1] = 0xFFFF; /* driver replaces this */
- rparamcnt = 0;
+ smbioc_xnp_t ioc;
- err = smb_t2_request(fd, 2, setup, "\\PIPE\\",
- 0, NULL, /* TX paramcnt, params */
- tdlen, (void *)tdata,
- &rparamcnt, NULL, /* no RX params */
- rdlen, rdata, more);
+ /* this gets copyin & copyout */
+ bzero(&ioc, sizeof (ioc));
+ ioc.ioc_fh = -1; /* tell driver to supply this */
+ ioc.ioc_tdlen = tdlen;
+ ioc.ioc_rdlen = *rdlen;
+ ioc.ioc_more = 0;
+ ioc.ioc_tdata = (char *)tdata;
+ ioc.ioc_rdata = rdata;
- if (err)
+ if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) {
*rdlen = 0;
+ return (-1);
+ }
+
+ *rdlen = ioc.ioc_rdlen;
+ *more = ioc.ioc_more;
- return (err);
+ return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index 9d9ccd678c..0e781f7099 100644
--- a/usr/src/lib/libsmbfs/smb/findvc.c
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -23,7 +23,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -121,7 +121,6 @@ smb_ctx_findvc(struct smb_ctx *ctx)
if (err == 0) {
/* re-use an existing VC */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
return (0);
}
}
diff --git a/usr/src/lib/libsmbfs/smb/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c
index 67e61567a1..7c01b0d7c9 100644
--- a/usr/src/lib/libsmbfs/smb/getaddr.c
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -57,6 +58,8 @@
#include "charsets.h"
#include "private.h"
+static char smb_port[16] = "445";
+
void
dump_addrinfo(struct addrinfo *ai)
{
@@ -118,7 +121,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
struct nb_ctx *nbc = ctx->ct_nb;
struct addrinfo hints, *res;
char *srvaddr_str;
- int gaierr, gaierr2;
+ int gaierr;
if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
return (EAI_NONAME);
@@ -154,19 +157,26 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+ gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res);
if (gaierr == 0) {
ctx->ct_addrinfo = res;
return (0);
}
/*
+ * If we really want to support NetBIOS, we should add
+ * an AF_NETBIOS entry to the address list here.
+ * For now, let's just skip NetBIOS.
+ * (Can we just kill NetBIOS? Please? :)
+ */
+#if 0 /* XXX Just kill NetBIOS? */
+ /*
* If regular IP name lookup failed, try NetBIOS,
* but only if given a valid NetBIOS name and if
* NetBIOS name lookup is enabled.
*/
if (nbc->nb_flags & NBCF_NS_ENABLE) {
- gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+ int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
if (gaierr2 == 0) {
if (res->ai_canonname)
strlcpy(ctx->ct_srvname,
@@ -176,6 +186,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
return (0);
}
}
+#endif
/*
* Return the original error from getaddrinfo
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index 8b56fdaf18..b19f1f3f0f 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,22 +60,21 @@
#include "private.h"
/*
- * Be the reader thread for this VC.
+ * The user agent (smbiod) calls smb_iod_connect for the first
+ * connection to some server, and if that succeeds, will start a
+ * thread running this function, passing the smb_ctx_t
+ *
+ * This thread now enters the driver and stays there, reading
+ * network responses as long as the connection is alive.
*/
int
smb_iod_work(smb_ctx_t *ctx)
{
smbioc_ssn_work_t *work = &ctx->ct_work;
- int vcst, err = 0;
+ int err = 0;
DPRINT("server: %s", ctx->ct_srvname);
- /* Caller should have opened these */
- if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
- err = EINVAL;
- goto out;
- }
-
/*
* This is the reader / reconnect loop.
*
@@ -84,20 +84,22 @@ smb_iod_work(smb_ctx_t *ctx)
*
* XXX: Add some syslog calls in here?
*/
- vcst = SMBIOD_ST_VCACTIVE;
for (;;) {
- switch (vcst) {
+ DPRINT("state: %s",
+ smb_iod_state_name(work->wk_out_state));
+
+ switch (work->wk_out_state) {
case SMBIOD_ST_IDLE:
/*
* Wait for driver requests to arrive
* for this VC, then return here.
* Next state is normally RECONNECT.
*/
- DPRINT("state: idle");
+ DPRINT("Call _ioc_idle...");
if (nsmb_ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_IDLE, &vcst) == -1) {
+ SMBIOC_IOD_IDLE, work) == -1) {
err = errno;
DPRINT("ioc_idle: err %d", err);
goto out;
@@ -105,13 +107,11 @@ smb_iod_work(smb_ctx_t *ctx)
continue;
case SMBIOD_ST_RECONNECT:
- DPRINT("state: reconnect");
+ DPRINT("Call _iod_connect...");
err = smb_iod_connect(ctx);
- if (err == 0) {
- vcst = SMBIOD_ST_VCACTIVE;
+ if (err == 0)
continue;
- }
- DPRINT("_iod_connect: err %d", err);
+ DPRINT("iod_connect: err %d", err);
/*
* If the error was EAUTH, retry is
* not likely to succeed either, so
@@ -121,60 +121,53 @@ smb_iod_work(smb_ctx_t *ctx)
*/
if (err == EAUTH)
goto out;
- vcst = SMBIOD_ST_RCFAILED;
continue;
case SMBIOD_ST_RCFAILED:
- DPRINT("state: rcfailed");
/*
* Reconnect failed. Kill off any
* requests waiting in the driver,
* then get ready to try again.
* Next state is normally IDLE.
*/
+ DPRINT("Call _iod_rcfail...");
if (nsmb_ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+ SMBIOC_IOD_RCFAIL, work) == -1) {
err = errno;
- DPRINT("ioc_rcfail: err %d", err);
+ DPRINT("iod_rcfail: err %d", err);
goto out;
}
continue;
- case SMBIOD_ST_VCACTIVE:
- DPRINT("state: active");
+ case SMBIOD_ST_AUTHOK:
+ /*
+ * This is where we enter the driver and
+ * stay there. While the connection is up
+ * the VC will have SMBIOD_ST_VCACTIVE
+ */
+ DPRINT("Call _iod_work...");
if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_WORK, work) == -1) {
err = errno;
- DPRINT("ioc_work: err %d", err);
+ DPRINT("iod_work: err %d", err);
goto out;
}
- vcst = work->wk_out_state;
- /*
- * Go ahead and close the transport now,
- * rather than wait until reconnect to
- * this server.
- */
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
continue;
case SMBIOD_ST_DEAD:
- DPRINT("state: dead");
err = 0;
goto out;
default:
- DPRINT("state: BAD(%d)", vcst);
+ DPRINT("Unexpected state: %d (%s)",
+ work->wk_out_state,
+ smb_iod_state_name(work->wk_out_state));
err = EFAULT;
goto out;
}
}
out:
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_dev_fd != -1) {
nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c
index 208ec6d0a4..421a0bda37 100644
--- a/usr/src/lib/libsmbfs/smb/krb5ssp.c
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c
@@ -32,6 +32,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -90,7 +91,7 @@ extern MECH_OID g_stcMechOIDList [];
typedef struct krb5ssp_state {
/* Filled in by krb5ssp_init_client */
krb5_context ss_krb5ctx; /* krb5 context (ptr) */
- krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
+ krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
krb5_principal ss_krb5clp; /* client principal (ptr) */
/* Filled in by krb5ssp_get_tkt */
krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */
@@ -107,8 +108,8 @@ krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
ulong_t len;
ulong_t bloblen = tktlen;
uchar_t krbapreq[2] = { KRB_AP_REQ, 0 };
- uchar_t *blob = NULL; /* result */
- uchar_t *b;
+ uchar_t *blob = NULL; /* result */
+ uchar_t *b;
bloblen += sizeof (krbapreq);
bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
@@ -168,7 +169,7 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
krb5_data outdata = {0};
krb5_error_code kerr = 0;
const char *fn = NULL;
- uchar_t *tkt;
+ uchar_t *tkt;
/* Should have these from krb5ssp_init_client. */
if (kctx == NULL || kcc == NULL) {
@@ -252,9 +253,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
- uchar_t *tkt = NULL;
+ uchar_t *tkt = NULL;
ulong_t tktlen;
- uchar_t *gtok = NULL; /* gssapi token */
+ uchar_t *gtok = NULL; /* gssapi token */
ulong_t gtoklen; /* gssapi token length */
char *prin = ctx->ct_srvname;
@@ -268,9 +269,6 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0)
goto out;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN)
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-
out:
if (gtok)
free(gtok);
@@ -383,7 +381,7 @@ krb5ssp_final(struct ssp_ctx *sp)
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
krb5_keyblock *ssn_key = NULL;
- int err, len;
+ int err;
/*
* Save the session key, used for SMB signing
@@ -398,35 +396,32 @@ krb5ssp_final(struct ssp_ctx *sp)
err = EAUTH;
goto out;
}
- memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
- if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
- len = SMBIOC_HASH_SZ;
- memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+ /* Sanity check the length */
+ if (ssn_key->length > 1024) {
+ DPRINT("session key too long");
+ err = EAUTH;
+ goto out;
+ }
/*
- * Set the MAC key on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = ssn_key->length;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ssn_key->contents,
- ctx->ct_mackeylen);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
+ }
+ ctx->ct_ssnkey_buf = malloc(ssn_key->length);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
}
+ ctx->ct_ssnkey_len = ssn_key->length;
+ memcpy(ctx->ct_ssnkey_buf, ssn_key->contents, ctx->ct_ssnkey_len);
err = 0;
out:
- if (ssn_key)
+ if (ssn_key != NULL)
krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
return (err);
@@ -508,7 +503,7 @@ krb5ssp_init_client(struct ssp_ctx *sp)
krb5ssp_state_t *ss;
krb5_error_code kerr;
krb5_context kctx = NULL;
- krb5_ccache kcc = NULL;
+ krb5_ccache kcc = NULL;
krb5_principal kprin = NULL;
if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 8d658ab937..73ab2504f5 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -19,7 +19,7 @@
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -127,16 +127,6 @@ SYMBOL_VERSION SUNWprivate {
smb_simplecrypt;
smb_simpledecrypt;
smb_strerror;
-#
-# Functions to support the Remote Access Protocol (RAP)
- smb_rap_create;
- smb_rap_done;
- smb_rap_error;
- smb_rap_getNparam;
- smb_rap_request;
- smb_rap_setNparam;
- smb_rap_setPparam;
-#
smb_verbose { FLAGS = NODIRECT }; # data
#
# Functions to support Access Control Lists (ACLs)
diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c
deleted file mode 100644
index 319e250296..0000000000
--- a/usr/src/lib/libsmbfs/smb/nb_ssn.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * NetBIOS session service functions
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-
-#include <netsmb/netbios.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/mchain.h>
-
-#include "private.h"
-#include "charsets.h"
-
-static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
-static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
-static int nb_ssn_pollin(struct smb_ctx *, int);
-
-/*
- * Send a data message.
- */
-int
-smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
-}
-
-/*
- * Send a NetBIOS message, after
- * prepending the 4-byte header.
- */
-static int
-nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
- int mtype, int mlen)
-{
- mbuf_t *m;
- uint32_t hdr, hdrbuf;
- int err;
-
- m = mbp->mb_top;
- if (m == NULL)
- return (EINVAL);
-
- /*
- * Prepend the NetBIOS header.
- * Our mbufs leave space for this.
- */
- hdr = (mtype << 24) | mlen;
- hdrbuf = htonl(hdr);
- m->m_data -= 4;
- m->m_len += 4;
- bcopy(&hdrbuf, m->m_data, 4);
-
- /*
- * Get contiguous data (so TCP won't fragment)
- * Note: replaces mb_top.
- */
- err = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (err)
- return (err);
- m = mbp->mb_top;
-
- /*
- * Send it.
- */
- if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
- return (err);
- }
-
- return (0);
-}
-
-/*
- * Receive a data message. Discard anything else.
- * Caller must deal with EAGAIN, EINTR.
- */
-int
-smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- int err, mtype, mlen;
- err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
- if (err)
- return (err);
- if (mtype != NB_SSN_MESSAGE) {
- DPRINT("discard type 0x%x", mtype);
- mb_done(mbp);
- return (EAGAIN);
- }
- if (mlen == 0) {
- DPRINT("zero length");
- mb_done(mbp);
- return (EAGAIN);
- }
-
- return (0);
-}
-
-/*
- * Receive a NetBIOS message, any type.
- * Give caller type and length.
- */
-static int
-nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
- int *mtype, int *mlen)
-{
- char *buf;
- uint32_t hdr, hdrbuf;
- int cnt, len, err, moreflag;
- int fd = ctx->ct_tran_fd;
- int tmo = smb_recv_timeout * 1000;
-
- /*
- * Start by getting the header
- * (four bytes)
- */
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- moreflag = 0;
- cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
-
- if (cnt != sizeof (hdrbuf)) {
- DPRINT("hdr cnt %d", cnt);
- return (EPROTO);
- }
-
- /*
- * Decode the header, get the length.
- */
- hdr = ntohl(hdrbuf);
- *mtype = (hdr >> 24) & 0xff;
- *mlen = hdr & 0xffffff;
-
- if (mlen == 0)
- return (0);
-
- /*
- * Get a message buffer, read the payload
- */
- if ((err = mb_init_sz(mb, *mlen)) != 0)
- return (err);
- buf = mb->mb_top->m_data;
- len = *mlen;
- while (len > 0) {
- if (!moreflag) {
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- }
-
- moreflag = 0;
- cnt = t_rcv(fd, buf, len, &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
- buf += cnt;
- len -= cnt;
- }
- mb->mb_top->m_len = *mlen;
- mb->mb_count = *mlen;
-
- return (0);
-}
-
-int
-get_xti_err(int fd)
-{
- int look;
- if (t_errno == TSYSERR)
- return (errno);
-
- if (t_errno == TLOOK) {
- look = t_look(fd);
- switch (look) {
- case T_DISCONNECT:
- (void) t_rcvdis(fd, NULL);
- (void) t_snddis(fd, NULL);
- return (ECONNRESET);
- case T_ORDREL:
- /* Received orderly release indication */
- (void) t_rcvrel(fd);
- /* Send orderly release indicator */
- (void) t_sndrel(fd);
- return (ECONNRESET);
- }
- }
- return (EPROTO);
-}
-
-/*
- * Wait for data we can receive.
- * Timeout is mSec., as for poll(2)
- */
-static int
-nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
-{
- struct pollfd pfd[1];
- int cnt, err;
-
- pfd[0].fd = ctx->ct_tran_fd;
- pfd[0].events = POLLIN | POLLPRI;
- pfd[0].revents = 0;
- cnt = poll(pfd, 1, tmo);
- switch (cnt) {
- case 0:
- err = ETIME;
- break;
- case -1:
- err = errno;
- break;
- default:
- err = 0;
- break;
- }
- return (err);
-}
-
-/*
- * Send a NetBIOS session request and
- * wait for the response.
- */
-int
-nb_ssn_request(struct smb_ctx *ctx, char *srvname)
-{
- struct mbdata req, res;
- struct nb_name lcl, srv;
- int err, mtype, mlen;
- char *ucwks;
-
- bzero(&req, sizeof (req));
- bzero(&res, sizeof (res));
-
- if ((err = mb_init(&req)) != 0)
- goto errout;
-
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucwks == NULL) {
- err = ENOMEM;
- goto errout;
- }
-
- /* Local NB name. */
- snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
- lcl.nn_type = NBT_WKSTA;
- lcl.nn_scope = ctx->ct_nb->nb_scope;
-
- /* Server NB name */
- snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
- srv.nn_type = NBT_SERVER;
- srv.nn_scope = ctx->ct_nb->nb_scope;
-
- /*
- * Build the request. Header is prepended later.
- */
- if ((err = nb_name_encode(&req, &srv)) != 0)
- goto errout;
- if ((err = nb_name_encode(&req, &lcl)) != 0)
- goto errout;
-
- /*
- * Send it, wait for the reply.
- */
- err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
- if (err) {
- DPRINT("send, err %d", err);
- goto errout;
- }
- err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
- if (err) {
- DPRINT("recv, err %d", err);
- goto errout;
- }
-
- if (mtype != NB_SSN_POSRESP) {
- DPRINT("recv, mtype 0x%x", mtype);
- err = ECONNREFUSED;
- goto errout;
- }
-
- return (0);
-
-errout:
- mb_done(&res);
- mb_done(&req);
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
deleted file mode 100644
index 770b742c44..0000000000
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Negotiate Protocol, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#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 "smb_crypt.h"
-#include "private.h"
-
-/*
- * SMB dialects that we know about.
- */
-struct smb_dialect {
- int d_id;
- const char *d_name;
-};
-static struct smb_dialect smb_dialects[] = {
- {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
- {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
- {-1, NULL}
-};
-
-#define SMB_DIALECT_MAX \
- (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
-
-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;
-
-/*
- * SMB Negotiate Protocol
- * Based on code from the driver: smb_smb.c
- *
- * If using Extended Security, oblob (output)
- * will hold the initial security "hint".
- */
-int
-smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
-{
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp;
- struct mbdata *mbp;
- struct smb_dialect *dp;
- int err, len;
- uint8_t wc, eklen;
- uint16_t dindex, bc;
- int will_sign = 0;
-
- /*
- * Initialize: vc_hflags and vc_hflags2.
- * Note: ctx->ct_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.
- */
- ctx->ct_hflags =
- SMB_FLAGS_CASELESS |
- SMB_FLAGS_CANONICAL_PATHNAMES;
- ctx->ct_hflags2 =
- SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_KNOWS_EAS |
- /* SMB_FLAGS2_IS_LONG_NAME |? */
- /* EXT_SEC (see below) */
- SMB_FLAGS2_ERR_STATUS |
- SMB_FLAGS2_UNICODE;
-
- /*
- * Sould we offer extended security?
- * We'll turn this back off below if
- * the server doesn't support it.
- */
- if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
- ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
- /*
- * The initial UID needs to be zero,
- * or Windows XP says "bad user".
- * The initial TID is all ones, but
- * we don't use it or store it here
- * because the driver handles that.
- */
- is->is_smbuid = 0;
-
- /*
- * In case we're reconnecting,
- * free previous stuff.
- */
- ctx->ct_mac_seqno = 0;
- if (ctx->ct_mackey != NULL) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
- ctx->ct_mackeylen = 0;
- }
-
- sv = &ctx->ct_sopt;
- bzero(sv, sizeof (struct smb_sopt));
-
- err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
- if (err)
- return (err);
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- mb_put_uint8(mbp, 0); /* word count */
- smb_rq_bstart(rqp);
- for (dp = smb_dialects; dp->d_id != -1; dp++) {
- mb_put_uint8(mbp, SMB_DT_DIALECT);
- mb_put_astring(mbp, dp->d_name);
- }
- smb_rq_bend(rqp);
-
- /*
- * This does the OTW call
- */
- err = smb_rq_internal(ctx, rqp);
- if (err) {
- DPRINT("call failed, err %d", err);
- goto errout;
- }
- if (rqp->rq_status != 0) {
- DPRINT("nt status 0x%x", rqp->rq_status);
- err = EBADRPC;
- goto errout;
- }
-
- /*
- * Decode the response
- *
- * Comments to right show names as described in
- * The Microsoft SMB Protocol spec. [MS-SMB]
- * section 2.2.3
- */
- mbp = &rqp->rq_rp;
- (void) md_get_uint8(mbp, &wc);
- err = md_get_uint16le(mbp, &dindex);
- if (err || dindex > SMB_DIALECT_MAX) {
- DPRINT("err %d dindex %d", err, (int)dindex);
- goto errout;
- }
- dp = smb_dialects + dindex;
- sv->sv_proto = dp->d_id;
- DPRINT("Dialect %s", dp->d_name);
- if (dp->d_id < SMB_DIALECT_NTLM0_12) {
- /* XXX: User-visible warning too? */
- DPRINT("old dialect %s", dp->d_name);
- goto errout;
- }
- if (wc != 17) {
- DPRINT("bad wc %d", (int)wc);
- goto errout;
- }
- md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */
- md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */
- md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */
- md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */
- md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */
- md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */
- md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */
- md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
- md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
- md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */
- err = md_get_uint16le(mbp, &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 = 1;
- } else if (sv->sv_sm & SMB_SM_SIGS) {
- /*
- * Server enables signing (client's option).
- * If enabled locally, do signing.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
- will_sign = 1;
- /* else not signing. */
- } else {
- /*
- * Server does not support signing.
- * If we "require" it, bail now.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
- DPRINT("Client requires signing "
- "but server has it disabled.");
- err = EBADRPC;
- goto errout;
- }
- }
-
- if (will_sign) {
- ctx->ct_vcflags |= SMBV_WILL_SIGN;
- }
- DPRINT("Security signatures: %d", will_sign);
-
- /* See comment above re. FLAGS2_UNICODE */
- if (sv->sv_caps & SMB_CAP_UNICODE)
- ctx->ct_vcflags |= SMBV_UNICODE;
- else
- ctx->ct_hflags2 &= ~SMB_FLAGS2_UNICODE;
-
- if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
- /*
- * They don't do NT error codes.
- *
- * If we send requests with
- * SMB_FLAGS2_ERR_STATUS set in
- * Flags2, Windows 98, at least,
- * appears to send replies with that
- * bit set even though it sends back
- * DOS error codes. (They probably
- * just use the request header as
- * a template for the reply header,
- * and don't bother clearing that bit.)
- *
- * Therefore, we clear that bit in
- * our vc_hflags2 field.
- */
- ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
- }
- if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
- sv->sv_maxtx < 4096 &&
- (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
- ctx->ct_vcflags |= SMBV_WIN95;
- DPRINT("Win95 detected");
- }
-
- /*
- * 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) {
- struct mbuf *m;
- DPRINT("Ext.Security: yes");
-
- /*
- * Skip the server GUID.
- */
- err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
- if (err)
- goto errout;
- /*
- * Remainder is the security blob.
- * Note: eklen "must be ignored" [MS-SMB]
- */
- len = (int)bc - SMB_GUIDLEN;
- if (len < 0)
- goto errout;
-
- /*
- * Get the (optional) SPNEGO "hint".
- */
- err = md_get_mbuf(mbp, len, &m);
- if (err)
- goto errout;
- mb_initm(oblob, m);
- oblob->mb_count = len;
- } else {
- DPRINT("Ext.Security: no");
- ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
-
- /*
- * Save the "Encryption Key" (the challenge).
- *
- * Sanity check: make sure the sec. blob length
- * isn't bigger than the byte count.
- */
- if (bc < eklen || eklen < NTLM_CHAL_SZ) {
- err = EBADRPC;
- goto errout;
- }
- err = md_get_mem(mbp, ctx->ct_srv_chal,
- NTLM_CHAL_SZ, MB_MSYSTEM);
- /*
- * Server domain follows (ignored)
- * Note: NOT aligned(2) - unusual!
- */
- }
-
- smb_rq_done(rqp);
-
- /*
- * 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.
- */
- is->is_txmax = sv->sv_maxtx;
- if (is->is_txmax > 0x8000)
- is->is_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.
- */
- len = is->is_txmax - 68;
- len &= 0xFE00;
- /* XXX: Not sure yet which of these to keep. */
- is->is_rwmax = len;
- is->is_rxmax = len;
- is->is_wxmax = len;
-
- /*
- * Most of the "capability" bits we offer in session setup
- * are just copied from those offered by the server.
- */
- ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask;
-
- /* Get the client nonce. */
- (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
-
- return (0);
-
-errout:
- smb_rq_done(rqp);
- if (err == 0)
- err = EBADRPC;
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index 9f08a2eaca..44b26f54e6 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -184,7 +184,8 @@ ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
*/
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -229,7 +230,7 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -245,7 +246,8 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
*/
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
MD5_CTX context;
uchar_t challenges[2 * NTLM_CHAL_SZ];
@@ -299,7 +301,7 @@ ntlm_put_v1x_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -477,7 +479,8 @@ ntlm_v2_session_key(uchar_t *ssn_key,
*/
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -547,7 +550,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
/*
* Compute the session key
*/
- ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+ ntlm_v2_session_key(ssn_key, v2hash, ntresp);
out:
if (err) {
@@ -650,37 +653,13 @@ out:
}
/*
- * Build the MAC key (for SMB signing)
- */
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
-{
- struct mbuf *m;
- size_t len;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- m = ntresp_mbp->mb_top;
- len = NTLM_HASH_SZ + m->m_len;
- if ((p = malloc(len)) == NULL)
- return (ENOMEM);
- ctx->ct_mackeylen = len;
- ctx->ct_mackey = p;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
- return (0);
-}
-
-/*
* Helper for ntlmssp_put_type3 - Build the "key exchange key"
* used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
* HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
*/
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey)
{
uchar_t data[NTLM_HASH_SZ];
uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
@@ -690,6 +669,6 @@ ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
/* HMAC_MD5(SessionBaseKey, concat(...)) */
- HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
+ HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
data, NTLM_HASH_SZ);
}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
index 447033b516..d0c093689a 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,7 +22,8 @@
/*
* 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.
*/
#ifndef _NTLM_H
@@ -38,7 +39,7 @@
* NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
* NTLM_CHAL_SZ: 8 bytes (see smb_lib.h)
*/
-#define NTLM_V1_RESP_SZ 24 /* response size */
+#define NTLM_V1_RESP_SZ 24 /* response size */
#define NAMETYPE_EOL 0x0000 /* end of list of names */
#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */
@@ -57,20 +58,21 @@ ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
-
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey);
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey);
#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index f39fa594ec..5ae583114d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -67,13 +67,14 @@
#include "ntlmssp.h"
/* A shorter alias for a crazy long name from [MS-NLMP] */
-#define NTLMSSP_NEGOTIATE_NTLM2 \
+#define NTLMSSP_NEGOTIATE_ESS \
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
typedef struct ntlmssp_state {
uint32_t ss_flags;
char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_ssnkey[NTLM_HASH_SZ];
uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
@@ -90,8 +91,7 @@ struct sec_buf {
static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
static int
-ntlm_rand_ssn_key(struct smb_ctx *ctx,
- ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
+ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
/*
* Get a "security buffer" (header part)
@@ -249,16 +249,14 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
NTLMSSP_NEGOTIATE_SEAL |
/* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
- NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_ESS |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
+ if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
@@ -447,15 +445,20 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
/*
* We're setting up a NULL session, meaning
* the lm_mbc, nt_mbc parts remain empty.
- * Let's add the "anon" flag (hint).
- * As there is no session key, disable the
- * fancy session key stuff.
+ * Let's add the "anon" flag (hint), and
+ * as we have no OWF hashes, we can't use
+ * "extended session security" (_ESS).
+ * The SessionBaseKey is all zeros, so
+ * the KeyExchangeKey is too. Otherwise
+ * this is like NTLMv2/LMv2
*/
- hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
- ssp_st->ss_flags &= ~(
- NTLMSSP_NEGOTIATE_NTLM2 |
- NTLMSSP_NEGOTIATE_KEY_EXCH);
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
+ hdr.h_flags = ssp_st->ss_flags;
err = 0;
+ /* KeyExchangeKey = SessionBaseKey = (zeros) */
+ memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
+ memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
} else if (ctx->ct_authflags & SMB_AT_NTLM2) {
/*
* Doing NTLMv2/LMv2
@@ -465,47 +468,49 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
-
- } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* KeyExchangeKey = SessionBaseKey (v2) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
+ } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
/*
* Doing NTLM ("v1x") which is NTLM with
* "Extended Session Security"
*/
err = ntlm_put_v1x_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* Compute the "Key exchange key". */
- ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
+ /*
+ * "v1x computes the KeyExchangeKey from both the
+ * server and client nonce and (v1) SessionBaseKey.
+ */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
+ ssp_st->ss_kxkey);
} else {
/*
* Doing plain old NTLM (and LM if enabled)
*/
err = ntlm_put_v1_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ /* KeyExchangeKey = SessionBaseKey (v1) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
}
/*
- * Compute the "Exported Session Key" and (possibly)
- * the "Encrypted Random Sesion Key".
- * [MS-NLMP 3.1.5.1.2]
+ * Compute the "ExportedSessionKey" and (possibly) the
+ * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
*/
if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
+ err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
if (err)
goto out;
} else {
/* ExportedSessionKey is the KeyExchangeKey */
- memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
/* EncryptedRandomSessionKey remains NULL */
}
@@ -590,7 +595,6 @@ out:
*/
static int
ntlm_rand_ssn_key(
- struct smb_ctx *ctx,
ntlmssp_state_t *ssp_st,
struct mbdata *ek_mbp)
{
@@ -603,12 +607,12 @@ ntlm_rand_ssn_key(
encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
/* Set "ExportedSessionKey to NONCE(16) */
- (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
+ (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
/* Set "EncryptedRandomSessionKey" to RC4(...) */
err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
ssp_st->ss_kxkey, NTLM_HASH_SZ,
- ctx->ct_ssn_key, NTLM_HASH_SZ);
+ ssp_st->ss_ssnkey, NTLM_HASH_SZ);
return (err);
}
@@ -617,34 +621,29 @@ ntlm_rand_ssn_key(
* ntlmssp_final
*
* Called after successful authentication.
- * Setup the MAC key for signing.
+ * Save the session key.
*/
int
ntlmssp_final(struct ssp_ctx *sp)
{
struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
int err = 0;
/*
- * MAC_key is just the session key, but
- * Only on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = NTLM_HASH_SZ;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
+ ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ ctx->ct_ssnkey_len = NTLM_HASH_SZ;
+ memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
out:
return (err);
@@ -728,13 +727,17 @@ int
ntlmssp_init_client(struct ssp_ctx *sp)
{
ntlmssp_state_t *ssp_st;
+ smb_ctx_t *ctx = sp->smb_ctx;
- if ((sp->smb_ctx->ct_authflags &
+ if ((ctx->ct_authflags &
(SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
return (EINVAL);
}
+ /* Get the client nonce. */
+ (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+
ssp_st = calloc(1, sizeof (*ssp_st));
if (ssp_st == NULL)
return (ENOMEM);
diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h
index febca40126..d877cafa1d 100644
--- a/usr/src/lib/libsmbfs/smb/private.h
+++ b/usr/src/lib/libsmbfs/smb/private.h
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _PRIVATE_H
@@ -61,60 +62,6 @@ extern void dprint(const char *, const char *, ...)
#endif
/*
- * Flags bits in ct_vcflags (copied from smb_conn.h)
- * Pass these to the driver?
- */
-#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
-#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
-#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
-#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
-#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
-#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
-
-/*
- * request handling structures
- */
-struct smb_rq {
- struct smb_ctx *rq_ctx;
- struct mbdata rq_rq;
- struct mbdata rq_rp;
- int rq_rpbufsz;
- uint8_t rq_cmd;
- uint8_t rq_hflags;
- uint16_t rq_hflags2;
- uint32_t rq_status;
- uint16_t rq_uid;
- uint16_t rq_tid;
- uint16_t rq_mid;
- uint32_t rq_seqno;
- /* See rq_[bw]{start,end} functions */
- char *rq_wcntp;
- int rq_wcbase;
- char *rq_bcntp;
- int rq_bcbase;
-};
-typedef struct smb_rq smb_rq_t;
-
-#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq)
-#define smb_rq_getreply(rqp) (&(rqp)->rq_rp)
-
-int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
-void smb_rq_done(struct smb_rq *);
-void smb_rq_bstart(struct smb_rq *);
-void smb_rq_bend(struct smb_rq *);
-void smb_rq_wstart(struct smb_rq *);
-void smb_rq_wend(struct smb_rq *);
-int smb_rq_simple(struct smb_rq *);
-int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_internal(struct smb_ctx *, struct smb_rq *);
-void smb_rq_sign(struct smb_rq *);
-int smb_rq_verify(struct smb_rq *);
-int smb_t2_request(int, int, uint16_t *, const char *,
- int, void *, int, void *, int *, void *, int *, void *, int *);
-
-/*
* This library extends the mchain.h function set a little.
*/
int m_getm(struct mbuf *, int, struct mbuf **);
@@ -174,16 +121,7 @@ int smb_ctx_getaddr(struct smb_ctx *ctx);
int smb_ctx_gethandle(struct smb_ctx *ctx);
int smb_iod_start(struct smb_ctx *);
-
-int smb_ssn_send(struct smb_ctx *, struct mbdata *);
-int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
-
-int smb_negprot(struct smb_ctx *, struct mbdata *);
-
-int smb_ssnsetup_null(struct smb_ctx *);
-int smb_ssnsetup_ntlm1(struct smb_ctx *);
-int smb_ssnsetup_ntlm2(struct smb_ctx *);
-int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+const char *smb_iod_state_name(enum smbiod_state st);
void smb_time_local2server(struct timeval *, int, long *);
void smb_time_server2local(ulong_t, int, struct timeval *);
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
deleted file mode 100644
index 546ee46f05..0000000000
--- a/usr/src/lib/libsmbfs/smb/rap.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
- *
- * This is very simple implementation of RAP protocol.
- */
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/isa_defs.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <libintl.h>
-#include <sysexits.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-#include "private.h"
-
-static int
-smb_rap_parserqparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'L':
- case 'T':
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- len = 4;
- break;
- case 'b':
- case 'F':
- len = 1;
- break;
- case 'r':
- case 's':
- len = 0;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len = 0;
-
- switch (*s++) {
- case 'e':
- case 'h':
- len = 2;
- break;
- case 'i':
- len = 4;
- break;
- case 'g':
- len = 1;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpdata(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'B':
- len = 1;
- break;
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- case 'z':
- len = 4;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
-{
- int len = strlen(value) + 1;
-
- bcopy(value, rap->r_npbuf, len);
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-/*
- * Marshal RAP request parameters.
- * Note: value is in host order.
- */
-static int
-smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
-{
- int len = 0;
- uint_t uv = (uint_t)value;
- uint32_t *lp;
- uint16_t *sp;
- char *p;
-
- switch (ptype) {
- case 'L':
- case 'W':
- /* LINTED */
- sp = (uint16_t *)rap->r_npbuf;
- *sp = htoles(uv);
- len = sizeof (*sp);
- break;
- case 'D':
- /* LINTED */
- lp = (uint32_t *)rap->r_npbuf;
- *lp = htolel(uv);
- len = sizeof (*lp);
- break;
- case 'b':
- p = rap->r_npbuf;
- memset(p, uv, plen);
- len = plen;
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-int
-smb_rap_create(int fn, const char *param, const char *data,
- struct smb_rap **rapp)
-{
- struct smb_rap *rap;
- char *p;
- int plen = 0, len = 0;
-
- rap = malloc(sizeof (*rap));
- if (rap == NULL)
- return (ENOMEM);
- bzero(rap, sizeof (*rap));
- p = rap->r_sparam = rap->r_nparam = strdup(param);
- rap->r_sdata = rap->r_ndata = strdup(data);
-
- /*
- * Calculate length of request parameter block
- */
- len = 2 + strlen(param) + 1 + strlen(data) + 1;
- while (*p) {
- if (smb_rap_parserqparam(p, &p, &plen) != 0)
- break;
- len += plen;
- }
- rap->r_pbuf = rap->r_npbuf = malloc(len);
- if (rap->r_pbuf == NULL)
- return (ENOMEM);
- (void) smb_rap_rqparam(rap, 'W', 1, fn);
- (void) smb_rap_rqparam_z(rap, rap->r_sparam);
- (void) smb_rap_rqparam_z(rap, rap->r_sdata);
- *rapp = rap;
- return (0);
-}
-
-void
-smb_rap_done(struct smb_rap *rap)
-{
- if (rap->r_sparam)
- free(rap->r_sparam);
- if (rap->r_sdata)
- free(rap->r_sdata);
- if (rap->r_pbuf)
- free(rap->r_pbuf);
-#ifdef NOTYETDEFINED
- if (rap->r_npbuf)
- free(rap->r_npbuf);
- if (rap->r_dbuf)
- free(rap->r_dbuf);
- if (rap->r_rcvbuf)
- free(rap->r_rcvbuf);
-#endif
- free(rap);
-}
-
-int
-smb_rap_setNparam(struct smb_rap *rap, int value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'L':
- rap->r_rcvbuflen = value;
- /* FALLTHROUGH */
- case 'W':
- case 'D':
- case 'b':
- error = smb_rap_rqparam(rap, ptype, plen, value);
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_setPparam(struct smb_rap *rap, void *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'r':
- rap->r_rcvbuf = value;
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_getNparam(struct smb_rap *rap, long *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
- uint16_t *te;
-
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'h':
- /* LINTED */
- te = (uint16_t *)rap->r_npbuf;
- *value = letohs(*te);
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += plen;
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
-{
- uint16_t *rp, conv, *tmp;
- uint32_t *p32;
- char *dp, *p = rap->r_nparam;
- char ptype;
- int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
-
- rdatacnt = rap->r_rcvbuflen;
- rparamcnt = rap->r_plen;
- error = smb_t2_request(ctx->ct_dev_fd,
- 0, NULL, "\\PIPE\\LANMAN",
- rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
- 0, NULL, /* int tdatacnt, void *tdata */
- &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
- &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
- &buffer_oflow);
- if (error)
- return (error);
-
- /* LINTED */
- rp = (uint16_t *)rap->r_pbuf;
-
- /*
- * Note: First is a "LanMan API" error code.
- * See: usr/src/uts/common/smbsrv/lmerr.h
- */
- if (rparamcnt < 2)
- return (EBADRPC);
- rap->r_result = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- if (rap->r_result != 0) {
- /*
- * Could also return zero and let the caller
- * come get r_result via smb_rap_error(),
- * but in case they dont...
- */
- return (rap->r_result | SMB_RAP_ERROR);
- }
-
- if (rparamcnt < 2)
- return (EBADRPC);
- conv = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- rap->r_npbuf = (char *)rp;
- rap->r_entries = entries = 0;
- /* Save the returned data length */
- rap->r_rcvbuflen = rdatacnt;
- done = 0;
-
- while (!done && *p) {
- ptype = *p;
- switch (ptype) {
- case 'e':
- if (rparamcnt < 2)
- return (EBADRPC);
- /* LINTED */
- tmp = (uint16_t *)rap->r_npbuf;
- rap->r_entries = entries = letohs(*tmp);
- rap->r_npbuf += 2;
- rparamcnt -= 2;
- p++;
- break;
- default:
- done = 1;
- }
-#if 0 /* commented out in Darwin. Why? */
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply parameter mismatch %s"), 0, p);
- return (EBADRPC);
- }
-#endif
- }
- rap->r_nparam = p;
- /*
- * In general, unpacking entries we may need to relocate
- * entries for proper aligning. For now use them as is.
- */
- dp = rap->r_rcvbuf;
- while (entries--) {
- p = rap->r_sdata;
- while (*p) {
- ptype = *p;
- error = smb_rap_parserpdata(p, &p, &dlen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply data mismatch %s"), 0, p);
- return (EBADRPC);
- }
- if (rdatacnt < dlen)
- return (EBADRPC);
- switch (ptype) {
- case 'z':
- /* LINTED */
- p32 = (uint32_t *)dp;
- *p32 = (letohl(*p32) & 0xffff) - conv;
- break;
- }
- dp += dlen;
- rdatacnt -= dlen;
- }
- }
- return (error);
-}
-
-int
-smb_rap_error(struct smb_rap *rap, int error)
-{
- if (error)
- return (error);
- if (rap->r_result == 0)
- return (0);
- return (rap->r_result | SMB_RAP_ERROR);
-}
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
deleted file mode 100644
index f6004dfa06..0000000000
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
- */
-
-/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <libintl.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include "private.h"
-
-#define MIN_REPLY_SIZE 4096
-
-static uint32_t smb_map_doserr(uint8_t, uint16_t);
-
-/*
- * Create and initialize a request structure, for either an
- * "internal" request (one that does not use the driver) or
- * a regular "driver" request, that uses driver ioctls.
- *
- * The two kinds are built a little differently:
- * Driver requests are composed starting with the
- * first word of the "variable word vector" section.
- * The driver prepends the SMB header and word count.
- * The driver also needs an output buffer to receive
- * the response, filled in via copyout in the ioctl.
- *
- * Internal requests are composed entirely in this library.
- * Space for the SMB header is reserved here, and later
- * filled in by smb_rq_internal before the send/receive.
- */
-int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
-{
- struct smb_rq *rqp;
-
- rqp = malloc(sizeof (*rqp));
- if (rqp == NULL)
- goto errout;
- bzero(rqp, sizeof (*rqp));
- rqp->rq_cmd = cmd;
- rqp->rq_ctx = ctx;
-
- /*
- * Setup the request buffer.
- * Do the reply buffer later.
- */
- if (mb_init(&rqp->rq_rq))
- goto errout;
-
- /* Space for the SMB header. (filled in later) */
- mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
-
- /*
- * Copy the ctx flags here, so the caller can
- * update the req flags before the OTW call.
- */
- rqp->rq_hflags = ctx->ct_hflags;
- rqp->rq_hflags2 = ctx->ct_hflags2;
-
- *rqpp = rqp;
- return (0);
-
-errout:
- if (rqp) {
- smb_rq_done(rqp);
- free(rqp);
- }
- return (ENOMEM);
-}
-
-void
-smb_rq_done(struct smb_rq *rqp)
-{
- mb_done(&rqp->rq_rp);
- mb_done(&rqp->rq_rq);
- free(rqp);
-}
-
-/*
- * Reserve space for the word count, which is filled in later by
- * smb_rq_wend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the word count happens to be 8-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_wstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 1, &rqp->rq_wcntp);
- rqp->rq_wcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the word count, in the space reserved by
- * smb_rq_wstart().
- */
-void
-smb_rq_wend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int wcnt;
-
- if (rqp->rq_wcntp == NULL) {
- DPRINT("no wcount ptr\n");
- return;
- }
- wcnt = mbp->mb_count - rqp->rq_wcbase;
- if (wcnt > 0x1ff)
- DPRINT("word count too large (%d)\n", wcnt);
- if (wcnt & 1)
- DPRINT("odd word count\n");
- wcnt >>= 1;
-
- /*
- * Fill in the word count (8-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- */
- *rqp->rq_wcntp = (char)wcnt;
-}
-
-/*
- * Reserve space for the byte count, which is filled in later by
- * smb_rq_bend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the byte count happens to be 16-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_bstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 2, &rqp->rq_bcntp);
- rqp->rq_bcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the byte count, in the space reserved by
- * smb_rq_bstart().
- */
-void
-smb_rq_bend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int bcnt;
-
- if (rqp->rq_bcntp == NULL) {
- DPRINT("no bcount ptr\n");
- return;
- }
- bcnt = mbp->mb_count - rqp->rq_bcbase;
- if (bcnt > 0xffff)
- DPRINT("byte count too large (%d)\n", bcnt);
- /*
- * Fill in the byte count (16-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- *
- * The pointer is char * type due to
- * typical off-by-one alignment.
- */
- rqp->rq_bcntp[0] = bcnt & 0xFF;
- rqp->rq_bcntp[1] = (bcnt >> 8);
-}
-
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
- struct smbioc_rq krq;
- struct mbdata *mbp;
- mbuf_t *m;
- char *data;
- uint32_t len;
- size_t rpbufsz;
- int error;
-
- bzero(&krq, sizeof (krq));
- krq.ioc_cmd = rqp->rq_cmd;
-
- /*
- * Make the SMB request body contiguous,
- * and fill in the ioctl request.
- */
- mbp = smb_rq_getrequest(rqp);
- error = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (error)
- return (error);
-
- data = mtod(mbp->mb_top, char *);
- len = m_totlen(mbp->mb_top);
-
- /*
- * _rq_init left space for the SMB header,
- * which makes mb_count the offset from
- * the beginning of the header (useful).
- * However, in this code path the driver
- * prepends the header, so we skip it.
- */
- krq.ioc_tbufsz = len - SMB_HDRLEN;
- krq.ioc_tbuf = data + SMB_HDRLEN;
-
- /*
- * Setup a buffer to hold the reply,
- * at least MIN_REPLY_SIZE, or larger
- * if the caller increased rq_rpbufsz.
- */
- mbp = smb_rq_getreply(rqp);
- rpbufsz = rqp->rq_rpbufsz;
- if (rpbufsz < MIN_REPLY_SIZE)
- rpbufsz = MIN_REPLY_SIZE;
- if ((error = m_get(rpbufsz, &m)) != 0)
- return (error);
- mb_initm(mbp, m);
- krq.ioc_rbufsz = rpbufsz;
- krq.ioc_rbuf = mtod(m, char *);
-
- /*
- * Call the driver
- */
- if (nsmb_ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
- return (errno);
-
- /*
- * Initialize returned mbdata.
- * SMB header already parsed.
- */
- m->m_len = krq.ioc_rbufsz;
-
- return (0);
-}
-
-
-int
-smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
- const char *name,
- int tparamcnt, void *tparam,
- int tdatacnt, void *tdata,
- int *rparamcnt, void *rparam,
- int *rdatacnt, void *rdata,
- int *buffer_oflow)
-{
- smbioc_t2rq_t *krq;
- int i;
-
- krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
- bzero(krq, sizeof (*krq));
-
- if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
- /* Bogus setup count, or too many setup words */
- return (EINVAL);
- }
- for (i = 0; i < setupcount; i++)
- krq->ioc_setup[i] = setup[i];
- krq->ioc_setupcnt = setupcount;
- strcpy(krq->ioc_name, name);
- krq->ioc_tparamcnt = tparamcnt;
- krq->ioc_tparam = tparam;
- krq->ioc_tdatacnt = tdatacnt;
- krq->ioc_tdata = tdata;
-
- krq->ioc_rparamcnt = *rparamcnt;
- krq->ioc_rdatacnt = *rdatacnt;
- krq->ioc_rparam = rparam;
- krq->ioc_rdata = rdata;
-
- if (nsmb_ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
- return (errno);
- }
-
- *rparamcnt = krq->ioc_rparamcnt;
- *rdatacnt = krq->ioc_rdatacnt;
- *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
- (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
- free(krq);
-
- return (0);
-}
-
-
-/*
- * Do an over-the-wire call without using the nsmb driver.
- * This is all "internal" to this library, and used only
- * for connection setup (negotiate protocol, etc.)
- */
-int
-smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
-{
- static const uint8_t ffsmb[4] = SMB_SIGNATURE;
- struct smb_iods *is = &ctx->ct_iods;
- uint32_t sigbuf[2];
- struct mbdata mbtmp, *mbp;
- int err, save_mlen;
- uint8_t ctmp;
-
- rqp->rq_uid = is->is_smbuid;
- rqp->rq_tid = SMB_TID_UNKNOWN;
- rqp->rq_mid = is->is_next_mid++;
-
- /*
- * Fill in the NBT and SMB headers
- * Using mbtmp so we can rewind without
- * affecting the passed request mbdata.
- */
- bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
- mbp = &mbtmp;
- mbp->mb_cur = mbp->mb_top;
- mbp->mb_pos = mbp->mb_cur->m_data;
- mbp->mb_count = 0;
- /* Have to save and restore m_len */
- save_mlen = mbp->mb_cur->m_len;
- mbp->mb_cur->m_len = 0;
-
- /*
- * rewind done; fill it in
- */
- mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
- mb_put_uint8(mbp, rqp->rq_cmd);
- mb_put_uint32le(mbp, 0); /* status */
- mb_put_uint8(mbp, rqp->rq_hflags);
- mb_put_uint16le(mbp, rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- mb_put_mem(mbp, NULL, 12, MB_MZERO);
- mb_put_uint16le(mbp, rqp->rq_tid);
- mb_put_uint16le(mbp, 0); /* pid_lo */
- mb_put_uint16le(mbp, rqp->rq_uid);
- mb_put_uint16le(mbp, rqp->rq_mid);
-
- /* Restore original m_len */
- mbp->mb_cur->m_len = save_mlen;
-
- /*
- * Sign the message, if flags2 indicates.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
-
- /*
- * Send it, wait for the reply.
- */
- if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
- return (err);
-
- if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
- return (err);
-
- /*
- * Should have an SMB header, at least.
- */
- mbp = &rqp->rq_rp;
- if (mbp->mb_cur->m_len < SMB_HDRLEN) {
- DPRINT("len < 32");
- return (EBADRPC);
- }
-
- /*
- * If the request was signed, validate the
- * signature on the response.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- err = smb_rq_verify(rqp);
- if (err) {
- DPRINT("bad signature");
- return (err);
- }
- }
-
- /*
- * Decode the SMB header.
- */
- md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
- if (0 != bcmp(sigbuf, ffsmb, 4)) {
- DPRINT("not SMB");
- return (EBADRPC);
- }
- md_get_uint8(mbp, &ctmp); /* SMB cmd */
- md_get_uint32le(mbp, &rqp->rq_status);
- md_get_uint8(mbp, &rqp->rq_hflags);
- md_get_uint16le(mbp, &rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
- md_get_uint16le(mbp, &rqp->rq_tid);
- md_get_uint16le(mbp, NULL); /* pid_lo */
- md_get_uint16le(mbp, &rqp->rq_uid);
- md_get_uint16le(mbp, &rqp->rq_mid);
-
- /*
- * Figure out the status return.
- * Caller looks at rq_status.
- */
- if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
- uint16_t serr;
- uint8_t class;
-
- class = rqp->rq_status & 0xff;
- serr = rqp->rq_status >> 16;
- rqp->rq_status = smb_map_doserr(class, serr);
- }
-
- return (0);
-}
-
-/*
- * Map old DOS errors (etc.) to NT status codes.
- * We probably don't need this anymore, since
- * the oldest server we talk to is NT. But if
- * later find we do need this, add support here
- * for the DOS errors we care about.
- */
-static uint32_t
-smb_map_doserr(uint8_t class, uint16_t serr)
-{
- if (class == 0 && serr == 0)
- return (0);
-
- DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
- return (NT_STATUS_UNSUCCESSFUL);
-}
diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c
deleted file mode 100644
index 0e9c826bbd..0000000000
--- a/usr/src/lib/libsmbfs/smb/signing.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Signing support, using libmd
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-
-#include <sys/types.h>
-#include <sys/md5.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-
-#include "private.h"
-
-#define SMBSIGOFF 14 /* SMB signature offset */
-#define SMBSIGLEN 8 /* SMB signature length */
-
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-#ifdef DEBUG
-int nsmb_signing_fudge = 4;
-#endif
-
-/*
- * Compute MD5 digest of packet data, using the stored MAC key.
- *
- * See similar code in the driver:
- * uts/common/fs/smbclnt/netsmb/smb_signing.c
- * and on the server side:
- * uts/common/fs/smbsrv/smb_signing.c
- */
-static int
-smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
- uint32_t seqno, uchar_t *signature)
-{
- MD5_CTX md5;
- uchar_t digest[MD5_DIGEST_LENGTH];
-
- /*
- * This union is a little bit of trickery to:
- * (1) get the sequence number int aligned, and
- * (2) reduce the number of digest calls, at the
- * cost of a copying 32 bytes instead of 8.
- * Both sides of this union are 2+32 bytes.
- */
- union {
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t raw[SMB_HDRLEN]; /* header length (32) */
- } r;
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
- uint32_t sig[2]; /* MAC signature, aligned! */
- uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
- } s;
- } smbhdr;
-
- if (m->m_len < SMB_HDRLEN)
- return (EIO);
- if (ctx->ct_mackey == NULL)
- return (EINVAL);
-
- /*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
- */
- bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
- smbhdr.s.sig[0] = htolel(seqno);
- smbhdr.s.sig[1] = 0;
-
- /*
- * Compute the MAC: MD5(concat(Key, message))
- */
- MD5Init(&md5);
-
- /* Digest the MAC Key */
- MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
-
- /* Digest the (copied) SMB header */
- MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
-
- /* Digest the rest of the first mbuf */
- if (m->m_len > SMB_HDRLEN) {
- MD5Update(&md5, m->m_data + SMB_HDRLEN,
- m->m_len - SMB_HDRLEN);
- }
- m = m->m_next;
-
- /* Digest rest of the SMB message. */
- while (m) {
- MD5Update(&md5, m->m_data, m->m_len);
- m = m->m_next;
- }
-
- /* Final */
- MD5Final(digest, &md5);
-
- /*
- * Finally, store the signature.
- * (first 8 bytes of the digest)
- */
- if (signature)
- bcopy(digest, signature, SMBSIGLEN);
-
- return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-void
-smb_rq_sign(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rq.mb_top;
- uint8_t *sigloc;
- int err;
-
- /*
- * Our mblk allocation ensures this,
- * but just in case...
- */
- if (m->m_len < SMB_HDRLEN)
- return;
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
-
- if (ctx->ct_mackey == NULL) {
- /*
- * Signing is required, but we have no key yet
- * fill in with the magic fake signing value.
- * This happens with SPNEGO, NTLMSSP, ...
- */
- bcopy("BSRSPLY", sigloc, 8);
- return;
- }
-
- /*
- * This will compute the MAC and store it
- * directly into the message at sigloc.
- */
- rqp->rq_seqno = ctx->ct_mac_seqno;
- ctx->ct_mac_seqno += 2;
- err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- bzero(sigloc, SMBSIGLEN);
- }
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rp.mb_top;
- uint8_t sigbuf[SMBSIGLEN];
- uint8_t *sigloc;
- uint32_t rseqno;
- int err, fudge;
-
- /*
- * Note ct_mackey and ct_mackeylen gets initialized by
- * smb_smb_ssnsetup. It's normal to have a null MAC key
- * during extended security session setup.
- */
- if (ctx->ct_mackey == NULL)
- return (0);
-
- /*
- * Let caller deal with empty reply or short messages by
- * returning zero. Caller will fail later, in parsing.
- */
- if (m == NULL) {
- DPRINT("empty reply");
- return (0);
- }
- if (m->m_len < SMB_HDRLEN) {
- DPRINT("short reply");
- return (0);
- }
-
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
- rseqno = rqp->rq_seqno + 1;
-
- DPRINT("rq_rseqno = 0x%x", rseqno);
-
- err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- /*
- * If we can't compute a MAC, then there's
- * no point trying other seqno values.
- */
- return (EBADRPC);
- }
-
- /*
- * Compare the computed signature with the
- * one found in the message (at sigloc)
- */
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- return (0);
-
- DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
-
-#ifdef DEBUG
- /*
- * For diag purposes, we check whether the client/server idea
- * of the sequence # has gotten a bit out of sync.
- */
- for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
- (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- break;
- (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
- fudge = -fudge;
- break;
- }
- }
- if (fudge <= nsmb_signing_fudge) {
- DPRINT("rseqno=%d, but %d would have worked",
- rseqno, rseqno + fudge);
- }
-#endif
- return (EBADRPC);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
deleted file mode 100644
index da7640241c..0000000000
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Session Setup, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/netbios.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb.h>
-
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-
-#include "private.h"
-#include "charsets.h"
-#include "ntlm.h"
-#include "smb_crypt.h"
-
-
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp);
-
-/*
- * Session Setup: NULL session (anonymous)
- */
-int
-smb_ssnsetup_null(struct smb_ctx *ctx)
-{
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- return (err);
-}
-
-
-/*
- * SMB Session Setup, using NTLMv1 (and maybe LMv1)
- */
-int
-smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
-
- /* Put the LM,NTLM responses (as mbdata). */
- err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-/*
- * SMB Session Setup, using NTLMv2 (and LMv2)
- */
-int
-smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc, ti_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
- bzero(&ti_mbc, sizeof (ti_mbc));
-
- /* Build the NTLMv2 "target info" blob (as mbdata) */
- err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
- if (err)
- goto out;
-
- /* Put the LMv2, NTLMv2 responses (as mbdata). */
- err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&ti_mbc);
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-int
-smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
-{
- struct mbdata send_mb, recv_mb;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- err = ssp_ctx_create_client(ctx, hint_mb);
- if (err)
- goto out;
-
- bzero(&send_mb, sizeof (send_mb));
- bzero(&recv_mb, sizeof (recv_mb));
-
- /* NULL input indicates first call. */
- err = ssp_ctx_next_token(ctx, NULL, &send_mb);
- if (err)
- goto out;
-
- for (;;) {
- err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
- &ntstatus, &action);
- if (err)
- goto out;
- if (ntstatus == 0)
- break; /* normal loop termination */
- if (ntstatus != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- err = EAUTH;
- goto out;
- }
-
- /* middle calls get both in, out */
- err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
- if (err)
- goto out;
- }
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
-
- /* NULL output indicates last call. */
- (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
-
-out:
- ssp_ctx_destroy(ctx);
-
- return (err);
-}
-
-/*
- * Session Setup function used for all the forms we support.
- * To allow this sharing, the crypto stuff is computed by
- * callers and passed in as mbdata chains. Also, the args
- * have different meanings for extended security vs. old.
- * Some may be used as either IN or OUT parameters.
- *
- * For NTLM (v1, v2), all parameters are inputs
- * mbc1: [in] LM password hash
- * mbc2: [in] NT password hash
- * For Extended security (spnego)
- * mbc1: [in] outgoing blob data
- * mbc2: [out] received blob data
- * For both forms, these are optional:
- * statusp: [out] NT status
- * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
- */
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp)
-{
- static const char NativeOS[] = "Solaris";
- static const char LanMan[] = "NETSMB";
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp = NULL;
- struct mbdata *mbp;
- struct mbuf *m;
- int err, uc;
- uint32_t caps;
- uint16_t bc, len1, len2, sblen;
- uint8_t wc;
-
- caps = ctx->ct_clnt_caps;
- uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
-
- err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
- if (err)
- goto out;
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_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 */
-
- if (caps & SMB_CAP_EXT_SECURITY) {
- len1 = mbc1 ? mbc1->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 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);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */
- mbc1->mb_top = NULL; /* consumed */
- }
- /* mbc2 is required below */
- if (mbc2 == NULL) {
- err = EINVAL;
- goto out;
- }
- } else {
- len1 = mbc1 ? mbc1->mb_count : 0;
- len2 = mbc2 ? mbc2->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: LM pass. len */
- mb_put_uint16le(mbp, len2); /* 8: NT pass. len */
- mb_put_uint32le(mbp, 0); /* 9,10: reserved */
- mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */
- smb_rq_wend(rqp); /* 13: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */
- mbc1->mb_top = NULL; /* consumed */
- }
- if (mbc2 && mbc2->mb_top) {
- mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */
- mbc2->mb_top = NULL; /* consumed */
- }
- mb_put_string(mbp, ctx->ct_user, uc);
- mb_put_string(mbp, ctx->ct_domain, uc);
- }
- mb_put_string(mbp, NativeOS, uc);
- mb_put_string(mbp, LanMan, uc);
- smb_rq_bend(rqp);
-
- err = smb_rq_internal(ctx, rqp);
- if (err)
- goto out;
-
- if (statusp)
- *statusp = rqp->rq_status;
-
- /*
- * If we have a real error, the response probably has
- * no more data, so don't try to parse any more.
- * Note: err=0, means rq_status is valid.
- */
- if (rqp->rq_status != 0 &&
- rqp->rq_status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- goto out;
- }
-
- /*
- * Parse the reply
- */
- uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
- is->is_smbuid = rqp->rq_uid;
- mbp = &rqp->rq_rp;
-
- err = md_get_uint8(mbp, &wc);
- if (err)
- goto out;
-
- err = EBADRPC; /* for any problems in this section */
- if (caps & SMB_CAP_EXT_SECURITY) {
- if (wc != 4)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- md_get_uint16le(mbp, &sblen); /* sec. blob len */
- md_get_uint16le(mbp, &bc); /* byte count */
- /*
- * Get the security blob, after
- * sanity-checking the length.
- */
- if (sblen == 0 || bc < sblen)
- goto out;
- err = md_get_mbuf(mbp, sblen, &m);
- if (err)
- goto out;
- mb_initm(mbc2, m);
- mbc2->mb_count = sblen;
- } else {
- if (wc != 3)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- err = md_get_uint16le(mbp, &bc); /* byte count */
- if (err)
- goto out;
- }
-
- /*
- * Native OS, LANMGR, & Domain follow here.
- * Parse these strings and store for later.
- * If unicode, they should be aligned.
- *
- * Note that with Extended security, we may use
- * multiple calls to this function. Only parse
- * these strings on the last one (status == 0).
- * Ditto for the CAP_LARGE work-around.
- */
- if (rqp->rq_status != 0)
- goto out;
-
- /* Ignore any parsing errors for these strings. */
- err = md_get_string(mbp, &ctx->ct_srv_OS, uc);
- DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
- err = md_get_string(mbp, &ctx->ct_srv_LM, uc);
- DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
- /*
- * There's sometimes a server domain folloing
- * at this point, but we don't need it.
- */
-
- /* Success! (See Ignore any ... above) */
- err = 0;
-
- /*
- * MS-SMB 2.2.4.5 clarifies that when SMB signing is enabled,
- * the client should NOT use "large read/write" even though
- * the server might offer those capabilities.
- */
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- DPRINT("signing, so disable CAP_LARGE_(r/w)");
- ctx->ct_sopt.sv_caps &=
- ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
- }
-
-out:
- if (rqp)
- smb_rq_done(rqp);
-
- return (err);
-}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 993bdd61a8..1d3bc3e6f5 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -20,7 +20,7 @@
\
\
-\ Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+\ Copyright 2018 Nexenta Systems, Inc. All rights reserved.
\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
@@ -68,71 +68,24 @@ smbioc_tcon
tc_opt
tc_sh
-smb_sopt
- sv_proto
- sv_sm
- sv_tz
- sv_maxmux
- sv_maxvcs
- sv_rawmode
- sv_maxtx
- sv_maxraw
- sv_skey
- sv_caps
-
-smb_iods
- is_tran_fd
- is_vcflags
- is_hflags
- is_hflags2
- is_smbuid
- is_next_mid
- is_txmax
- is_rwmax
- is_rxmax
- is_wxmax
- is_ssn_key
- is_next_seq
- is_u_maclen
- is_u_mackey
-
smbioc_ssn_work
- wk_iods
- wk_sopt
wk_out_state
-
-smbioc_rq SIZEOF_SMBIOC_RQ
- ioc_cmd
- ioc_errclass IOC_RQ_ERRCLASS
- ioc_serror IOC_RQ_SERROR
- ioc_error IOC_RQ_ERROR
- ioc_tbufsz
- ioc_rbufsz
- _ioc_tbuf
- _ioc_rbuf
-
-smbioc_t2rq SIZEOF_SMBIOC_T2RQ
- ioc_setup
- ioc_setupcnt
- ioc_name IOC_T2_NAME
- ioc_tparamcnt
- ioc_tdatacnt
- ioc_rparamcnt
- ioc_rdatacnt
- ioc_errclass IOC_T2_ERRCLASS
- ioc_serror IOC_T2_SERROR
- ioc_error IOC_T2_ERROR
- ioc_rpflags2
- _ioc_tparam
+ wk_u_ssnkey_len
+ wk_u_ssnkey_buf
+ wk_u_auth_rlen
+ wk_u_auth_wlen
+ wk_u_auth_rbuf
+ wk_u_auth_wbuf
+ wk_ssn_key
+
+smbioc_xnp SIZEOF_SMBIOC_XNP
+ ioc_fh
+ ioc_tdlen
+ ioc_rdlen
+ ioc_more
_ioc_tdata
- _ioc_rparam
_ioc_rdata
-smbioc_flags SIZEOF_SMBIOC_FLAGS
- ioc_level
- ioc_mask
- ioc_flags
-
smbioc_rw SIZEOF_SMBIOC_RW
ioc_fh
ioc_cnt
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index d1e7efd60a..41405c314d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -34,6 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -105,7 +107,7 @@ void
smb_sm_done(void)
{
/*
- * XXX Q4BP why are we not iterating on smb_vclist here?
+ * Why are we not iterating on smb_vclist here?
* Because the caller has just called smb_sm_idle() to
* make sure we have no VCs before calling this.
*/
@@ -365,6 +367,8 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_mackey != NULL)
kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ if (vcp->vc_ssnkey != NULL)
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
cv_destroy(&vcp->iod_idle);
rw_destroy(&vcp->iod_rqlock);
@@ -399,7 +403,8 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
/* Expanded TAILQ_HEAD_INITIALIZER */
vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
- vcp->vc_state = SMBIOD_ST_IDLE;
+ /* A brand new VC should connect. */
+ vcp->vc_state = SMBIOD_ST_RECONNECT;
/*
* These identify the connection.
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index 42dfd687f9..7b2b6a4690 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_CONN_H
@@ -61,14 +62,11 @@ typedef struct smb_cred {
/*
* Bits in vc_flags (a.k.a. vc_co.co_flags)
- * Many of these were duplicates of SMBVOPT_ flags
- * and we now keep those too instead of merging
- * them into vc_flags.
+ * Note: SMBO_GONE is also in vc_flags
*/
-
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
+#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
+#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
/*
* Note: the common "obj" level uses this GONE flag by
@@ -146,6 +144,41 @@ typedef struct smb_connobj smb_connobj_t;
#define SMBL_SHARE 2
/*
+ * SMB1 Negotiated protocol parameters
+ */
+struct smb_sopt {
+ int16_t sv_proto; /* protocol dialect */
+ uchar_t sv_sm; /* security mode */
+ int16_t sv_tz; /* offset in min relative to UTC */
+ uint16_t sv_maxmux; /* max number of outstanding rq's */
+ uint16_t sv_maxvcs; /* max number of VCs */
+ uint16_t sv_rawmode;
+ uint32_t sv_maxtx; /* maximum transmit buf size */
+ uint32_t sv_maxraw; /* maximum raw-buffer size */
+ uint32_t sv_skey; /* session key */
+ uint32_t sv_caps; /* capabilites SMB_CAP_ */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * SMB1 I/O Deamon state
+ */
+struct smb_iods {
+ uint8_t is_hflags; /* SMB header flags */
+ uint16_t is_hflags2; /* SMB header flags2 */
+ uint16_t is_smbuid; /* SMB header UID */
+ uint16_t is_next_mid; /* SMB header MID */
+ uint32_t is_txmax; /* max tx/rx packet size */
+ uint32_t is_rwmax; /* max read/write data size */
+ uint32_t is_rxmax; /* max readx data size */
+ uint32_t is_wxmax; /* max writex data size */
+ /* Signing state */
+ uint32_t is_next_seq; /* my next sequence number */
+
+};
+typedef struct smb_iods smb_iods_t;
+
+/*
* Virtual Circuit to a server (really connection + session).
* Yes, calling this a "Virtual Circuit" is confusining,
* because it has nothing to do with the SMB notion of a
@@ -160,21 +193,26 @@ typedef struct smb_vc {
uid_t vc_owner; /* Unix owner */
int vc_genid; /* "generation" ID */
- int vc_mackeylen; /* length of MAC key */
- uint8_t *vc_mackey; /* MAC key */
+ int vc_mackeylen; /* MAC key length */
+ int vc_ssnkeylen; /* session key length */
+ uint8_t *vc_mackey; /* MAC key buffer */
+ uint8_t *vc_ssnkey; /* session key buffer */
ksema_t vc_sendlock;
struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
void *vc_tdata; /* transport control block */
- kcondvar_t iod_idle; /* IOD thread idle CV */
+ kcondvar_t iod_idle; /* IOD thread idle CV */
krwlock_t iod_rqlock; /* iod_rqlist */
struct smb_rqhead iod_rqlist; /* list of outstanding reqs */
- struct _kthread *iod_thr; /* the IOD (reader) thread */
+ struct _kthread *iod_thr; /* the IOD (reader) thread */
int iod_flags; /* see SMBIOD_* below */
int iod_newrq; /* send needed (iod_rqlock) */
int iod_muxfull; /* maxmux limit reached */
+ smb_iods_t vc_iods;
+ smb_sopt_t vc_sopt;
+
/* This is copied in/out when IOD enters/returns */
smbioc_ssn_work_t vc_work;
@@ -191,24 +229,23 @@ typedef struct smb_vc {
#define vc_srvaddr vc_ssn.ssn_id.id_srvaddr
#define vc_domain vc_ssn.ssn_id.id_domain
#define vc_username vc_ssn.ssn_id.id_user
-#define vc_vopt vc_ssn.ssn_vopt
+#define vc_vopt vc_ssn.ssn_vopt
/* defines for members in vc_work */
-#define vc_sopt vc_work.wk_sopt
-#define vc_maxmux vc_work.wk_sopt.sv_maxmux
-#define vc_tran_fd vc_work.wk_iods.is_tran_fd
-#define vc_hflags vc_work.wk_iods.is_hflags
-#define vc_hflags2 vc_work.wk_iods.is_hflags2
-#define vc_smbuid vc_work.wk_iods.is_smbuid
-#define vc_next_mid vc_work.wk_iods.is_next_mid
-#define vc_txmax vc_work.wk_iods.is_txmax
-#define vc_rwmax vc_work.wk_iods.is_rwmax
-#define vc_rxmax vc_work.wk_iods.is_rxmax
-#define vc_wxmax vc_work.wk_iods.is_wxmax
-#define vc_ssn_key vc_work.wk_iods.is_ssn_key
-#define vc_next_seq vc_work.wk_iods.is_next_seq
-#define vc_u_mackey vc_work.wk_iods.is_u_mackey
-#define vc_u_maclen vc_work.wk_iods.is_u_maclen
+
+/* defines for members in vc_sopt ? */
+#define vc_maxmux vc_sopt.sv_maxmux
+
+/* defines for members in vc_iods */
+#define vc_hflags vc_iods.is_hflags
+#define vc_hflags2 vc_iods.is_hflags2
+#define vc_smbuid vc_iods.is_smbuid
+#define vc_next_mid vc_iods.is_next_mid
+#define vc_txmax vc_iods.is_txmax
+#define vc_rwmax vc_iods.is_rwmax
+#define vc_rxmax vc_iods.is_rxmax
+#define vc_wxmax vc_iods.is_wxmax
+#define vc_next_seq vc_iods.is_next_seq
#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock)
#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock)
@@ -300,6 +337,8 @@ int smb_dev2share(int fd, struct smb_share **sspp);
/*
* smb_usr.c
*/
+int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *);
+
int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags);
@@ -319,7 +358,10 @@ int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
-int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags,
+ cred_t *cr);
+
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
/*
@@ -327,18 +369,21 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
*/
int smb_iod_create(smb_vc_t *vcp);
int smb_iod_destroy(smb_vc_t *vcp);
-int smb_iod_connect(smb_vc_t *vcp);
void smb_iod_disconnect(smb_vc_t *vcp);
int smb_iod_addrq(struct smb_rq *rqp);
int smb_iod_multirq(struct smb_rq *rqp);
int smb_iod_waitrq(struct smb_rq *rqp);
void smb_iod_removerq(struct smb_rq *rqp);
+int smb_iod_sendrecv(struct smb_rq *, int);
void smb_iod_shutdown_share(smb_share_t *ssp);
void smb_iod_sendall(smb_vc_t *);
-int smb_iod_recvall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *, boolean_t);
-int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int nsmb_iod_connect(smb_vc_t *vcp);
+int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr);
+int smb_iod_vc_work(smb_vc_t *, int, cred_t *);
int smb_iod_vc_idle(smb_vc_t *);
int smb_iod_vc_rcfail(smb_vc_t *);
int smb_iod_reconnect(smb_vc_t *);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index 9f718a7bfc..b2788bb194 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -34,7 +34,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -62,7 +62,7 @@
#include <sys/modctl.h>
#include <sys/devops.h>
#include <sys/thread.h>
-#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/zone.h>
#include <netsmb/smb_osdep.h>
@@ -88,6 +88,10 @@
/* for version checks */
const uint32_t nsmb_version = NSMB_VERSION;
+/* for smb_nbst_create() */
+dev_t nsmb_dev_tcp = NODEV;
+dev_t nsmb_dev_tcp6 = NODEV;
+
static void *statep;
static major_t nsmb_major;
static minor_t last_minor = NSMB_MIN_MINOR;
@@ -221,6 +225,9 @@ _init(void)
streams_msg_init();
/* No attach, so need to set major. */
nsmb_major = 1;
+ /* And these, for smb_nbst_create() */
+ nsmb_dev_tcp = AF_INET;
+ nsmb_dev_tcp6 = AF_INET6;
#endif /* _KERNEL */
return (0);
@@ -296,6 +303,7 @@ nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
static int
nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ major_t tmaj;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
@@ -320,6 +328,20 @@ nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
nsmb_major = ddi_name_to_major(NSMB_NAME);
+ /*
+ * We also need major numbers for t_kopen
+ */
+ tmaj = ddi_name_to_major("tcp");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp major?");
+ else
+ nsmb_dev_tcp = makedevice(tmaj, 0);
+ tmaj = ddi_name_to_major("tcp6");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp6 major?");
+ else
+ nsmb_dev_tcp6 = makedevice(tmaj, 0);
+
nsmb_dip = dip;
ddi_report_dev(dip);
return (DDI_SUCCESS);
@@ -431,107 +453,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
* check the zone status here on every ioctl call.
*/
- /*
- * 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_FLAGS2:
- err = smb_usr_get_flags2(sdp, arg, 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_REQUEST:
- err = smb_usr_simplerq(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_T2RQ:
- err = smb_usr_t2request(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_WORK:
- err = smb_usr_iod_work(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_IOD_IDLE:
- case SMBIOC_IOD_RCFAIL:
- err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
- 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);
+ err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);
return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
index 1e83a87806..4c547df25b 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -36,7 +36,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifdef DEBUG
@@ -75,6 +75,14 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.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 = 10; /* seconds */
+
int smb_iod_send_echo(smb_vc_t *);
#ifdef _FAKE_KERNEL
@@ -203,14 +211,15 @@ smb_iod_sendrq(struct smb_rq *rqp)
ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
/*
- * Note: Anything special for SMBR_INTERNAL here?
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
return (ENOTCONN);
}
-
/*
* On the first send, set the MID and (maybe)
* the signing sequence numbers. The increments
@@ -220,12 +229,16 @@ smb_iod_sendrq(struct smb_rq *rqp)
rqp->sr_mid = vcp->vc_next_mid++;
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 &
+ SMB_FLAGS2_SECURITY_SIGNATURE) != 0) {
/*
* We're signing requests and verifying
* signatures on responses. Set the
* sequence numbers of the request and
* response here, used in smb_rq_verify.
+ * Note we have the signing flag during
+ * session setup but no key yet, and
+ * don't want sequence numbers there.
*/
rqp->sr_seqno = vcp->vc_next_seq++;
rqp->sr_rseqno = vcp->vc_next_seq++;
@@ -258,12 +271,8 @@ smb_iod_sendrq(struct smb_rq *rqp)
*/
m = copymsg(rqp->sr_rq.mb_top);
-#ifdef DTRACE_PROBE
DTRACE_PROBE2(smb_iod_sendrq,
(smb_rq_t *), rqp, (mblk_t *), m);
-#else
- SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
-#endif
m_dumpm(m);
if (m != NULL) {
@@ -295,12 +304,6 @@ smb_iod_sendrq(struct smb_rq *rqp)
if (error)
SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error);
-#ifdef APPLE
- /* If proc waiting on rqp was signaled... */
- if (smb_rq_intr(rqp))
- smb_iod_rqprocessed(rqp, EINTR, 0);
-#endif
-
return (0);
}
@@ -341,15 +344,14 @@ top:
/*
* Process incoming packets
*
- * This is the "reader" loop, run by the IOD thread
- * while in state SMBIOD_ST_VCACTIVE. The loop now
- * simply blocks in the socket recv until either a
- * message arrives, or a disconnect.
+ * This is the "reader" loop, run by the IOD thread. Normally we're in
+ * state SMBIOD_ST_VCACTIVE here, but during reconnect we're called in
+ * other states with poll==TRUE
*
- * Any non-zero error means the IOD should terminate.
+ * A non-zero error return here causes the IOD work loop to terminate.
*/
int
-smb_iod_recvall(struct smb_vc *vcp)
+smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
{
struct smb_rq *rqp;
mblk_t *m;
@@ -364,12 +366,6 @@ smb_iod_recvall(struct smb_vc *vcp)
* or is asking the IOD to terminate.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- error = 0;
- break;
- }
-
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
/* This IOD thread will terminate. */
@@ -384,6 +380,13 @@ smb_iod_recvall(struct smb_vc *vcp)
m = NULL;
error = smb_iod_recv1(vcp, &m);
+ /*
+ * Internal requests (reconnecting) call this in a loop
+ * (with poll==TRUE) until the request completes.
+ */
+ if (error == ETIME && poll)
+ break;
+
if (error == ETIME &&
vcp->iod_rqlist.tqh_first != NULL) {
/*
@@ -417,16 +420,17 @@ smb_iod_recvall(struct smb_vc *vcp)
continue;
} /* ETIME && requests in queue */
- if (error == ETIME) {
+ if (error == ETIME) { /* and req list empty */
/*
* If the IOD thread holds the last reference
- * to this VC, let the IOD thread terminate.
+ * to this VC, let it become IDLE, and then
+ * let it be destroyed if not used.
*/
if (vcp->vc_co.co_usecount > 1)
continue;
SMB_VC_LOCK(vcp);
if (vcp->vc_co.co_usecount == 1) {
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
SMB_VC_UNLOCK(vcp);
error = 0;
break;
@@ -442,17 +446,16 @@ smb_iod_recvall(struct smb_vc *vcp)
* It's dangerous to continue here.
* (possible infinite loop!)
*
- * If we have requests enqueued, next
- * state is reconnecting, else idle.
+ * If this VC has shares, try reconnect;
+ * otherwise let this VC die now.
*/
- int state;
SMB_VC_LOCK(vcp);
- state = (vcp->iod_rqlist.tqh_first != NULL) ?
- SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
- smb_iod_newstate(vcp, state);
+ if (vcp->vc_co.co_usecount > 1)
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ else
+ smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
- error = 0;
break;
}
@@ -514,11 +517,18 @@ smb_iod_recvall(struct smb_vc *vcp)
if (cmd != SMB_COM_ECHO)
SMBSDEBUG("drop resp: mid %d, cmd %d\n",
(uint_t)mid, cmd);
-/* smb_printrqlist(vcp); */
m_freem(m);
}
rw_exit(&vcp->iod_rqlock);
+ /*
+ * Reconnect calls this in a loop with poll=TRUE
+ * We've received a response, so break now.
+ */
+ if (poll) {
+ error = 0;
+ break;
+ }
}
return (error);
@@ -565,21 +575,11 @@ smb_iod_addrq(struct smb_rq *rqp)
ASSERT(rqp->sr_cred);
/*
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
- */
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
- }
-
- /*
* Requests from the IOD itself are marked _INTERNAL,
* and get some special treatment to avoid blocking
* the reader thread (so we don't deadlock).
* The request is not yet on the queue, so we can
* modify it's state here without locks.
- * Only thing using this now is ECHO.
*/
rqp->sr_owner = curthread;
if (rqp->sr_owner == vcp->iod_thr) {
@@ -619,6 +619,15 @@ smb_iod_addrq(struct smb_rq *rqp)
smb_iod_removerq(rqp);
return (error);
+ } else {
+ /*
+ * State should be correct after the check in
+ * smb_rq_enqueue(), but we dropped locks...
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
}
rw_enter(&vcp->iod_rqlock, RW_WRITER);
@@ -722,9 +731,24 @@ smb_iod_waitrq(struct smb_rq *rqp)
int error, rc;
if (rqp->sr_flags & SMBR_INTERNAL) {
+ int timeleft = rqp->sr_timo;
+
ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
+ again:
+ smb_iod_sendall(vcp);
+ error = smb_iod_recvall(vcp, B_TRUE);
+ if (error == ETIME) {
+ /* We waited SMB_NBTIMO sec. */
+ timeleft -= SMB_NBTIMO;
+ if (timeleft > 0)
+ goto again;
+ }
+
smb_iod_removerq(rqp);
- return (EAGAIN);
+ if (rqp->sr_state != SMBRQ_NOTIFIED)
+ error = ETIME;
+
+ return (error);
}
/*
@@ -797,17 +821,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE1
DTRACE_PROBE1(smb_iod_waitrq1,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (still waiting).\n", vcp->vc_srvname,
- rqp->sr_mid, smb_timo_notice);
-#endif
}
}
@@ -826,17 +841,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq2,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (giving up).\n", vcp->vc_srvname,
- rqp->sr_mid, rqp->sr_timo);
-#endif
error = ETIME;
goto out;
}
@@ -930,11 +936,6 @@ smb_iod_sendall(smb_vc_t *vcp)
error = muxcnt = 0;
TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- error = ENOTCONN; /* stop everything! */
- break;
- }
-
if (rqp->sr_state == SMBRQ_NOTSENT) {
error = smb_iod_sendrq(rqp);
if (error)
@@ -960,10 +961,180 @@ smb_iod_sendall(smb_vc_t *vcp)
rw_exit(&vcp->iod_rqlock);
}
+/*
+ * Ioctl functions called by the user-level I/O Deamon (IOD)
+ * to bring up and service a connection to some SMB server.
+ */
+
+int
+nsmb_iod_connect(struct smb_vc *vcp)
+{
+ int err, val;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_connect: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
+ /*
+ * Set various options on this endpoint.
+ * Keep going in spite of errors.
+ */
+ val = smb_tcpsndbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_SNDBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt SNDBUF, err=%d", err);
+ }
+ val = smb_tcprcvbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_RCVBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt RCVBUF, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_KEEPALIVE, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt KEEPALIVE, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_NODELAY, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP_NODELAY, err=%d", err);
+ }
+ val = smb_connect_timeout * 1000;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_CON_TMO, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP con tmo, err=%d", err);
+ }
+
+ /*
+ * Bind and connect
+ */
+ err = SMB_TRAN_BIND(vcp, NULL);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: t_kbind: err=%d", err);
+ /* Continue on and try connect. */
+ }
+ err = SMB_TRAN_CONNECT(vcp, &vcp->vc_srvaddr.sa);
+ /*
+ * No cmn_err here, as connect failures are normal, i.e.
+ * when a server has multiple addresses and only some are
+ * routed for us. (libsmbfs tries them all)
+ */
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_CONNECTED);
+ SMB_VC_UNLOCK(vcp);
+ } /* else stay in state reconnect */
+
+ return (err);
+}
+
+/*
+ * Do the whole SMB1/SMB2 negotiate
+ */
+int
+nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
+{
+ struct smb_sopt *sv = &vcp->vc_sopt;
+ smb_cred_t scred;
+ int err = 0;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_CONNECTED) {
+ cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
+ /*
+ * (Re)init negotiated values
+ */
+ bzero(sv, sizeof (*sv));
+ vcp->vc_next_seq = 0;
+
+ /*
+ * If this was reconnect, get rid of the old MAC key
+ * and session key.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_mackey != NULL) {
+ kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ vcp->vc_mackey = NULL;
+ vcp->vc_mackeylen = 0;
+ }
+ if (vcp->vc_ssnkey != NULL) {
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ vcp->vc_ssnkey = NULL;
+ vcp->vc_ssnkeylen = 0;
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ smb_credinit(&scred, cr);
+ err = smb_smb_negotiate(vcp, &scred);
+ smb_credrele(&scred);
+
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED);
+ SMB_VC_UNLOCK(vcp);
+ }
+ /*
+ * (else) leave state as it was.
+ * User-level will report this error
+ * and close this device handle.
+ */
+
+ return (err);
+}
+
+/*
+ * Do either SMB1 or SMB2 session setup.
+ */
+int
+nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
+{
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ switch (vcp->vc_state) {
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ smb_credinit(&scred, cr);
+ // XXX if SMB1 else ...
+ err = smb_smb_ssnsetup(vcp, &scred);
+ smb_credrele(&scred);
+
+ SMB_VC_LOCK(vcp);
+ switch (err) {
+ case 0:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHOK);
+ break;
+ case EINPROGRESS: /* MORE_PROCESSING_REQUIRED */
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHCONT);
+ break;
+ default:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHFAIL);
+ break;
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ return (err);
+}
+
+/* ARGSUSED */
int
-smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
+smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
{
- struct file *fp = NULL;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
int err = 0;
/*
@@ -973,19 +1144,54 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
ASSERT(vcp->iod_thr == curthread);
/*
- * Get the network transport file pointer,
- * and "loan" it to our transport module.
+ * Should be in state...
+ */
+ if (vcp->vc_state != SMBIOD_ST_AUTHOK) {
+ cmn_err(CE_NOTE, "iod_vc_work: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
+ /*
+ * Update the session key and initialize SMB signing.
+ *
+ * This implementation does not use multiple SMB sessions per
+ * TCP connection (where only the first session key is used)
+ * so we always have a new session key here. Sanity check the
+ * length from user space. Normally 16 or 32.
*/
- if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
- err = EBADF;
- goto out;
+ if (wk->wk_u_ssnkey_len > 1024) {
+ cmn_err(CE_NOTE, "iod_vc_work: ssn key too long");
+ return (EINVAL);
}
- if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
- goto out;
+
+ ASSERT(vcp->vc_ssnkey == NULL);
+ SMB_VC_LOCK(vcp);
+ if (wk->wk_u_ssnkey_len != 0 &&
+ wk->wk_u_ssnkey_buf.lp_ptr != NULL) {
+ vcp->vc_ssnkeylen = wk->wk_u_ssnkey_len;
+ vcp->vc_ssnkey = kmem_alloc(vcp->vc_ssnkeylen, KM_SLEEP);
+ if (ddi_copyin(wk->wk_u_ssnkey_buf.lp_ptr,
+ vcp->vc_ssnkey, vcp->vc_ssnkeylen, flags) != 0) {
+ err = EFAULT;
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
/*
- * In case of reconnect, tell any enqueued requests
- * then can GO!
+ * If we have a session key, derive the MAC key for SMB signing.
+ * If this was a NULL session, we might have no session key.
+ */
+ ASSERT(vcp->vc_mackey == NULL);
+ if (vcp->vc_ssnkey != NULL) {
+ err = smb_sign_init(vcp);
+ if (err != 0)
+ return (err);
+ }
+
+ /*
+ * Tell any enqueued requests they can start.
*/
SMB_VC_LOCK(vcp);
vcp->vc_genid++; /* possibly new connection */
@@ -1006,7 +1212,7 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
/*
* Run the "reader" loop.
*/
- err = smb_iod_recvall(vcp);
+ err = smb_iod_recvall(vcp, B_FALSE);
/*
* The reader loop returned, so we must have a
@@ -1027,13 +1233,6 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
*/
smb_iod_invrq(vcp);
-out:
- /* Recall the file descriptor loan. */
- (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
- if (fp != NULL) {
- releasef(vcp->vc_tran_fd);
- }
-
return (err);
}
@@ -1092,10 +1291,6 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
* IOD thread for this VC.
*/
ASSERT(vcp->iod_thr == curthread);
-
- if (vcp->vc_state != SMBIOD_ST_RECONNECT)
- return (EINVAL);
-
SMB_VC_LOCK(vcp);
smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
@@ -1111,7 +1306,13 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
if (tr == 0)
err = EINTR;
- smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+ /*
+ * While we were waiting on the CV, the state might have
+ * changed to reconnect. If so, leave that; otherwise
+ * go to state idle until the next request.
+ */
+ if (vcp->vc_state == SMBIOD_ST_RCFAILED)
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
@@ -1138,6 +1339,10 @@ again:
/* FALLTHROUGH */
case SMBIOD_ST_RECONNECT:
+ case SMBIOD_ST_CONNECTED:
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ case SMBIOD_ST_AUTHOK:
rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
if (rv == 0) {
err = EINTR;
@@ -1149,6 +1354,7 @@ again:
err = 0; /* success! */
break;
+ case SMBIOD_ST_AUTHFAIL:
case SMBIOD_ST_RCFAILED:
case SMBIOD_ST_DEAD:
default:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
index f4ebf9a573..4a44e36e89 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_PASS_H
@@ -44,14 +46,13 @@ typedef struct smb_passid {
zoneid_t zoneid; /* Future Use */
char *srvdom; /* Windows Domain (or server) */
char *username; /* Windows User name */
- uchar_t lmhash[SMBIOC_HASH_SZ];
- uchar_t nthash[SMBIOC_HASH_SZ];
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
} smb_passid_t;
/* Called from smb_dev.c */
void smb_pkey_init(void);
void smb_pkey_fini(void);
int smb_pkey_idle(void);
-int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
#endif /* _SMB_PASS_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
index 997b7318dd..2301965762 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -331,6 +332,34 @@ ok_out:
}
/*
+ * Used by the IOD thread during connection setup.
+ */
+int
+smb_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int err;
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * Skip smb_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. We're doing that.
+ */
+ rqp->sr_rquid = vcp->vc_smbuid;
+ rqp->sr_rqtid = SMB_TID_UNKNOWN;
+ err = smb_iod_addrq(rqp);
+ if (err != 0)
+ return (err);
+
+ err = smb_rq_reply(rqp);
+
+ return (err);
+}
+
+/*
* Mark location of the word count, which is filled in later by
* smb_rw_wend(). Also initialize the counter that it uses
* to figure out what value to fill in.
@@ -495,7 +524,20 @@ smb_rq_reply(struct smb_rq *rqp)
error = md_get_uint32le(mdp, &rqp->sr_error);
error = md_get_uint8(mdp, &rqp->sr_rpflags);
error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
- if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+
+ if (rqp->sr_error != 0) {
+ if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+ rperror = smb_maperr32(rqp->sr_error);
+ } else {
+ uint8_t errClass = rqp->sr_error & 0xff;
+ uint16_t errCode = rqp->sr_error >> 16;
+ /* Convert to NT status */
+ rqp->sr_error = smb_doserr2status(errClass, errCode);
+ rperror = smb_maperror(errClass, errCode);
+ }
+ }
+
+ if (rperror) {
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
@@ -506,23 +548,13 @@ smb_rq_reply(struct smb_rq *rqp)
* they can look at rqp->sr_error if they
* need to know whether we got a
* STATUS_BUFFER_OVERFLOW.
- * XXX - should we do that for all errors
- * where (error & 0xC0000000) is 0x80000000,
- * i.e. all warnings?
*/
+ rqp->sr_flags |= SMBR_MOREDATA;
rperror = 0;
- } else
- rperror = smb_maperr32(rqp->sr_error);
+ }
} else {
- rqp->sr_errclass = rqp->sr_error & 0xff;
- rqp->sr_serror = rqp->sr_error >> 16;
- rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
- }
- if (rperror == EMOREDATA) {
- rperror = E2BIG;
- rqp->sr_flags |= SMBR_MOREDATA;
- } else
rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
error = md_get_uint32le(mdp, NULL);
error = md_get_uint32le(mdp, NULL);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
index 0184022a65..4d6dbb1fe0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_RQ_H_
@@ -54,7 +55,7 @@
#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */
#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */
#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
-/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
+/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
#define SMBR_MOREDATA 0x8000 /* our buffer was too small */
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
@@ -64,7 +65,7 @@
#define SMBT2_NORESTART 0x0010
#define SMBT2_MOREDATA 0x8000 /* our buffer was too small */
-#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
+#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock)
enum smbrq_state {
@@ -83,7 +84,7 @@ struct smb_rq {
enum smbrq_state sr_state;
struct smb_vc *sr_vc;
struct smb_share *sr_share;
- struct _kthread *sr_owner;
+ struct _kthread *sr_owner;
uint32_t sr_seqno; /* Seq. no. of request */
uint32_t sr_rseqno; /* Seq. no. of reply */
struct mbchain sr_rq;
@@ -105,7 +106,7 @@ struct smb_rq {
int sr_timo;
int sr_rexmit; /* how many more retries. dflt 0 */
int sr_sendcnt;
- struct timespec sr_timesent;
+ struct timespec sr_timesent;
int sr_lerror;
uint8_t sr_errclass;
uint16_t sr_serror;
@@ -124,7 +125,7 @@ struct smb_t2rq {
kcondvar_t t2_cond;
uint16_t t2_setupcount;
uint16_t *t2_setupdata;
- uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP];
+ uint16_t t2_setup[4];
uint8_t t2_maxscount; /* max setup words to return */
uint16_t t2_maxpcount; /* max param bytes to return */
uint16_t t2_maxdcount; /* max data bytes to return */
@@ -193,6 +194,7 @@ void smb_rq_bend(struct smb_rq *rqp);
int smb_rq_intr(struct smb_rq *rqp);
int smb_rq_simple(struct smb_rq *rqp);
int smb_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb_rq_internal(struct smb_rq *rqp, int timeout);
int smb_t2_alloc(struct smb_connobj *layer, ushort_t setup,
struct smb_cred *scred, struct smb_t2rq **rqpp);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
index d0f3e493ef..0d3b21a888 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -69,6 +69,31 @@ smb_crypto_mech_init(void)
cmn_err(CE_NOTE, "nsmb can't get md5 mech");
}
+/*
+ * This is called just after session setup completes,
+ * at the top of smb_iod_vc_work(). Initialize signing.
+ */
+int
+smb_sign_init(smb_vc_t *vcp)
+{
+
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ /*
+ * Convert the session key to the MAC key.
+ * SMB1 uses the whole session key.
+ */
+ vcp->vc_mackeylen = vcp->vc_ssnkeylen;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
+
+ /* The initial sequence number is two. */
+ vcp->vc_next_seq = 2;
+
+ return (0);
+}
+
#define SMBSIGLEN 8 /* SMB signature length */
#define SMBSIGOFF 14 /* SMB signature offset */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
index efb7e9a03d..47f9a201cc 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -33,8 +33,9 @@
*/
/*
+ * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -71,12 +72,38 @@
*/
#define SMB_MAX_LARGE_RW_SIZE (60*1024)
+struct smb_dialect {
+ int d_id;
+ const char *d_name;
+};
+
+static struct smb_dialect smb_dialects[] = {
+ {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
+ {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"},
+ {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"},
+ {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
+ {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
+ {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
+ {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
+ {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+};
+static uint_t smb_ndialect =
+ sizeof (smb_dialects) / sizeof (smb_dialects[0]);
+
+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 */
@@ -92,6 +119,443 @@ static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
+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;
+ 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;
+
+ 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 < smb_ndialect; 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 (err) {
+ SMBSDEBUG("smb_rq_internal, err %d", err);
+ 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 >= smb_ndialect) {
+ 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_WILL_SIGN;
+ 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;
+ }
+
+ /*
+ * 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.
+ */
+ ret = smb_rq_internal(rqp, smb_timo_logon);
+ if (ret != 0 && rqp->sr_error !=
+ NT_STATUS_MORE_PROCESSING_REQUIRED) {
+ /* UID no longer valid. */
+ vcp->vc_smbuid = 0;
+ 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 (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
/*
* Get the string representation of a share "use" type,
* as needed for the "service" in tree connect.
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
index df0f28ec05..48815ff709 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -33,8 +33,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_SUBR_H_
@@ -117,6 +117,8 @@ extern int smb_timo_open;
extern int smb_timo_read;
extern int smb_timo_write;
extern int smb_timo_append;
+extern dev_t nsmb_dev_tcp;
+extern dev_t nsmb_dev_tcp6;
#define EMOREDATA (0x7fff)
@@ -133,6 +135,7 @@ int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8,
const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen);
int smb_maperror(int eclass, int eno);
int smb_maperr32(uint32_t eno);
+uint_t smb_doserr2status(int, int);
int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int len, int caseopt, int *lenp);
int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
@@ -144,8 +147,8 @@ int smb_checksmp(void);
int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *);
struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa);
void smb_free_sockaddr(struct sockaddr *sa);
-int smb_toupper(const char *, char *, size_t);
+int smb_sign_init(struct smb_vc *);
void smb_rq_sign(struct smb_rq *);
int smb_rq_verify(struct smb_rq *);
int smb_calcv2mackey(struct smb_vc *, const uchar_t *,
@@ -158,6 +161,8 @@ void smb_crypto_mech_init(void);
/*
* SMB protocol level functions
*/
+int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
index a581aa3533..dc0e824e5e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -34,7 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -58,40 +59,6 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_subr.h>
-/*
- * XXX:This conversion might not be fully MS-Compatible
- * for calculating hashes. The output length may differ
- * for some locales and needs to be handled from where
- * the call is made.
- */
-int
-smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
-{
- int err = 0;
- size_t inlen, inrem, outrem;
-
- inrem = inlen = strlen(inbuf);
- outrem = outlen;
- (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem,
- U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
- /* inrem, outrem are bytes unused, remaining */
- if (inrem) {
- SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf);
- inlen -= inrem;
- }
- if (outrem) {
- outlen -= outrem;
- outbuf[outlen] = '\0';
- }
- if (outlen > inlen) {
- SMBSDEBUG("outlen > inlen! (%d > %d)\n",
- (int)outlen, (int)inlen);
- /* Truncate to inlen here? */
- }
-
- return (err);
-}
-
void
smb_credinit(struct smb_cred *scred, cred_t *cr)
{
@@ -223,7 +190,9 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
{NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
{NT_STATUS_BAD_NETWORK_NAME, ENOENT},
- {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA},
+ {NT_STATUS_BAD_NETWORK_PATH, ENOENT},
+ {NT_STATUS_BUFFER_TOO_SMALL, E2BIG},
+ {NT_STATUS_CANCELLED, ECANCELED},
{NT_STATUS_CANNOT_DELETE, EACCES},
{NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
{NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
@@ -237,59 +206,87 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_DISK_FULL, ENOSPC},
{NT_STATUS_DLL_NOT_FOUND, ELIBACC},
{NT_STATUS_DUPLICATE_NAME, EINVAL},
+ {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_EA_TOO_LARGE, E2BIG},
{NT_STATUS_END_OF_FILE, ENODATA},
+ {NT_STATUS_FILE_CLOSED, EBADF},
+ {NT_STATUS_FILE_DELETED, ENOENT},
+ {NT_STATUS_FILE_INVALID, EIO},
{NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
{NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN},
+ {NT_STATUS_FILE_RENAMED, ENOENT},
{NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
{NT_STATUS_FLOAT_OVERFLOW, ERANGE},
{NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
{NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
- {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EAUTH},
+ {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL},
+ {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN},
+ {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN},
{NT_STATUS_INTEGER_OVERFLOW, ERANGE},
- {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES},
+ {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH},
+ {NT_STATUS_INVALID_BUFFER_SIZE, EIO},
+ {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL},
{NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_INVALID_INFO_CLASS, EINVAL},
{NT_STATUS_INVALID_LEVEL, ENOTSUP},
- {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL},
+ {NT_STATUS_INVALID_LOGON_HOURS, EAUTH},
{NT_STATUS_INVALID_OWNER, EINVAL},
{NT_STATUS_INVALID_PARAMETER, EINVAL},
{NT_STATUS_INVALID_PIPE_STATE, EPIPE},
{NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL},
{NT_STATUS_INVALID_WORKSTATION, EACCES},
{NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_IO_DEVICE_ERROR, EIO},
{NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
- {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
- {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE},
{NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
{NT_STATUS_LOCK_NOT_GRANTED, EAGAIN},
- {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES},
- {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH},
+ {NT_STATUS_LOGON_FAILURE, EAUTH},
+ {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH},
{NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
{NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS},
{NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
{NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
{NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_NETWORK_NAME_DELETED, ENOENT},
{NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
{NT_STATUS_NET_WRITE_FAULT, ECOMM},
+ {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT},
{NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
{NT_STATUS_NONE_MAPPED, EINVAL},
{NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_NOT_FOUND, ENOENT},
{NT_STATUS_NOT_IMPLEMENTED, ENOTSUP},
+ {NT_STATUS_NOT_LOCKED, ENOLCK},
{NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
{NT_STATUS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_NO_EAS_ON_FILE, ENOENT},
+ {NT_STATUS_NO_LOGON_SERVERS, EAUTH},
{NT_STATUS_NO_MEDIA, ENOMEDIUM},
{NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
{NT_STATUS_NO_MEMORY, ENOMEM},
{NT_STATUS_NO_SUCH_DEVICE, ENODEV},
{NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_LOGON_SESSION, EAUTH},
+ {NT_STATUS_NO_SUCH_USER, EAUTH},
+ {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH},
+ {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH},
{NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
{NT_STATUS_OBJECT_NAME_INVALID, EINVAL},
{NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
{NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
{NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL},
+ {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF},
{NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
- {NT_STATUS_PASSWORD_EXPIRED, EACCES},
- {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES},
- {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EAUTH},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH},
+ {NT_STATUS_PASSWORD_RESTRICTION, EAUTH},
{NT_STATUS_PATH_NOT_COVERED, ENOENT},
{NT_STATUS_PIPE_BROKEN, EPIPE},
{NT_STATUS_PIPE_BUSY, EPIPE},
@@ -297,11 +294,12 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_PIPE_DISCONNECTED, EPIPE},
{NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY},
{NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_PORT_DISCONNECTED, EBADF},
{NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
{NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
{NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
{NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
- {NT_STATUS_RANGE_NOT_LOCKED, EIO},
+ {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */
{NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
{NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
{NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
@@ -311,9 +309,11 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_TIMER_NOT_CANCELED, ETIME},
{NT_STATUS_TOO_MANY_LINKS, EMLINK},
{NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+ {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH},
+ {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH},
{NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
{NT_STATUS_UNSUCCESSFUL, EINVAL},
- {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_WRONG_PASSWORD, EAUTH},
{0, 0}
};
@@ -872,6 +872,19 @@ smb_maperr32(uint32_t nterr)
return (EIO);
}
+uint_t
+smb_doserr2status(int dclass, int derr)
+{
+ const nt2doserr_t *nt2d;
+
+ if (dclass == 0 && derr == 0)
+ return (0);
+
+ for (nt2d = nt2doserr; nt2d->nterr; nt2d++)
+ if (nt2d->dclass == dclass && nt2d->derr == derr)
+ return (nt2d->nterr);
+ return (NT_STATUS_UNSUCCESSFUL);
+}
int
smb_maperror(int eclass, int eno)
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
index fd8f91eb1c..dc44fcc755 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
@@ -36,7 +36,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRAN_H_
@@ -54,11 +54,14 @@ struct file;
#define SMBT_NBTCP 1
/*
- * Transport parameters
+ * Transport parameters, for tr_getparam/tr_setparam
*/
-#define SMBTP_SNDSZ 1 /* R - int */
-#define SMBTP_RCVSZ 2 /* R - int */
-#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
+#define SMBTP_TCP_NODELAY 0x01 /* RW - int */
+#define SMBTP_TCP_CON_TMO 0x13 /* RW - int */
+#define SMBTP_KEEPALIVE SO_KEEPALIVE /* RW - int */
+#define SMBTP_SNDBUF SO_SNDBUF /* RW - int */
+#define SMBTP_RCVBUF SO_RCVBUF /* RW - int */
+#define SMBTP_RCVTIMEO SO_RCVTIMEO /* RW - int? */
struct smb_tran_ops;
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index 0b44cf879f..733ff9d078 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -35,7 +35,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -74,13 +74,6 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.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 nb_disconnect(struct nbpcb *nbp);
@@ -486,22 +479,45 @@ out:
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
-/*ARGSUSED*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
- struct nbpcb *nbp;
+ TIUSER *tiptr = NULL;
+ struct nbpcb *nbp = NULL;
+ dev_t dev;
+ int rc;
+ ushort_t fmode;
+
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ dev = nsmb_dev_tcp;
+ break;
+ case AF_INET6:
+ dev = nsmb_dev_tcp6;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ fmode = FREAD|FWRITE;
+ rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
+ return (rc);
+ }
+ ASSERT(tiptr != NULL);
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
- nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
- nbp->nbp_sndbuf = smb_tcpsndbuf;
- nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ nbp->nbp_tiptr = tiptr;
+ nbp->nbp_fmode = fmode;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+
vcp->vc_tdata = nbp;
return (0);
@@ -543,6 +559,8 @@ smb_nbst_done(struct smb_vc *vcp)
}
/*
+ * XXX - Later, get rid of nb_loan_fp, nb_unloan_fp
+ *
* Loan a transport file pointer (from user space) to this
* IOD endpoint. There should be no other thread using this
* endpoint when we do this, but lock for consistency.
@@ -632,21 +650,62 @@ smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
return (error);
}
-/*ARGSUSED*/
static int
smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- return (ENOTSUP);
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
+
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
+
+ err = t_kbind(tiptr, NULL, NULL);
+
+ return (err);
}
-/*ARGSUSED*/
static int
smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
- return (ENOTSUP);
+ struct t_call call;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int alen, err;
+
+ /* Need the address length */
+ switch (sap->sa_family) {
+ case AF_INET:
+ alen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ alen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ /* sockaddr goes in the "addr" netbuf */
+ bzero(&call, sizeof (call));
+ call.addr.buf = (char *)sap;
+ call.addr.len = alen;
+ call.addr.maxlen = alen;
+
+ err = t_kconnect(tiptr, &call, NULL);
+ if (err != 0)
+ return (err);
+
+ mutex_enter(&nbp->nbp_lock);
+
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
+
+ mutex_exit(&nbp->nbp_lock);
+
+ return (0);
}
-/*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
@@ -833,42 +892,78 @@ smb_nbst_poll(struct smb_vc *vcp, int ticks)
return (ENOTSUP);
}
+/*ARGSUSED*/
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
+ return (EINVAL);
+}
+
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct T_opthdr oh;
+ int ival;
+ } opts;
struct nbpcb *nbp = vcp->vc_tdata;
+ int level, name, err;
switch (param) {
- case SMBTP_SNDSZ:
- *(int *)data = nbp->nbp_sndbuf;
- break;
- case SMBTP_RCVSZ:
- *(int *)data = nbp->nbp_rcvbuf;
- break;
- case SMBTP_TIMEOUT:
- *(struct timespec *)data = nbp->nbp_timo;
+ case SMBTP_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ name = TCP_NODELAY;
break;
-#ifdef SMBTP_SELECTID
- case SMBTP_SELECTID:
- *(void **)data = nbp->nbp_selectid;
+
+ case SMBTP_TCP_CON_TMO: /* int mSec */
+ level = IPPROTO_TCP;
+ name = TCP_CONN_ABORT_THRESHOLD;
break;
-#endif
-#ifdef SMBTP_UPCALL
- case SMBTP_UPCALL:
- *(void **)data = nbp->nbp_upcall;
+
+ case SMBTP_KEEPALIVE: // SO_KEEPALIVE
+ case SMBTP_SNDBUF: // SO_SNDBUF
+ case SMBTP_RCVBUF: // SO_RCVBUF
+ case SMBTP_RCVTIMEO: // SO_RCVTIMEO
+ level = SOL_SOCKET;
+ name = param;
break;
-#endif
+
default:
return (EINVAL);
}
- return (0);
-}
-/*ARGSUSED*/
-static int
-smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
-{
- return (EINVAL);
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = *(int *)data;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+ oreq.opt.maxlen = oreq.opt.len;
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.len = 0;
+ ores.opt.maxlen = 0;
+
+ err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
+ return (EPROTO);
+ }
+
+ if (ores.flags != T_SUCCESS) {
+ cmn_err(CE_NOTE, "smb_nbst_setparam: "
+ "flags 0x%x, status 0x%x",
+ (int)ores.flags, (int)opts.oh.status);
+ return (EPROTO);
+ }
+
+ return (0);
}
/*
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
index f810a538cd..3c5e86639e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
@@ -32,13 +32,14 @@
* $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRANTCP_H_
#define _NETSMB_SMB_TRANTCP_H_
enum nbstate {
NBST_CLOSED,
+ NBST_IDLE,
NBST_RQSENT,
NBST_SESSION,
NBST_RETARGET,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
index fb587cd79e..5209732a1e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* 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>
@@ -61,28 +62,6 @@
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.
*
@@ -105,7 +84,10 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
/*
* Return the session key.
*/
- if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+ 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);
@@ -113,112 +95,18 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
}
/*
- * 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
+ * Ioctl function for SMBIOC_XACTNP (transact named pipe)
*/
int
-smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_xnp(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;
+ smbioc_xnp_t *ioc = NULL;
struct smb_t2rq *t2p = NULL;
struct mdchain *mdp;
int err, len, mbseg;
+ uint16_t setup[2];
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
@@ -234,91 +122,64 @@ smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
/* 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 (ioc->ioc_fh == -1) {
if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
err = ESTALE;
goto out;
}
- ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
+ ioc->ioc_fh = sdp->sd_smbfid;
}
+ setup[0] = TRANS_TRANSACT_NAMED_PIPE;
+ setup[1] = (uint16_t)ioc->ioc_fh;
+
t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
- err = smb_t2_init(t2p, SSTOCP(ssp),
- ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
+ err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &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_setupcount = 2;
+ t2p->t2_setupdata = setup;
+
+ t2p->t_name = "\\PIPE\\";
+ t2p->t_name_len = 6;
+
t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = ioc->ioc_rparamcnt;
- t2p->t2_maxdcount = ioc->ioc_rdatacnt;
+ t2p->t2_maxpcount = 0;
+ t2p->t2_maxdcount = ioc->ioc_rdlen;
- /* Transmit parameters */
- err = smb_cpdatain(&t2p->t2_tparam,
- ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
- if (err)
- goto out;
+ /* Transmit parameters (none) */
/* Transmit data */
err = smb_cpdatain(&t2p->t2_tdata,
- ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
+ ioc->ioc_tdlen, 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;
+ /* No returned parameters. */
/* 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) {
+ if (len > ioc->ioc_rdlen) {
err = EMSGSIZE;
goto out;
}
- ioc->ioc_rdatacnt = (ushort_t)len;
+ ioc->ioc_rdlen = (ushort_t)len;
err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
if (err)
goto out;
} else
- ioc->ioc_rdatacnt = 0;
+ ioc->ioc_rdlen = 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;
+ if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
+ ioc->ioc_more = 1;
(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
@@ -825,24 +686,22 @@ smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
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)
+ * Ioctl handler for all SMBIOC_IOD_...
*/
int
-smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
+ struct smb_vc *vcp;
int err = 0;
- /* Must have a valid session. */
+ /* 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 (vcp->vc_flags & SMBV_GONE)
+ if (sdp->sd_share != NULL)
return (EINVAL);
/*
@@ -859,39 +718,53 @@ smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
return (err);
/*
- * Copy the "work" state, etc. into the VC
- * The MAC key is copied separately.
+ * 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;
}
- 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;
- }
- }
+ vcp->vc_work.wk_out_state = 0;
- err = smb_iod_vc_work(vcp, cr);
+ switch (cmd) {
- /* Caller wants state here. */
- vcp->vc_work.wk_out_state = vcp->vc_state;
+ case SMBIOC_IOD_CONNECT:
+ err = nsmb_iod_connect(vcp);
+ break;
- (void) ddi_copyout(&vcp->vc_work, (void *)arg,
- sizeof (smbioc_ssn_work_t), flags);
+ case SMBIOC_IOD_NEGOTIATE:
+ err = nsmb_iod_negotiate(vcp, cr);
+ break;
-out:
- if (vcp->vc_mackey) {
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
+ 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.
@@ -904,67 +777,104 @@ out:
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)
+smb_usr_ioctl(smb_dev_t *sdp, int cmd, 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);
+ int err;
/*
- * Is there already an IOD for this VC?
- * (Should never happen.)
+ * Serialize ioctl calls. The smb_usr_... functions
+ * don't expect concurrent calls on a given sdp.
*/
- 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 */
+ 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_IOD_IDLE:
- err = smb_iod_vc_idle(vcp);
+ 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_iod_vc_rcfail(vcp);
+ 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;
- goto out;
+ break;
}
- /* 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);
+ mutex_enter(&sdp->sd_lock);
+ sdp->sd_flags &= ~NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
return (err);
}
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index d2e7690062..fb20b9c753 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_DEV_H_
@@ -71,9 +72,9 @@
* associated structures change in ways that would
* make them incompatible with an old driver.
*/
-#define NSMB_VERMAJ 1
-#define NSMB_VERMIN 4000
-#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
+#define NSMB_VERMAJ 2
+#define NSMB_VERMIN 0x100
+#define NSMB_VERSION ((NSMB_VERMAJ << 16) | NSMB_VERMIN)
/*
* Some errno values we need to expose to the library.
@@ -84,7 +85,7 @@
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -111,9 +112,7 @@
#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */
#define SMBVOPT_SINGLESHARE 0x0004 /* keep only one share at this VC */
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
-#define SMBVOPT_EXT_SEC 0x0020 /* extended security negotiation */
-#define SMBVOPT_USE_KEYCHAIN 0x0040 /* get p/w from keychain */
-#define SMBVOPT_KC_DOMAIN 0x0080 /* keychain lookup uses domain */
+#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */
#define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */
#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
@@ -137,13 +136,18 @@
/*
* network IO daemon states
- * really connection states.
*/
enum smbiod_state {
- SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */
- SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
+ SMBIOD_ST_UNINIT = 0, /* uninitialized */
+ SMBIOD_ST_RECONNECT, /* a [re]connect attempt requested */
SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */
- SMBIOD_ST_VCACTIVE, /* session established */
+ SMBIOD_ST_CONNECTED, /* Transport (TCP) connected */
+ SMBIOD_ST_NEGOTIATED, /* Negotiated SMB/SMB2+ */
+ SMBIOD_ST_AUTHCONT, /* Session setup continuing */
+ SMBIOD_ST_AUTHFAIL, /* Session setup failed */
+ SMBIOD_ST_AUTHOK, /* Session setup success */
+ SMBIOD_ST_VCACTIVE, /* iod_work running */
+ SMBIOD_ST_IDLE, /* no trees, will go DEAD */
SMBIOD_ST_DEAD /* connection gone, no IOD */
};
@@ -232,55 +236,19 @@ typedef struct smbioc_tcon {
smbioc_oshare_t tc_sh;
} smbioc_tcon_t;
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
- int16_t sv_proto; /* protocol dialect */
- uchar_t sv_sm; /* security mode */
- int16_t sv_tz; /* offset in min relative to UTC */
- uint16_t sv_maxmux; /* max number of outstanding rq's */
- uint16_t sv_maxvcs; /* max number of VCs */
- uint16_t sv_rawmode;
- uint32_t sv_maxtx; /* maximum transmit buf size */
- uint32_t sv_maxraw; /* maximum raw-buffer size */
- uint32_t sv_skey; /* session key */
- uint32_t sv_caps; /* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * State carried in/out of the driver by the IOD thread.
- * Inside the driver, these are members of the "VC" object.
- */
-struct smb_iods {
- int32_t is_tran_fd; /* transport FD */
- uint32_t is_vcflags; /* SMBV_... */
- uint8_t is_hflags; /* SMB header flags */
- uint16_t is_hflags2; /* SMB header flags2 */
- uint16_t is_smbuid; /* SMB header UID */
- uint16_t is_next_mid; /* SMB header MID */
- uint32_t is_txmax; /* max tx/rx packet size */
- uint32_t is_rwmax; /* max read/write data size */
- uint32_t is_rxmax; /* max readx data size */
- uint32_t is_wxmax; /* max writex data size */
- uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
- /* Signing state */
- uint32_t is_next_seq; /* my next sequence number */
- uint32_t is_u_maclen; /* MAC key length */
- lptr_t is_u_mackey; /* user-space ptr! */
-};
-typedef struct smb_iods smb_iods_t;
-
/*
* This is the operational state information passed
* in and out of the driver for SMBIOC_SSN_WORK
*/
struct smbioc_ssn_work {
- smb_iods_t wk_iods;
- smb_sopt_t wk_sopt;
- int wk_out_state;
+ uint32_t wk_out_state; /* out-only */
+ uint32_t wk_u_ssnkey_len; /* ssn key length */
+ lptr_t wk_u_ssnkey_buf; /* user-space ptr! */
+ uint32_t wk_u_auth_rlen; /* recv auth tok len */
+ uint32_t wk_u_auth_wlen; /* send auth tok len */
+ lptr_t wk_u_auth_rbuf; /* recv auth tok buf */
+ lptr_t wk_u_auth_wbuf; /* send auth tok buf */
+ uint8_t wk_ssn_key[SMBIOC_HASH_SZ]; /* session key */
};
typedef struct smbioc_ssn_work smbioc_ssn_work_t;
@@ -288,57 +256,6 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t;
* User-level SMB requests
*/
-/*
- * SMBIOC_REQUEST (simple SMB request)
- */
-typedef struct smbioc_rq {
- uchar_t ioc_cmd;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint32_t ioc_tbufsz; /* transmit */
- uint32_t ioc_rbufsz; /* receive */
- lptr_t _ioc_tbuf;
- lptr_t _ioc_rbuf;
-} smbioc_rq_t;
-#define ioc_tbuf _ioc_tbuf.lp_ptr
-#define ioc_rbuf _ioc_rbuf.lp_ptr
-
-
-#define SMBIOC_T2RQ_MAXSETUP 4
-#define SMBIOC_T2RQ_MAXNAME 128
-
-typedef struct smbioc_t2rq {
- uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP];
- int32_t ioc_setupcnt;
- char ioc_name[SMBIOC_T2RQ_MAXNAME];
- ushort_t ioc_tparamcnt;
- ushort_t ioc_tdatacnt;
- ushort_t ioc_rparamcnt;
- ushort_t ioc_rdatacnt;
- uint8_t ioc__pad1;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint16_t ioc_rpflags2;
- uint16_t ioc__pad2;
- lptr_t _ioc_tparam;
- lptr_t _ioc_tdata;
- lptr_t _ioc_rparam;
- lptr_t _ioc_rdata;
-} smbioc_t2rq_t;
-#define ioc_tparam _ioc_tparam.lp_ptr
-#define ioc_tdata _ioc_tdata.lp_ptr
-#define ioc_rparam _ioc_rparam.lp_ptr
-#define ioc_rdata _ioc_rdata.lp_ptr
-
-
-typedef struct smbioc_flags {
- int32_t ioc_level; /* 0 - session, 1 - share */
- int32_t ioc_flags;
- int32_t ioc_mask;
-} smbioc_flags_t;
-
typedef struct smbioc_rw {
int32_t ioc_fh;
uint32_t ioc_cnt;
@@ -348,6 +265,18 @@ typedef struct smbioc_rw {
#define ioc_offset _ioc_offset._f
#define ioc_base _ioc_base.lp_ptr
+/* Transact on named pipe (send/recv) */
+typedef struct smbioc_xnp {
+ int32_t ioc_fh;
+ uint32_t ioc_tdlen; /* transmit len */
+ uint32_t ioc_rdlen; /* recv maxlen */
+ uint32_t ioc_more; /* more data to read */
+ lptr_t _ioc_tdata;
+ lptr_t _ioc_rdata;
+} smbioc_xnp_t;
+#define ioc_tdata _ioc_tdata.lp_ptr
+#define ioc_rdata _ioc_rdata.lp_ptr
+
typedef struct smbioc_ntcreate {
uint32_t ioc_req_acc;
uint32_t ioc_efattr;
@@ -383,18 +312,16 @@ typedef struct smbioc_pk {
* Keep GETVERS first and use it to verify
* driver compatibility with the library.
*/
-#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
+#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
typedef enum nsmb_ioc {
SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */
- SMBIOC_FLAGS2, /* get hflags2 */
+ SMBIOC_FLAGS2, /* obsolete */
SMBIOC_GETSSNKEY, /* get SMB session key */
SMBIOC_DUP_DEV, /* duplicate dev handle */
- SMBIOC_REQUEST, /* simple request */
- SMBIOC_T2RQ, /* trans2 request */
-
SMBIOC_READ, /* read (pipe) */
SMBIOC_WRITE, /* write (pipe) */
+ SMBIOC_XACTNP, /* "transact" (pipe) */
SMBIOC_NTCREATE, /* open or create */
SMBIOC_PRINTJOB, /* open print job */
SMBIOC_CLOSEFH, /* from ntcreate or printjob */
@@ -409,9 +336,12 @@ typedef enum nsmb_ioc {
SMBIOC_TREE_KILL,
SMBIOC_TREE_RELE,
+ SMBIOC_IOD_CONNECT, /* Setup connection */
+ SMBIOC_IOD_NEGOTIATE, /* SMB/SMB2 negotiate */
+ SMBIOC_IOD_SSNSETUP, /* SMB/SMB2 session setup */
SMBIOC_IOD_WORK, /* work on session requests */
SMBIOC_IOD_IDLE, /* wait for requests on this session */
- SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */
+ SMBIOC_IOD_RCFAIL, /* tell driver reconnect failed */
/* Password Keychain (PK) support. */
SMBIOC_PK_ADD, /* Add/Modify a password entry */
diff --git a/usr/src/uts/common/sys/t_kuser.h b/usr/src/uts/common/sys/t_kuser.h
index 7aac9d94d2..b3c4da657c 100644
--- a/usr/src/uts/common/sys/t_kuser.h
+++ b/usr/src/uts/common/sys/t_kuser.h
@@ -98,6 +98,7 @@ extern int t_kconnect(TIUSER *, struct t_call *, struct t_call *);
extern int t_kfree(TIUSER *, char *, int);
extern int t_kgetstate(TIUSER *, int *);
extern int t_kopen(struct file *, dev_t, int, TIUSER **, struct cred *);
+extern int t_koptmgmt(TIUSER *, struct t_optmgmt *, struct t_optmgmt *);
extern int t_krcvudata(TIUSER *, struct t_kunitdata *, int *, int *);
extern int t_ksndudata(TIUSER *, struct t_kunitdata *, frtn_t *);
extern int t_kspoll(TIUSER *, int, int, int *);
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index 9d670f24c3..e966bfdef5 100644
--- a/usr/src/uts/intel/nsmb/ioc_check.ref
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref
@@ -17,65 +17,22 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_SSN_KEY 0x28
+#define WK_SSN_KEY_INCR 0x1
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_FH 0x0
+#define IOC_TDLEN 0x4
+#define IOC_RDLEN 0x8
+#define IOC_MORE 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_SMBIOC_RW 0x18
#define IOC_FH 0x0
#define IOC_CNT 0x4
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index 9d670f24c3..e966bfdef5 100644
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref
@@ -17,65 +17,22 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_SSN_KEY 0x28
+#define WK_SSN_KEY_INCR 0x1
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_FH 0x0
+#define IOC_TDLEN 0x4
+#define IOC_RDLEN 0x8
+#define IOC_MORE 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_SMBIOC_RW 0x18
#define IOC_FH 0x0
#define IOC_CNT 0x4