diff options
author | Gordon Ross <gwr@nexenta.com> | 2013-07-16 22:10:42 -0400 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2014-11-12 14:29:11 -0500 |
commit | 85e6b6747d07050e01ec91acef2453655821f9ab (patch) | |
tree | b2531706b2e44cbeaad4a5b157ddffbae7e8406f /usr/src | |
parent | fd75ca8de430ee0ba5ce650efee0ac0b85ed43e9 (diff) | |
download | illumos-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/Makefile | 56 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/test/srvenum.c | 436 | ||||
-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.c | 171 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/netsmb/smb_lib.h | 5 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/connect.c | 95 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/crypt.c | 99 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ctx.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/negprot.c | 34 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlm.c | 178 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlm.h | 11 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlmssp.c | 257 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlmssp.h | 15 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/smb_crypt.h | 19 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ssnsetup.c | 73 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libsmb/common/mapfile-vers | 3 |
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; |