summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2013-07-16 22:10:42 -0400
committerGordon Ross <gwr@nexenta.com>2014-11-12 14:29:11 -0500
commit85e6b6747d07050e01ec91acef2453655821f9ab (patch)
treeb2531706b2e44cbeaad4a5b157ddffbae7e8406f /usr/src
parentfd75ca8de430ee0ba5ce650efee0ac0b85ed43e9 (diff)
downloadillumos-joyent-85e6b6747d07050e01ec91acef2453655821f9ab.tar.gz
5308 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Reviewed by: Bayard Bell <bayard.bell@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Thomas Keiser <thomas.keiser@nexenta.com> Reviewed by: Albert Lee <trisk@nexenta.com> Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/Makefile56
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/srvenum.c436
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/srvinfo.c (renamed from usr/src/cmd/fs.d/smbclnt/test/testnp.c)15
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/tconn.c171
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h5
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c95
-rw-r--r--usr/src/lib/libsmbfs/smb/crypt.c99
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c34
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c178
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h11
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c257
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.h15
-rw-r--r--usr/src/lib/libsmbfs/smb/smb_crypt.h19
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c73
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/mapfile-vers3
16 files changed, 1192 insertions, 283 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/test/Makefile b/usr/src/cmd/fs.d/smbclnt/test/Makefile
index 40f12dfc39..62eb716f5f 100644
--- a/usr/src/cmd/fs.d/smbclnt/test/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/test/Makefile
@@ -19,41 +19,63 @@
# CDDL HEADER END
#
#
-# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
#
-FSTYPE= smbfs
-LIBPROG= testnp
-ROOTFS_PROG= $(LIBPROG)
+include $(SRC)/cmd/Makefile.cmd
-include ../../Makefile.fstype
+PROG= srvenum srvinfo tconn
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
-OBJS= $(LIBPROG).o
-SRCS= $(LIBPROG).c $(FSLIBSRC)
+# ROOTFS_PROG= $(LIBPROG)
+# include ../../Makefile.fstype
+ROOTOPTPKG = $(ROOT)/opt/smbcl-tests
+TESTDIR = $(ROOTOPTPKG)/tests
+INST_CMDS = $(PROG:%=$(TESTDIR)/%)
+
+# OBJS= $(LIBPROG).o
+# SRCS= $(LIBPROG).c $(FSLIBSRC)
+
+CPPFLAGS += -I../../../../uts/common
+CPPFLAGS += -I../../../../lib/libsmbfs
+
+LDLIBS += -R '$$ORIGIN/../../../usr/lib'
LDLIBS += -lsmbfs
+LINTLIBS= -L$(ROOTLIB) -lsmbfs
CFLAGS += $(CCVERBOSE)
CERRWARN += -_gcc=-Wno-unused-variable
C99MODE= $(C99_ENABLE)
-CLOBBERFILES += $(LIBPROG)
+LINTFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+
+# CLOBBERFILES += $(LIBPROG)
-# uncomment these for dbx debugging
-#COPTFLAG = -g
-#CTF_FLAGS =
-#CTFCONVERT_O=
-#CTFMERGE_LIB=
+all: $(PROG)
-all: $(ROOTFS_PROG)
+install: all $(ROOTOPTPKG) $(TESTDIR) $(INST_CMDS)
-install: $(ROOTLIBFSTYPEPROG)
+lint:
+ for f in $(SRCS); do ;\
+ $(LINT.c) $$f $(LINTLIBS) ; done
-lint: lint_SRCS
+clobber: clean
+ -$(RM) $(PROG)
clean:
- $(RM) $(OBJS)
+ -$(RM) $(OBJS)
+
+$(ROOTOPTPKG):
+ $(INS.dir)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/test/srvenum.c b/usr/src/cmd/fs.d/smbclnt/test/srvenum.c
new file mode 100644
index 0000000000..ee3aeba014
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/test/srvenum.c
@@ -0,0 +1,436 @@
+/*
+ * 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) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Test program for the smbfs named pipe API.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include <netsmb/smbfs_api.h>
+
+/*
+ * This is a quick hack for testing client-side named pipes.
+ * Its purpose is to test the ability to connect to a server,
+ * open a pipe, send and receive data. The "hack" aspect is
+ * the use of hand-crafted RPC messages, which allows testing
+ * of the named pipe API separately from the RPC libraries.
+ *
+ * I captured the two small name pipe messages sent when
+ * requesting a share list via RPC over /pipe/srvsvc and
+ * dropped them into the arrays below (bind and enum).
+ * This program sends the two messages (with adjustments)
+ * and just dumps whatever comes back over the pipe.
+ * Use wireshark if you want to see decoded messages.
+ */
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+/* This is a DCE/RPC bind call for "srvsvc". */
+static const uchar_t
+srvsvc_bind[] = {
+ 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01,
+ 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88,
+ 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
+ 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
+ 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 };
+
+/* This is a srvsvc "enum servers" call, in two parts */
+static const uchar_t
+srvsvc_enum1[] = {
+ 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00,
+#define ENUM_RPCLEN_OFF 8
+ /* V - RPC frag length */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* ... and the operation number is: VVVV */
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00,
+#define ENUM_SLEN1_OFF 28
+#define ENUM_SLEN2_OFF 36
+ /* server name, length 14 vv ... */
+ 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 };
+ /* UNC server here, i.e.: "\\192.168.1.6" */
+
+static const uchar_t
+srvsvc_enum2[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+static uchar_t sendbuf[1024];
+static uchar_t recvbuf[4096];
+static char *server;
+
+static int pipetest(struct smb_ctx *);
+
+static void
+srvenum_usage(void)
+{
+ printf("usage: srvenum [-d domain][-u user][-p passwd] server\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, error;
+ struct smb_ctx *ctx = NULL;
+ char *dom = NULL;
+ char *usr = NULL;
+ char *pw = NULL;
+
+ while ((c = getopt(argc, argv, "vd:u:p:")) != -1) {
+ switch (c) {
+ case 'v':
+ smb_verbose = 1;
+ break;
+
+ case 'd':
+ dom = optarg;
+ break;
+ case 'u':
+ usr = optarg;
+ break;
+ case 'p':
+ pw = optarg;
+ break;
+ case '?':
+ srvenum_usage();
+ break;
+ }
+ }
+ if (optind >= argc)
+ srvenum_usage();
+ server = argv[optind];
+
+ if (pw != NULL && (dom == NULL || usr == NULL)) {
+ fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
+ argv[0]);
+ srvenum_usage();
+ }
+
+ /*
+ * This section is intended to demonstrate how an
+ * RPC client library might use this interface.
+ */
+ error = smb_ctx_alloc(&ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
+ goto out;
+ }
+
+ /*
+ * Set server, share, domain, user
+ * (in the ctx handle).
+ */
+ smb_ctx_setfullserver(ctx, server);
+ smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+ if (dom)
+ smb_ctx_setdomain(ctx, dom, B_TRUE);
+ if (usr)
+ smb_ctx_setuser(ctx, usr, B_TRUE);
+ if (pw)
+ smb_ctx_setpassword(ctx, pw, NULL);
+
+
+ /*
+ * If this code were in smbutil or mount_smbfs, it would
+ * get system and $HOME/.nsmbrc settings here, like this:
+ */
+#if 0
+ error = smb_ctx_readrc(ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_readrc failed\n", argv[0]);
+ goto out;
+ }
+#endif
+
+ /*
+ * Resolve the server address,
+ * setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
+ goto out;
+ }
+
+ /*
+ * Get the session and tree.
+ */
+ error = smb_ctx_get_ssn(ctx);
+ if (error) {
+ fprintf(stderr, "//%s: login failed, error %d\n",
+ server, error);
+ goto out;
+ }
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
+ server, "IPC$", error);
+ goto out;
+ }
+
+ /*
+ * Do some named pipe I/O.
+ */
+ error = pipetest(ctx);
+ if (error) {
+ fprintf(stderr, "pipetest, %d\n", error);
+ goto out;
+ }
+
+out:
+ smb_ctx_free(ctx);
+
+ return ((error) ? 1 : 0);
+}
+
+static void
+hexdump(const uchar_t *buf, int len) {
+ int idx;
+ char ascii[24];
+ char *pa = ascii;
+
+ memset(ascii, '\0', sizeof (ascii));
+
+ idx = 0;
+ while (len--) {
+ if ((idx & 15) == 0) {
+ printf("[%04X] ", idx);
+ pa = ascii;
+ }
+ if (*buf > ' ' && *buf <= '~')
+ *pa++ = *buf;
+ else
+ *pa++ = '.';
+ printf("%02x ", *buf++);
+
+ idx++;
+ if ((idx & 7) == 0) {
+ *pa++ = ' ';
+ putchar(' ');
+ }
+ if ((idx & 15) == 0) {
+ *pa = '\0';
+ printf("%s\n", ascii);
+ }
+ }
+
+ if ((idx & 15) != 0) {
+ *pa = '\0';
+ /* column align the last ascii row */
+ do {
+ printf(" ");
+ idx++;
+ if ((idx & 7) == 0)
+ putchar(' ');
+ } while ((idx & 15) != 0);
+ printf("%s\n", ascii);
+ }
+}
+
+/*
+ * Put a unicode UNC server name, including the null.
+ * Quick-n-dirty, just for this test...
+ */
+static int
+put_uncserver(const char *s, uchar_t *buf)
+{
+ uchar_t *p = buf;
+ char c;
+
+ *p++ = '\\'; *p++ = '\0';
+ *p++ = '\\'; *p++ = '\0';
+
+ do {
+ c = *s++;
+ if (c == '/')
+ c = '\\';
+ *p++ = c;
+ *p++ = '\0';
+
+ } while (c != 0);
+
+ return (p - buf);
+}
+
+/*
+ * Send the bind and read the ack.
+ * This tests smb_fh_xactnp.
+ */
+static int
+do_bind(int fid)
+{
+ int err, len, more;
+
+ more = 0;
+ len = sizeof (recvbuf);
+ err = smb_fh_xactnp(fid,
+ sizeof (srvsvc_bind), (char *)srvsvc_bind,
+ &len, (char *)recvbuf, &more);
+ if (err) {
+ printf("xact bind, err=%d\n", err);
+ return (err);
+ }
+ if (smb_verbose) {
+ printf("bind ack, len=%d\n", len);
+ hexdump(recvbuf, len);
+ }
+ if (more > 0) {
+ if (more > sizeof (recvbuf)) {
+ printf("bogus more=%d\n", more);
+ more = sizeof (recvbuf);
+ }
+ len = smb_fh_read(fid, 0,
+ more, (char *)recvbuf);
+ if (len == -1) {
+ err = EIO;
+ printf("read enum resp, err=%d\n", err);
+ return (err);
+ }
+ if (smb_verbose) {
+ printf("bind ack (more), len=%d\n", len);
+ hexdump(recvbuf, len);
+ }
+ }
+
+ return (0);
+}
+
+static int
+do_enum(int fid)
+{
+ int err, len, rlen, wlen;
+ uchar_t *p;
+
+ /*
+ * Build the enum request - three parts.
+ * See above: srvsvc_enum1, srvsvc_enum2
+ *
+ * First part: RPC header, etc.
+ */
+ p = sendbuf;
+ len = sizeof (srvsvc_enum1); /* 40 */
+ memcpy(p, srvsvc_enum1, len);
+ p += len;
+
+ /* Second part: UNC server name */
+ len = put_uncserver(server, p);
+ p += len;
+ sendbuf[ENUM_SLEN1_OFF] = len / 2;
+ sendbuf[ENUM_SLEN2_OFF] = len / 2;
+
+ /* Third part: level, etc. (align4) */
+ for (len = (p - sendbuf) & 3; len; len--)
+ *p++ = '\0';
+ len = sizeof (srvsvc_enum2); /* 28 */
+ memcpy(p, srvsvc_enum2, len);
+ p += len;
+
+ /*
+ * Compute total length, and fixup RPC header.
+ */
+ len = p - sendbuf;
+ sendbuf[ENUM_RPCLEN_OFF] = len;
+
+ /*
+ * Send the enum request, read the response.
+ * This tests smb_fh_write, smb_fh_read.
+ */
+ wlen = smb_fh_write(fid, 0, len, (char *)sendbuf);
+ if (wlen == -1) {
+ err = errno;
+ printf("write enum req, err=%d\n", err);
+ return (err);
+ }
+ if (wlen != len) {
+ printf("write enum req, short write %d\n", wlen);
+ return (EIO);
+ }
+
+ rlen = smb_fh_read(fid, 0,
+ sizeof (recvbuf), (char *)recvbuf);
+ if (rlen == -1) {
+ err = errno;
+ printf("read enum resp, err=%d\n", err);
+ return (err);
+ }
+
+ /* Just dump the response data. */
+ printf("enum recv, len=%d\n", rlen);
+ hexdump(recvbuf, rlen);
+
+ return (0);
+}
+
+static int
+pipetest(struct smb_ctx *ctx)
+{
+ static char path[] = "/srvsvc";
+ static uchar_t key[16];
+ int err, fd;
+
+ printf("open pipe: %s\n", path);
+ fd = smb_fh_open(ctx, path, O_RDWR);
+ if (fd < 0) {
+ perror(path);
+ return (errno);
+ }
+
+ /* Test this too. */
+ err = smb_fh_getssnkey(fd, key, sizeof (key));
+ if (err) {
+ printf("getssnkey: %d\n", err);
+ goto out;
+ }
+
+ err = do_bind(fd);
+ if (err) {
+ printf("do_bind: %d\n", err);
+ goto out;
+ }
+ err = do_enum(fd);
+ if (err)
+ printf("do_enum: %d\n", err);
+
+out:
+ smb_fh_close(fd);
+ return (0);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/test/testnp.c b/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
index 7b28194b0b..81ba8c9afc 100644
--- a/usr/src/cmd/fs.d/smbclnt/test/testnp.c
+++ b/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -93,9 +93,9 @@ static char *server;
static int pipetest(struct smb_ctx *);
static void
-testnp_usage(void)
+srvinfo_usage(void)
{
- printf("usage: testnp [-d domain][-u user][-p passwd] server\n");
+ printf("usage: srvinfo [-d domain][-u user][-p passwd] server\n");
exit(1);
}
@@ -124,18 +124,18 @@ main(int argc, char *argv[])
pw = optarg;
break;
case '?':
- testnp_usage();
+ srvinfo_usage();
break;
}
}
if (optind >= argc)
- testnp_usage();
+ srvinfo_usage();
server = argv[optind];
if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%0: -p arg requires -d dom -u usr\n",
+ fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
argv[0]);
- testnp_usage();
+ srvinfo_usage();
}
/*
@@ -236,7 +236,6 @@ static int
put_uncserver(const char *s, uchar_t *buf)
{
uchar_t *p = buf;
- int slashcnt = 0;
char c;
*p++ = '\\'; *p++ = '\0';
diff --git a/usr/src/cmd/fs.d/smbclnt/test/tconn.c b/usr/src/cmd/fs.d/smbclnt/test/tconn.c
new file mode 100644
index 0000000000..bfeac98fe0
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/test/tconn.c
@@ -0,0 +1,171 @@
+/*
+ * 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) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Test program for opening an SMB connection directly.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+
+#include <netsmb/smb_lib.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+extern int smb_iod_connect(struct smb_ctx *);
+
+static char *server;
+
+static void
+tconn_usage(void)
+{
+ printf("usage: tconn [-d domain][-u user][-p passwd] server\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, error, aflags;
+ struct smb_ctx *ctx = NULL;
+ char *dom = NULL;
+ char *usr = NULL;
+ char *pw = NULL;
+ char *secopt = NULL;
+ struct addrinfo *ai;
+
+ while ((c = getopt(argc, argv, "vd:p:s:u:")) != -1) {
+ switch (c) {
+ case 'v':
+ smb_debug = 1;
+ smb_verbose = 1;
+ break;
+
+ case 'd':
+ dom = optarg;
+ break;
+ case 'u':
+ usr = optarg;
+ break;
+ case 'p':
+ pw = optarg;
+ break;
+ case 's':
+ secopt = optarg;
+ break;
+ case '?':
+ tconn_usage();
+ break;
+ }
+ }
+ if (optind >= argc)
+ tconn_usage();
+ server = argv[optind];
+
+ if (pw != NULL && (dom == NULL || usr == NULL)) {
+ fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
+ argv[0]);
+ tconn_usage();
+ }
+
+ /*
+ * This section is intended to demonstrate how an
+ * RPC client library might use this interface.
+ */
+ error = smb_ctx_alloc(&ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
+ goto out;
+ }
+
+ /*
+ * Set server, share, domain, user
+ * (in the ctx handle).
+ */
+ smb_ctx_setfullserver(ctx, server);
+ smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+ if (dom)
+ smb_ctx_setdomain(ctx, dom, B_TRUE);
+ if (usr)
+ smb_ctx_setuser(ctx, usr, B_TRUE);
+ if (pw)
+ smb_ctx_setpassword(ctx, pw, NULL);
+
+ /*
+ * Hackish option to override the Authentication Type flags.
+ * Sorry about exposing the flag values here, but this is
+ * really a programmer's test tool. See smbfs_api.h for
+ * the SMB_AT_... flag values.
+ */
+ if (secopt != NULL) {
+ aflags = atoi(secopt);
+ if (aflags < 1 || aflags > 0x1f) {
+ fprintf(stderr, "%s: -s {0..31}\n", argv[0]);
+ tconn_usage();
+ }
+ smb_ctx_setauthflags(ctx, aflags);
+ }
+
+ /*
+ * Resolve the server address,
+ * setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
+ goto out;
+ }
+
+ if ((ai = ctx->ct_addrinfo) == NULL) {
+ fprintf(stderr, "%s: no ct_addrinfo\n", argv[0]);
+ goto out;
+ }
+ memcpy(&ctx->ct_srvaddr, ai->ai_addr, ai->ai_addrlen);
+
+ /*
+ * If this code were in smbutil or mount_smbfs, it would
+ * get system and $HOME/.nsmbrc settings here, like this:
+ */
+ error = smb_iod_connect(ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_iod_connect failed\n", argv[0]);
+ goto out;
+ }
+
+ printf("Yea, we connected!\n");
+
+out:
+ smb_ctx_free(ctx);
+
+ return ((error) ? 1 : 0);
+}
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index 02eb6106c2..c1dc6886ac 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.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 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -115,10 +115,11 @@ struct smb_ctx {
/* Strings from the SMB negotiate response. */
char *ct_srv_OS;
char *ct_srv_LM;
+ uint32_t ct_clnt_caps;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
- uchar_t ct_ntlm_chal[NTLM_CHAL_SZ];
+ uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
/* See ssp.c */
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index d0f4e2b228..c2ccc3361d 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -460,76 +461,68 @@ smb_iod_connect(smb_ctx_t *ctx)
}
/*
- * SMB Negotiate Protocol and
- * SMB Session Setup, one of 3 ways:
- * NULL session
- * Extended security,
- * NTLM (v2, v1)
- *
+ * Do SMB Negotiate Protocol.
+ */
+ err = smb_negprot(ctx, &blob);
+ if (err)
+ goto out;
+
+ /*
* Empty user name means an explicit request for
- * NULL session setup. No fall-back logic here.
- *
- * For NULL session, don't offer extended security.
- * That's a lot simpler than dealing with NTLMSSP.
+ * NULL session setup, which is a special case.
+ * If negotiate determined that we want to do
+ * SMB signing, we have to turn that off for a
+ * NULL session. [MS-SMB 3.3.5.3].
*/
if (ctx->ct_user[0] == '\0') {
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- err = smb_negprot(ctx, &blob);
- if (err)
- goto out;
- err = smb_ssnsetup_null(ctx);
- } else {
- /*
- * Do SMB Negotiate Protocol.
- */
- err = smb_negprot(ctx, &blob);
- if (err)
- goto out;
+ /* Null user should have null domain too. */
+ ctx->ct_domain[0] = '\0';
+ ctx->ct_authflags = SMB_AT_ANON;
+ ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
+ ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
+ }
+ /*
+ * Do SMB Session Setup (authenticate)
+ *
+ * If the server negotiated extended security,
+ * run the SPNEGO state machine, otherwise do
+ * one of the old-style variants.
+ */
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ } else {
/*
- * Do SMB Session Setup (authenticate)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine.
+ * Server did NOT negotiate extended security.
+ * Try NTLMv2, NTLMv1, or ANON (if enabled).
*/
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
+ 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 {
/*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1 (if enabled).
+ * Don't return EAUTH, because a new
+ * password prompt will not help.
*/
- if ((ctx->ct_authflags &
- (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
- /*
- * Don't return EAUTH, because a
- * new password will not help.
- */
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
- goto out;
- }
- if (ctx->ct_authflags & SMB_AT_NTLM2)
- err = smb_ssnsetup_ntlm2(ctx);
- else
- err = EAUTH;
- if (err == EAUTH && 0 !=
- (ctx->ct_authflags & SMB_AT_NTLM1))
- err = smb_ssnsetup_ntlm1(ctx);
+ DPRINT("No NTLM authflags");
+ err = ENOTSUP;
}
}
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
-
out:
mb_done(&blob);
if (err) {
close(ctx->ct_tran_fd);
ctx->ct_tran_fd = -1;
- } else
+ } else {
+ /* Tell library code we have a session. */
+ ctx->ct_flags |= SMBCF_SSNACTIVE;
DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+ }
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/crypt.c b/usr/src/lib/libsmbfs/smb/crypt.c
index ea1d7e6dd1..13569c1b8c 100644
--- a/usr/src/lib/libsmbfs/smb/crypt.c
+++ b/usr/src/lib/libsmbfs/smb/crypt.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -29,7 +30,7 @@
*
* Some code copied from the server: libsmb smb_crypt.c
* with minor changes, i.e. errno.h return values.
- * XXX: Move this to a common library (later).
+ * XXX: Later, make the server use these.
*/
#include <sys/types.h>
@@ -67,13 +68,21 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
int K, D;
int k, d;
- /* Calculate proper number of iterations */
+ /*
+ * Calculate proper number of iterations.
+ * Known call cases include:
+ * ResultLen=16, KeyLen=14, DataLen=8
+ * ResultLen=24, KeyLen=21, DataLen=8
+ * ResultLen=16, KeyLen=14, DataLen=16
+ */
K = KeyLen / 7;
D = DataLen / 8;
-
- if (ResultLen < (K * 8 * D)) {
+ if ((KeyLen % 7) || (DataLen % 8))
+ return (EINVAL);
+ if (K == 0 || D == 0)
+ return (EINVAL);
+ if (ResultLen < (K * 8))
return (EINVAL);
- }
/*
* Use SUNW convenience function to initialize the cryptoki
@@ -88,7 +97,10 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
return (ENOTSUP);
}
- for (k = 0; k < K; k++) {
+ for (d = k = 0; k < K; k++, d++) {
+ /* Cycle the input again, as necessary. */
+ if (d == D)
+ d = 0;
smb_initlmkey(des_key, &Key[k * 7]);
rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
des_key, 8, &hKey);
@@ -102,18 +114,18 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
error = EIO;
goto exit_encrypt;
}
- ciphertext_len = DataLen;
- for (d = 0; d < D; d++) {
- /* Read in the data and encrypt this portion */
- rv = C_EncryptUpdate(hSession,
- (CK_BYTE_PTR)Data + (d * 8), 8,
- &Result[(k * (8 * D)) + (d * 8)],
- &ciphertext_len);
- if (rv != CKR_OK) {
- error = EIO;
- goto exit_encrypt;
- }
+ ciphertext_len = 8;
+
+ /* Read in the data and encrypt this portion */
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data + (d * 8), 8,
+ (CK_BYTE_PTR)Result + (k * 8),
+ &ciphertext_len);
+ if (rv != CKR_OK) {
+ error = EIO;
+ goto exit_encrypt;
}
+
(void) C_DestroyObject(hSession, hKey);
}
goto exit_session;
@@ -149,6 +161,59 @@ smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
}
/*
+ * CKM_RC4
+ */
+int
+smb_encrypt_RC4(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_SESSION_HANDLE hSession;
+ CK_ULONG ciphertext_len;
+ int error = EIO;
+
+ /*
+ * Use SUNW convenience function to initialize the cryptoki
+ * library, and open a session with a slot that supports
+ * the mechanism we plan on using.
+ */
+ mechanism.mechanism = CKM_RC4;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK) {
+ return (ENOTSUP);
+ }
+
+ rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+ Key, KeyLen, &hKey);
+ if (rv != CKR_OK)
+ goto exit_session;
+
+ /* Initialize the encryption operation in the session */
+ rv = C_EncryptInit(hSession, &mechanism, hKey);
+ if (rv != CKR_OK)
+ goto exit_encrypt;
+
+ ciphertext_len = ResultLen;
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data, DataLen,
+ (CK_BYTE_PTR)Result, &ciphertext_len);
+ if (rv == CKR_OK)
+ error = 0;
+
+exit_encrypt:
+ (void) C_DestroyObject(hSession, hKey);
+exit_session:
+ (void) C_CloseSession(hSession);
+
+ return (error);
+}
+
+/*
* Get some random bytes from /dev/urandom
*
* There may be a preferred way to call this via libpkcs11
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 81e4241aa5..e68213b6ef 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -1121,13 +1121,7 @@ smb_ctx_resolve(struct smb_ctx *ctx)
* check for a keychain entry.
* XXX: Only for auth NTLM?
*/
- if (ctx->ct_user[0] == '\0') {
- /*
- * No user name (anonymous session).
- * The minauth checks do not apply.
- */
- ctx->ct_authflags = SMB_AT_ANON;
- } else {
+ if (ctx->ct_user[0] != '\0') {
/*
* Have a user name.
* If we don't have a p/w yet,
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
index 9345cd8c47..770b742c44 100644
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ b/usr/src/lib/libsmbfs/smb/negprot.c
@@ -32,11 +32,11 @@
/*
* 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.
- * Copied from the driver: smb_smb.c
*/
#include <errno.h>
@@ -66,6 +66,7 @@
#include <netsmb/smb_dev.h>
#include "charsets.h"
+#include "smb_crypt.h"
#include "private.h"
/*
@@ -87,6 +88,13 @@ static struct smb_dialect smb_dialects[] = {
#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
@@ -118,9 +126,16 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
* 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;
- ctx->ct_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_ERR_STATUS | SMB_FLAGS2_UNICODE;
+ 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?
@@ -362,7 +377,7 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
err = EBADRPC;
goto errout;
}
- err = md_get_mem(mbp, ctx->ct_ntlm_chal,
+ err = md_get_mem(mbp, ctx->ct_srv_chal,
NTLM_CHAL_SZ, MB_MSYSTEM);
/*
* Server domain follows (ignored)
@@ -423,6 +438,15 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
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:
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index bee189561e..9f08a2eaca 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -62,10 +63,11 @@
/*
* ntlm_compute_lm_hash
*
- * Compute an LM hash given a password
+ * Given a password, compute the LM hash.
+ * a.k.a. ResponseKeyLM in [MS-NLMP]
*
* Output:
- * hash: 16-byte "LanMan" (LM) hash.
+ * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash)
* Inputs:
* ucpw: User's password, upper-case UTF-8 string.
*
@@ -102,10 +104,11 @@ ntlm_compute_lm_hash(uchar_t *hash, const char *pass)
/*
* ntlm_compute_nt_hash
*
- * Compute an NT hash given a password in UTF-8.
+ * Given a password, compute the NT hash.
+ * a.k.a. the ResponseKeyNT in [MS-NLMP]
*
* Output:
- * hash: 16-byte "NT" hash.
+ * hash: 16-byte "NT" hash (normally ctx->ct_nthash)
* Inputs:
* upw: User's password, mixed-case UCS-2LE.
* pwlen: Size (in bytes) of upw
@@ -134,6 +137,7 @@ ntlm_compute_nt_hash(uchar_t *hash, const char *pass)
/*
* ntlm_v1_response
+ * a.k.a. DESL() in [MS-NLMP]
*
* Create an LM response from the given LM hash and challenge,
* or an NTLM repsonse from a given NTLM hash and challenge.
@@ -194,32 +198,103 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
return (err);
/*
- * Compute the LM response, derived
- * from the challenge and the ASCII
- * password (if authflags allow).
+ * Compute the NTLM response, derived from
+ * the challenge and the NT hash (a.k.a ResponseKeyNT)
+ */
+ err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
+ if (err)
+ return (err);
+ bzero(ntresp, NTLM_V1_RESP_SZ);
+ err = ntlm_v1_response(ntresp, ctx->ct_nthash,
+ ctx->ct_srv_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Compute the LM response, derived from
+ * the challenge and the ASCII password.
+ * Per. [MS-NLMP 3.3.1] if NoLmResponse,
+ * send the NT response for both NT+LM.
*/
err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
if (err)
return (err);
- bzero(lmresp, NTLM_V1_RESP_SZ);
+ memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ);
if (ctx->ct_authflags & SMB_AT_LM1) {
/* They asked to send the LM hash too. */
err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
- ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ ctx->ct_srv_chal, NTLM_CHAL_SZ);
if (err)
return (err);
}
/*
- * Compute the NTLM response, derived from
- * the challenge and the NT hash.
+ * Compute the session key
+ */
+ ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+
+ return (err);
+}
+
+/*
+ * Compute both the LM(v1x) response and the NTLM(v1x) response,
+ * and put them in the mbdata chains passed. "v1x" here refers to
+ * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP,
+ * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2.
+ * [MS-NLMP 3.3.1]
+ *
+ * This allocates mbuf chains in the output args (caller frees).
+ */
+int
+ntlm_put_v1x_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+ MD5_CTX context;
+ uchar_t challenges[2 * NTLM_CHAL_SZ];
+ uchar_t digest[NTLM_HASH_SZ];
+ uchar_t *lmresp, *ntresp;
+ int err;
+
+ /* Get mbuf chain for the LM response. */
+ if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /* Get mbuf chain for the NT response. */
+ if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /*
+ * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
+ */
+ memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+ memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ);
+
+ /*
+ * digest = MD5(challenges)
+ */
+ MD5Init(&context);
+ MD5Update(&context, challenges, sizeof (challenges));
+ MD5Final(digest, &context);
+
+ /*
+ * Compute the NTLM response, derived from the
+ * NT hash (a.k.a ResponseKeyNT) and the first
+ * 8 bytes of the MD5 digest of the challenges.
*/
err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
if (err)
return (err);
bzero(ntresp, NTLM_V1_RESP_SZ);
err = ntlm_v1_response(ntresp, ctx->ct_nthash,
- ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ digest, NTLM_CHAL_SZ);
+
+ /*
+ * With "Extended Session Security", the LM response
+ * is simply the client challenge (nonce) padded out.
+ */
+ err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
+ if (err)
+ return (err);
+ bzero(lmresp, NTLM_V1_RESP_SZ);
+ memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ);
/*
* Compute the session key
@@ -410,22 +485,22 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
uchar_t v2hash[NTLM_HASH_SZ];
struct mbuf *tim = ti_mbp->mb_top;
- if ((err = mb_init(lm_mbp)) != 0)
- return (err);
- if ((err = mb_init(nt_mbp)) != 0)
- return (err);
-
/*
* Convert the user name to upper-case, as
* that's what's used when computing LMv2
* and NTLMv2 responses. Note that the
* domain name is NOT upper-cased!
*/
+ if (ctx->ct_user[0] == '\0')
+ return (EINVAL);
ucuser = utf8_str_toupper(ctx->ct_user);
- if (ucuser == NULL) {
- err = ENOMEM;
+ if (ucuser == NULL)
+ return (ENOMEM);
+
+ if ((err = mb_init(lm_mbp)) != 0)
+ goto out;
+ if ((err = mb_init(nt_mbp)) != 0)
goto out;
- }
/*
* Compute the NTLMv2 hash
@@ -444,10 +519,9 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
* 1: 16-byte response hash
* 2: Client nonce
*/
- lmresp = (uchar_t *)lm_mbp->mb_pos;
- mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM);
+ lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ);
err = ntlm_v2_resp_hash(lmresp,
- v2hash, ctx->ct_ntlm_chal,
+ v2hash, ctx->ct_srv_chal,
ctx->ct_clnonce, NTLM_CHAL_SZ);
if (err)
goto out;
@@ -462,10 +536,9 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
* 1: 16-byte response hash
* 2: "target info." blob
*/
- ntresp = (uchar_t *)nt_mbp->mb_pos;
- mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM);
+ ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ);
err = ntlm_v2_resp_hash(ntresp,
- v2hash, ctx->ct_ntlm_chal,
+ v2hash, ctx->ct_srv_chal,
(uchar_t *)tim->m_data, tim->m_len);
if (err)
goto out;
@@ -533,14 +606,6 @@ ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
return (err);
/*
- * Construct the client nonce by getting
- * some random data from /dev/urandom
- */
- err = smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
- if (err)
- goto out;
-
- /*
* Get the "NT time" for the target info header.
*/
(void) gettimeofday(&now, 0);
@@ -583,3 +648,48 @@ out:
free(ucdom);
return (err);
}
+
+/*
+ * 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)
+{
+ uchar_t data[NTLM_HASH_SZ];
+ uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
+
+ /* concat(ServerChallenge, LmResponse[0..7]) */
+ memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+ memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
+
+ /* HMAC_MD5(SessionBaseKey, concat(...)) */
+ HMACT64(kxkey, ctx->ct_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 e8eae559e9..447033b516 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLM_H
@@ -59,7 +60,17 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
struct mbdata *lm_mbp, struct mbdata *nt_mbp);
int
+ntlm_put_v1x_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+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);
+
+void
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, 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 5766ec835c..f39fa594ec 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,16 +59,22 @@
#include "private.h"
#include "charsets.h"
+#include "smb_crypt.h"
#include "spnego.h"
#include "derparse.h"
#include "ssp.h"
#include "ntlm.h"
#include "ntlmssp.h"
+/* A shorter alias for a crazy long name from [MS-NLMP] */
+#define NTLMSSP_NEGOTIATE_NTLM2 \
+ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+
typedef struct ntlmssp_state {
uint32_t ss_flags;
- char *ss_target_name;
+ char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
/*
@@ -83,6 +89,10 @@ struct sec_buf {
#define ID_SZ 8
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);
+
/*
* Get a "security buffer" (header part)
*/
@@ -147,10 +157,12 @@ mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
static int
mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
{
- int cnt0, err;
+ int cnt0;
+ int err = 0;
sb->sb_offset = cnt0 = mbp->mb_count;
- err = mb_put_mbuf(mbp, m);
+ if (m != NULL)
+ err = mb_put_mbuf(mbp, m);
sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
return (err);
@@ -164,31 +176,35 @@ mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
*/
static int
mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
- const char *s, int unicode)
+ const char *str, int unicode)
{
int err, trim;
struct mbdata tmp_mb;
- /*
- * Put the string into a temp. mbuf,
- * then chop off the null terminator
- * before appending to caller's mbp.
- */
- err = mb_init(&tmp_mb);
- if (err)
- return (err);
- err = mb_put_string(&tmp_mb, s, unicode);
- if (err)
- return (err);
+ bzero(&tmp_mb, sizeof (tmp_mb));
- trim = (unicode) ? 2 : 1;
- if (tmp_mb.mb_cur->m_len < trim)
- return (EFAULT);
- tmp_mb.mb_cur->m_len -= trim;
+ if (str != NULL && *str != '\0') {
+ /*
+ * Put the string into a temp. mbuf,
+ * then chop off the null terminator
+ * before appending to caller's mbp.
+ */
+ err = mb_init(&tmp_mb);
+ if (err)
+ return (err);
+ err = mb_put_string(&tmp_mb, str, unicode);
+ if (err)
+ return (err);
+
+ trim = (unicode) ? 2 : 1;
+ if (tmp_mb.mb_cur->m_len < trim)
+ trim = 0;
+ tmp_mb.mb_cur->m_len -= trim;
+ }
err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
/*
- * Note: tmp_mb.mb_top is consumed,
+ * Note: tmp_mb.mb_top (if any) is consumed,
* so do NOT free it (no mb_done)
*/
return (err);
@@ -215,60 +231,47 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
ntlmssp_state_t *ssp_st = sp->sp_private;
- char *ucdom = NULL;
- char *ucwks = NULL;
if ((err = mb_init(&mb2)) != 0)
return (err);
mb2.mb_count = sizeof (hdr);
/*
- * Initialize the negotiation flags, and
- * save what we sent. For reference:
- * [MS-NLMP] spec. (also ntlmssp.h)
+ * The initial negotiation flags represent the union of all
+ * options we support. The server selects from these.
+ * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
*/
ssp_st->ss_flags =
+ NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_OEM |
NTLMSSP_REQUEST_TARGET |
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL |
+ /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- NTLMSSP_NEGOTIATE_TARGET_INFO |
+ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
+ NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
- else
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
-
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_authflags & SMB_AT_NTLM2)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
- if (ctx->ct_authflags & SMB_AT_NTLM1)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
-
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
- hdr.h_type = 1; /* Type 1 */
+ hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
hdr.h_flags = ssp_st->ss_flags;
/*
- * Put the client domain, client name strings.
- * These are always in OEM format, upper-case.
+ * We could put the client domain, client name strings
+ * here, (always in OEM format, upper-case), and set
+ * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
+ * leaves these NULL so let's do the same.
*/
- ucdom = utf8_str_toupper(ctx->ct_domain);
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucdom == NULL || ucwks == NULL) {
- err = ENOMEM;
- goto out;
- }
- err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
- if (err)
- goto out;
- err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
- if (err)
- goto out;
+ (void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
+ (void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
/*
* Marshal the header (in LE order)
@@ -282,10 +285,6 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
err = mb_put_mbuf(out_mb, mb2.mb_top);
-out:
- free(ucdom);
- free(ucwks);
-
return (err);
}
@@ -329,7 +328,7 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
bzero(&hdr, sizeof (hdr));
(void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
(void) md_get_uint32le(in_mb, &hdr.h_type);
- if (hdr.h_type != 2) {
+ if (hdr.h_type != NTLMSSP_MSGTYPE_CHALLENGE) {
err = EPROTO;
goto out;
}
@@ -338,11 +337,17 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
(void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM);
/*
- * Save flags, challenge for later.
+ * Save flags, server challenge for later.
*/
ssp_st->ss_flags = hdr.h_flags;
+ bcopy(&hdr.h_challenge, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Turn off flags that might have been given but
+ * that we don't want to send with authenticate.
+ */
uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
- bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
/*
* Now find out if the optional parts are there.
@@ -355,8 +360,9 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
}
/*
- * Get the target name string. First get a copy of
- * the data from the offset/length indicated in the
+ * Get the target name string. (Server name or
+ * Primary domain name.) First get a copy of the
+ * data from the offset/length indicated in the
* security buffer header; then parse the string.
*/
err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m);
@@ -401,19 +407,24 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
struct sec_buf h_wksta;
struct sec_buf h_ssn_key;
uint32_t h_flags;
+ /* Version struct (ommitted) */
+ uchar_t h_mic[NTLM_HASH_SZ];
} hdr;
struct mbdata lm_mbc; /* LM response */
struct mbdata nt_mbc; /* NT response */
struct mbdata ti_mbc; /* target info */
+ struct mbdata ek_mbc; /* encrypted session key */
struct mbdata mb2; /* payload */
int err, uc;
struct smb_ctx *ctx = sp->smb_ctx;
ntlmssp_state_t *ssp_st = sp->sp_private;
+ uchar_t *pmic;
bzero(&hdr, sizeof (hdr));
bzero(&lm_mbc, sizeof (lm_mbc));
bzero(&nt_mbc, sizeof (nt_mbc));
bzero(&ti_mbc, sizeof (ti_mbc));
+ bzero(&ek_mbc, sizeof (ek_mbc));
bzero(&mb2, sizeof (mb2));
/*
@@ -425,27 +436,78 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
- hdr.h_type = 3; /* Type 3 */
+ hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
hdr.h_flags = ssp_st->ss_flags;
/*
- * Put the LMv2,NTLMv2 responses, or
- * possibly LM, NTLM (v1) responses.
+ * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
+ * and compute the session key, etc.
*/
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- /* Build the NTLMv2 "target info" blob. */
+ if (ctx->ct_authflags & SMB_AT_ANON) {
+ /*
+ * 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.
+ */
+ hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~(
+ NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH);
+ err = 0;
+ } else if (ctx->ct_authflags & SMB_AT_NTLM2) {
+ /*
+ * Doing NTLMv2/LMv2
+ */
err = ntlm_build_target_info(ctx,
ssp_st->ss_target_info, &ti_mbc);
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
&lm_mbc, &nt_mbc);
+ 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) {
+ /*
+ * Doing NTLM ("v1x") which is NTLM with
+ * "Extended Session Security"
+ */
+ err = ntlm_put_v1x_responses(ctx,
+ &lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+ /* Compute the "Key exchange key". */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
} else {
+ /*
+ * Doing plain old NTLM (and LM if enabled)
+ */
err = ntlm_put_v1_responses(ctx,
&lm_mbc, &nt_mbc);
+ 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);
+ }
+
+ /*
+ * Compute the "Exported Session Key" and (possibly)
+ * the "Encrypted Random Sesion Key".
+ * [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);
+ if (err)
+ goto out;
+ } else {
+ /* ExportedSessionKey is the KeyExchangeKey */
+ memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ /* EncryptedRandomSessionKey remains NULL */
}
- if (err)
- goto out;
err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
lm_mbc.mb_top = NULL; /* consumed */
@@ -470,12 +532,13 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
goto out;
/*
- * Put the "Random Session Key". We don't set
- * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty.
- * (In-line mb_put_sb_data here.)
+ * Put the "Encrypted Random Session Key", if any.
+ * (ek_mbc.mb_top may be NULL)
*/
- hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0;
- hdr.h_ssn_key.sb_offset = mb2.mb_count;
+ err = mb_put_sb_data(&mb2, &hdr.h_ssn_key, ek_mbc.mb_top);
+ ek_mbc.mb_top = NULL; /* consumed (if any) */
+ if (err)
+ goto out;
/*
* Marshal the header (in LE order)
@@ -494,14 +557,58 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
(void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key);
(void) mb_put_uint32le(out_mb, hdr.h_flags);
+ /* Put zeros for the MIC - filled in later */
+ pmic = mb_reserve(out_mb, NTLM_HASH_SZ);
+
+ /* Put the payload. */
err = mb_put_mbuf(out_mb, mb2.mb_top);
mb2.mb_top = NULL; /* consumed */
+ /*
+ * Compute the MIC and stuff that in...
+ * The MIC is apparently optional.
+ */
+ (void) pmic;
+
out:
mb_done(&mb2);
mb_done(&lm_mbc);
mb_done(&nt_mbc);
mb_done(&ti_mbc);
+ mb_done(&ek_mbc);
+
+ return (err);
+}
+
+/*
+ * Helper for ntlmssp_put_type3 when doing key exchange.
+ *
+ * "ExportedSessionKey" is what we give to the "application"
+ * layer, which in here means the MAC key for SMB signing.
+ * With "key exchange", we replace the ExportedSessionKey
+ * with random data and send that (encrypted) to the peer.
+ */
+static int
+ntlm_rand_ssn_key(
+ struct smb_ctx *ctx,
+ ntlmssp_state_t *ssp_st,
+ struct mbdata *ek_mbp)
+{
+
+ uchar_t *encr_ssn_key;
+ int err;
+
+ if ((err = mb_init(ek_mbp)) != 0)
+ return (err);
+ 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);
+
+ /* 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);
return (err);
}
@@ -623,9 +730,9 @@ ntlmssp_init_client(struct ssp_ctx *sp)
ntlmssp_state_t *ssp_st;
if ((sp->smb_ctx->ct_authflags &
- (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+ (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
- return (ENOTSUP);
+ return (EINVAL);
}
ssp_st = calloc(1, sizeof (*ssp_st));
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.h b/usr/src/lib/libsmbfs/smb/ntlmssp.h
index 591b1ab088..5f3e09ac0d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.h
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.h
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLMSSP_H
@@ -37,6 +38,14 @@
*/
/*
+ * NTLMSSP Message Types
+ * [MS-NLMP] sec. 2.2.1
+ */
+#define NTLMSSP_MSGTYPE_NEGOTIATE 1
+#define NTLMSSP_MSGTYPE_CHALLENGE 2
+#define NTLMSSP_MSGTYPE_AUTHENTICATE 3
+
+/*
* NTLMSSP Negotiate Flags
* [MS-NLMP] sec. 2.2.2.5
*/
@@ -48,13 +57,13 @@
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
-/* reserved 0x00000100 */
+/* reserved (netware) 0x00000100 */
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
#define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400
-/* old anonymous_session (ignored by servers) 0x00000800 */
+#define NTLMSSP_NEGOTIATE_NULL_SESSION 0x00000800
#define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000
#define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000
-/* reserved 0x00004000 */
+/* reserved (local caller) 0x00004000 */
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
diff --git a/usr/src/lib/libsmbfs/smb/smb_crypt.h b/usr/src/lib/libsmbfs/smb/smb_crypt.h
index 15005ddab6..a3ebd69e22 100644
--- a/usr/src/lib/libsmbfs/smb/smb_crypt.h
+++ b/usr/src/lib/libsmbfs/smb/smb_crypt.h
@@ -33,17 +33,36 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
+#ifndef _SMB_CRYPT_H
+#define _SMB_CRYPT_H
+
/*
* Various crypto stuff.
* from the driver: smb_crypt.c
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int
smb_encrypt_DES(uchar_t *Result, int ResultLen,
const uchar_t *Key, int KeyLen,
const uchar_t *Data, int DataLen);
int
+smb_encrypt_RC4(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen);
+
+int
smb_get_urandom(void *data, size_t dlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_CRYPT_H */
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
index 03f92dc62c..68e7ce1337 100644
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c
@@ -32,11 +32,11 @@
/*
* 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.
- * Copied from the driver: smb_smb.c
*/
#include <errno.h>
@@ -88,7 +88,7 @@ smb_ssnsetup_null(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -118,7 +118,7 @@ smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -133,30 +133,11 @@ smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
if (err)
goto out;
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
(ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- struct mbuf *m = nt_mbc.mb_top;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
+ err = ntlm_build_mac_key(ctx, &nt_mbc);
+ if (err)
goto out;
- }
- p = ctx->ct_mackey;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
/* OK, start signing! */
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
@@ -187,7 +168,7 @@ smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -208,30 +189,11 @@ smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
if (err)
goto out;
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
(ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- struct mbuf *m = nt_mbc.mb_top;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
+ err = ntlm_build_mac_key(ctx, &nt_mbc);
+ if (err)
goto out;
- }
- p = ctx->ct_mackey;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
/* OK, start signing! */
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
@@ -334,20 +296,7 @@ smb__ssnsetup(struct smb_ctx *ctx,
uint16_t bc, len1, len2, sblen;
uint8_t wc;
- /*
- * Some of the "capability" bits we offer will be copied
- * from those offered by the server, with a mask applied.
- * This is the mask of capabilies copied from the server.
- * Some others get special handling below.
- */
- static const uint32_t caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32 |
- SMB_CAP_EXT_SECURITY;
-
- caps = ctx->ct_sopt.sv_caps & caps_mask;
+ caps = ctx->ct_clnt_caps;
uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
index 7b7f222d2d..63f2543780 100644
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
@@ -19,7 +19,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -79,7 +79,6 @@ SYMBOL_VERSION SUNWprivate {
smb_auth_ntlm_hash;
smb_auth_ntlmv2_hash;
smb_auth_qnd_unicode;
- smb_auth_set_info;
smb_auth_validate_lm;
smb_auth_validate_nt;
smb_buf32_xdr;