summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.c87
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.h1
-rw-r--r--usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c3
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/Makefile15
-rwxr-xr-xusr/src/cmd/smbsrv/fksmbd/Run.sh19
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c22
-rw-r--r--usr/src/cmd/smbsrv/smbd/Makefile14
-rw-r--r--usr/src/cmd/smbsrv/smbd/server.xml2
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd.h6
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_authsvc.c973
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_authsvc.h82
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c24
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_krb5ssp.c350
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_logon.c23
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_main.c17
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_ntlmssp.c595
-rw-r--r--usr/src/common/smbsrv/smb_msgbuf.c267
-rw-r--r--usr/src/common/smbsrv/smb_token.c13
-rw-r--r--usr/src/common/smbsrv/smb_token_xdr.c16
-rw-r--r--usr/src/lib/Makefile5
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c10
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c7
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c35
-rw-r--r--usr/src/lib/libshare/smb/Makefile.com5
-rw-r--r--usr/src/lib/libsmbfs/Makefile5
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com4
-rw-r--r--usr/src/lib/libsmbfs/netsmb/ntlmssp.h (renamed from usr/src/lib/libsmbfs/smb/ntlmssp.h)29
-rw-r--r--usr/src/lib/libsmbfs/netsmb/spnego.h260
-rw-r--r--usr/src/lib/libsmbfs/smb/derparse.c92
-rw-r--r--usr/src/lib/libsmbfs/smb/derparse.h8
-rw-r--r--usr/src/lib/libsmbfs/smb/llib-lsmbfs3
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers16
-rw-r--r--usr/src/lib/libsmbfs/smb/spnego.c119
-rw-r--r--usr/src/lib/libsmbfs/smb/spnego.h244
-rw-r--r--usr/src/lib/libsmbfs/smb/spnegoparse.c94
-rw-r--r--usr/src/lib/libsmbfs/smb/spnegoparse.h7
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/Makefile.com1
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers3
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c97
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c122
-rw-r--r--usr/src/lib/smbsrv/libsmb/Makefile.com7
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/libsmb.h61
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/mapfile-vers11
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_auth.c241
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_cfg.c44
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_info.c24
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_kmod.c11
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_mac.c207
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c23
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h8
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c29
-rwxr-xr-xusr/src/tools/quick/make-smbsrv18
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_authenticate.c706
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_cred.c157
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c25
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_negotiate.c104
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c15
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c92
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c600
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_signing.c171
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c239
-rw-r--r--usr/src/uts/common/gssapi/Makefile11
-rw-r--r--usr/src/uts/common/gssapi/gen_oids.c13
-rw-r--r--usr/src/uts/common/smbsrv/Makefile2
-rw-r--r--usr/src/uts/common/smbsrv/ndl/netlogon.ndl22
-rw-r--r--usr/src/uts/common/smbsrv/netrauth.h28
-rw-r--r--usr/src/uts/common/smbsrv/smb.h19
-rw-r--r--usr/src/uts/common/smbsrv/smb_ioctl.h9
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h12
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h39
-rw-r--r--usr/src/uts/common/smbsrv/smb_signing.h8
-rw-r--r--usr/src/uts/common/smbsrv/smb_token.h82
-rw-r--r--usr/src/uts/common/smbsrv/smbinfo.h9
77 files changed, 4999 insertions, 1757 deletions
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c
index b8c2867489..a95441d4b9 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c
@@ -89,46 +89,52 @@ struct enum_lookup_map trust_dir_map[] = {
};
static int
-generate_machine_sid(char **machine_sid)
+generate_machine_uuid(char **machine_uuid)
{
- char *p;
uuid_t uu;
- int i, j, len, rlen;
- uint32_t rid;
- /*
- * Generate and split 128-bit UUID into three 32-bit RIDs The
- * machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's
- * four RIDs altogether).
- *
- * Technically we could use up to 14 random RIDs here, but it
- * turns out that with some versions of Windows using SIDs with
- * more than five RIDs in security descriptors causes problems.
- */
-
- *machine_sid = calloc(1, MACHINE_SID_LEN);
- if (*machine_sid == NULL) {
+ *machine_uuid = calloc(1, UUID_PRINTABLE_STRING_LENGTH + 1);
+ if (*machine_uuid == NULL) {
idmapdlog(LOG_ERR, "Out of memory");
return (-1);
}
- (void) strcpy(*machine_sid, "S-1-5-21");
- p = *machine_sid + strlen("S-1-5-21");
- len = MACHINE_SID_LEN - strlen("S-1-5-21");
uuid_clear(uu);
- uuid_generate_random(uu);
+ uuid_generate_time(uu);
+ uuid_unparse(uu, *machine_uuid);
+
+ return (0);
+}
+
+static int
+generate_machine_sid(char **machine_sid, char *machine_uuid)
+{
+ union {
+ uuid_t uu;
+ uint32_t v[4];
+ } uv;
+ int len;
+
+ /*
+ * Split the 128-bit machine UUID into three 32-bit values
+ * we'll use as the "sub-authorities" of the machine SID.
+ * The machine_sid will have the form S-1-5-21-J-K-L
+ * (that's four sub-authorities altogether) where:
+ * J = last 4 bytes of node_addr,
+ * K = time_mid, time_hi_and_version
+ * L = time_low
+ * (see struct uuid)
+ */
+
+ (void) memset(&uv, 0, sizeof (uv));
+ (void) uuid_parse(machine_uuid, uv.uu);
-#if UUID_LEN != 16
-#error UUID size is not 16!
-#endif
+ len = asprintf(machine_sid, "S-1-5-21-%u-%u-%u",
+ uv.v[3], uv.v[0], uv.v[1]);
- for (i = 0; i < 3; i++) {
- j = i * 4;
- rid = (uu[j] << 24) | (uu[j + 1] << 16) |
- (uu[j + 2] << 8) | (uu[j + 3]);
- rlen = snprintf(p, len, "-%u", rid);
- p += rlen;
- len -= rlen;
+ if (len == -1 || *machine_sid == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ return (-1);
}
return (0);
@@ -1537,12 +1543,29 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
pgcfg->default_domain = strdup(pgcfg->domain_name);
}
+ rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid);
+ if (rc != 0)
+ (*errors)++;
+ if (pgcfg->machine_uuid == NULL) {
+ /* If machine_uuid not configured, generate one */
+ if (generate_machine_uuid(&pgcfg->machine_uuid) < 0)
+ return (-2);
+ rc = set_val_astring(handles, handles->config_pg,
+ "machine_uuid", pgcfg->machine_uuid);
+ if (rc != 0)
+ (*errors)++;
+ }
+
rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
if (rc != 0)
(*errors)++;
if (pgcfg->machine_sid == NULL) {
- /* If machine_sid not configured, generate one */
- if (generate_machine_sid(&pgcfg->machine_sid) < 0)
+ /*
+ * If machine_sid not configured, generate one
+ * from the machine UUID.
+ */
+ if (generate_machine_sid(&pgcfg->machine_sid,
+ pgcfg->machine_uuid) < 0)
return (-2);
rc = set_val_astring(handles, handles->config_pg,
"machine_sid", pgcfg->machine_sid);
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h
index 31ae7b6ad1..f2ed7caa7c 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.h
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.h
@@ -77,6 +77,7 @@ typedef struct idmap_pg_config {
uint64_t list_size_limit;
uint64_t id_cache_timeout;
uint64_t name_cache_timeout;
+ char *machine_uuid; /* machine uuid */
char *machine_sid; /* machine sid */
char *default_domain; /* default domain name */
char *domain_name; /* AD domain name */
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
index d184f2a3e8..113f5bf458 100644
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -972,7 +972,8 @@ smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
static const char *smb_user_state[SMB_USER_STATE_SENTINEL] =
{
- "LOGGED_IN",
+ "LOGGING_ON",
+ "LOGGED_ON",
"LOGGING_OFF",
"LOGGED_OFF"
};
diff --git a/usr/src/cmd/smbsrv/fksmbd/Makefile b/usr/src/cmd/smbsrv/fksmbd/Makefile
index 615818e44a..a245c2422e 100644
--- a/usr/src/cmd/smbsrv/fksmbd/Makefile
+++ b/usr/src/cmd/smbsrv/fksmbd/Makefile
@@ -26,11 +26,14 @@
PROG= fksmbd
OBJS_SMBD= \
+ smbd_authsvc.o \
smbd_doorsvc.o \
smbd_join.o \
+ smbd_krb5ssp.o \
smbd_logon.o \
smbd_main.o \
smbd_nicmon.o \
+ smbd_ntlmssp.o \
smbd_pipesvc.o \
smbd_share_doorsvc.o \
smbd_spool.o \
@@ -59,6 +62,9 @@ INCS += -I../../../uts/common
INCS += -I../../../uts/common/smbsrv
INCS += -I../../../common/smbsrv
+# Should not have to do this, but the Kerberos includes are a mess.
+INCS += -I $(ROOT)/usr/include/kerberosv5
+
C99MODE= -xc99=%all
C99LMODE= -Xc99=%all
@@ -74,12 +80,15 @@ CPPFLAGS += $(INCS)
LDFLAGS += $(ZNOLAZYLOAD)
LDFLAGS += -R/usr/lib/smbsrv
-LDLIBS += -L$(ROOT)/usr/lib/smbsrv
+LDLIBS += -L$(ROOT)/usr/lib/smbsrv
LDLIBS += -lfksmbsrv -lfakekernel
-LDLIBS += -lmlsvc -lmlrpc -lsmbns -lsmb
-LDLIBS += -lzfs -lcmdutils -lbsm -lsocket -lnsl -lscf -lumem
+# prefer to keep libs ordered by dependence
+LDLIBS += -lmlsvc -lmlrpc -lsmbns -lsmb -lsmbfs -lgss
+LDLIBS += -lzfs -lbsm -lscf -lcmdutils -lsocket -lnsl -lumem
+$(PROG) := LDLIBS += -lkrb5
LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
+LINTFLAGS += -xerroff=E_NAME_USED_NOT_DEF2
LINTFLAGS += -xerroff=E_INCONS_ARG_DECL2
LINTFLAGS += -xerroff=E_INCONS_VAL_TYPE_DECL2
diff --git a/usr/src/cmd/smbsrv/fksmbd/Run.sh b/usr/src/cmd/smbsrv/fksmbd/Run.sh
index f1f4b5973b..0e42825dab 100755
--- a/usr/src/cmd/smbsrv/fksmbd/Run.sh
+++ b/usr/src/cmd/smbsrv/fksmbd/Run.sh
@@ -12,7 +12,7 @@
#
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
# Helper program to run fksmbd (user-space smbd for debugging)
@@ -32,6 +32,23 @@ then
exit 1;
fi
+if [[ ! -r /var/smb/smbpasswd ]]
+then
+ echo "Need readable /var/smb/smbpasswd, i.e."
+ echo 'chgrp staff /var/smb/smbpasswd'
+ echo 'chmod 440 /var/smb/smbpasswd'
+ exit 1;
+fi
+
+if [[ -e /var/smb/.pwd.lock && ! -w /var/smb/.pwd.lock ]]
+then
+ echo "Need to cleanup /var/smb/.pwd.lock, i.e."
+ echo "rm -f /var/smb/.pwd.lock"
+ exit 1;
+fi
+
+# OK, setup env. to run it.
+
export SMBD_DOOR_NAME="/tmp/fksmbd_door"
export SMB_SHARE_DNAME="/tmp/fksmbshare_door"
diff --git a/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c b/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
index 65fc7cecbb..4e4b17fcf1 100644
--- a/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
+++ b/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -62,11 +62,31 @@ static void
fksmbd_adjust_config(smb_ioc_header_t *ioc_hdr)
{
smb_ioc_cfg_t *ioc = (smb_ioc_cfg_t *)ioc_hdr;
+ char *s;
ioc->maxconnections = 10;
ioc->maxworkers = 20;
smbd_report("maxconnections=%d, maxworkers=%d",
ioc->maxconnections, ioc->maxworkers);
+
+ if ((s = getenv("SMB_SIGNING")) != NULL) {
+ ioc->signing_enable = 0;
+ ioc->signing_required = 0;
+ switch (s[0]) {
+ case 'e':
+ ioc->signing_enable = 1;
+ break;
+ case 'r':
+ ioc->signing_enable = 1;
+ ioc->signing_required = 1;
+ break;
+ default:
+ smbd_report("env SMB_SIGNING invalid");
+ break;
+ }
+ }
+ smbd_report("signing: enable=%d, required=%d",
+ ioc->signing_enable, ioc->signing_required);
}
boolean_t
diff --git a/usr/src/cmd/smbsrv/smbd/Makefile b/usr/src/cmd/smbsrv/smbd/Makefile
index 8fd9ccb74a..134a317fd8 100644
--- a/usr/src/cmd/smbsrv/smbd/Makefile
+++ b/usr/src/cmd/smbsrv/smbd/Makefile
@@ -26,11 +26,14 @@
PROG= smbd
OBJS= \
+ smbd_authsvc.o \
smbd_doorsvc.o \
smbd_join.o \
+ smbd_krb5ssp.o \
smbd_logon.o \
smbd_main.o \
smbd_nicmon.o \
+ smbd_ntlmssp.o \
smbd_pipesvc.o \
smbd_share_doorsvc.o \
smbd_spool.o \
@@ -54,18 +57,25 @@ $(ROOTSVCMETHOD):= FILEMODE = 0555
$(ROOTVARSMBDLL):= FILEMODE = 0755
LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
+LINTFLAGS += -xerroff=E_NAME_USED_NOT_DEF2
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -D_REENTRANT
CPPFLAGS += -Dsyslog=smb_syslog
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+# Should not have to do this, but the Kerberos includes are a mess.
+CPPFLAGS += -I $(ROOT)/usr/include/kerberosv5
+
C99MODE = -xc99=%all
C99LMODE = -Xc99=%all
-LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lmlsvc -lmlrpc -lsmbns -lsmb \
- -lzfs -lbsm -lsocket -lnsl -lscf -lumem -lcmdutils
LDFLAGS += -R/usr/lib/smbsrv
+LDLIBS += -L$(ROOT)/usr/lib/smbsrv
+# prefer to keep libs ordered by dependence
+LDLIBS += -lmlsvc -lmlrpc -lsmbns -lsmb -lsmbfs -lgss
+LDLIBS += -lzfs -lbsm -lscf -lcmdutils -lsocket -lnsl -lumem
+$(PROG) := LDLIBS += -lkrb5
$(ENABLE_SMB_PRINTING) CPPFLAGS += -DHAVE_CUPS
diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml
index 10b0c82a87..d8dc32c114 100644
--- a/usr/src/cmd/smbsrv/smbd/server.xml
+++ b/usr/src/cmd/smbsrv/smbd/server.xml
@@ -181,7 +181,7 @@ file.
<propval name='restrict_anonymous' type='boolean'
value='false' override='true'/>
<propval name='signing_enabled' type='boolean'
- value='false' override='true'/>
+ value='true' override='true'/>
<propval name='signing_required' type='boolean'
value='false' override='true'/>
<propval name='signing_check' type='boolean'
diff --git a/usr/src/cmd/smbsrv/smbd/smbd.h b/usr/src/cmd/smbsrv/smbd/smbd.h
index 3ec5877fac..f3c1351851 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd.h
+++ b/usr/src/cmd/smbsrv/smbd/smbd.h
@@ -56,6 +56,7 @@ uint32_t smbd_join(smb_joininfo_t *);
void smbd_set_secmode(int);
boolean_t smbd_online(void);
void smbd_online_wait(const char *);
+void smbd_get_authconf(smb_kmod_cfg_t *);
void smbd_spool_start(void);
void smbd_spool_stop(void);
@@ -81,6 +82,7 @@ typedef struct smbd {
boolean_t s_shutting_down; /* shutdown control */
volatile uint_t s_refreshes;
boolean_t s_kbound; /* B_TRUE if bound to kernel */
+ int s_authsvc_sock;
int s_door_lmshr;
int s_door_srv;
int s_door_opipe;
@@ -89,6 +91,7 @@ typedef struct smbd {
smb_inaddr_t s_pdc;
boolean_t s_pdc_changed;
pthread_t s_refresh_tid;
+ pthread_t s_authsvc_tid;
pthread_t s_localtime_tid;
pthread_t s_spool_tid;
pthread_t s_dc_monitor_tid;
@@ -140,6 +143,9 @@ void smbd_door_return(smbd_door_t *, char *, size_t, door_desc_t *, uint_t);
void *smbd_door_dispatch_op(void *);
+int smbd_authsvc_start(void);
+void smbd_authsvc_stop(void);
+
/* For fksmbd */
void fksmbd_init(void);
int fksmbd_door_dispatch(smb_doorarg_t *);
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_authsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_authsvc.c
new file mode 100644
index 0000000000..0b6af80bd8
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_authsvc.c
@@ -0,0 +1,973 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * SMB authentication service
+ *
+ * This service listens on a local AF_UNIX socket, spawning a
+ * thread to service each connection. The client-side of such
+ * connections is the in-kernel SMB service, with an open and
+ * connect done in the SMB session setup handler.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <note.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <smbsrv/libsmb.h>
+#include <netsmb/spnego.h>
+
+#include "smbd.h"
+#include "smbd_authsvc.h"
+
+/* Arbitrary value outside the (small) range of valid OIDs */
+#define special_mech_raw_NTLMSSP (spnego_mech_oid_NTLMSSP + 100)
+
+static struct sockaddr_un smbauth_sockname = {
+ AF_UNIX, SMB_AUTHSVC_SOCKNAME };
+
+typedef struct spnego_mech_handler {
+ int mh_oid; /* SPNEGO_MECH_OID */
+ int (*mh_init)(authsvc_context_t *);
+ int (*mh_work)(authsvc_context_t *);
+ void (*mh_fini)(authsvc_context_t *);
+} spnego_mech_handler_t;
+
+static int smbd_authsock_create(void);
+static void smbd_authsock_destroy(void);
+static void *smbd_authsvc_listen(void *);
+static void *smbd_authsvc_work(void *);
+static void smbd_authsvc_flood(void);
+
+static int smbd_authsvc_oldreq(authsvc_context_t *);
+static int smbd_authsvc_clinfo(authsvc_context_t *);
+static int smbd_authsvc_esfirst(authsvc_context_t *);
+static int smbd_authsvc_esnext(authsvc_context_t *);
+static int smbd_authsvc_escmn(authsvc_context_t *);
+static int smbd_authsvc_gettoken(authsvc_context_t *);
+static int smbd_raw_ntlmssp_esfirst(authsvc_context_t *);
+static int smbd_raw_ntlmssp_esnext(authsvc_context_t *);
+
+/*
+ * We can get relatively large tokens now, thanks to krb5 PAC.
+ * Might be better to size these buffers dynamically, but these
+ * are all short-lived so not bothering with that for now.
+ */
+int smbd_authsvc_bufsize = 65000;
+
+static mutex_t smbd_authsvc_mutex = DEFAULTMUTEX;
+
+/*
+ * The maximum number of authentication thread is limited by the
+ * smbsrv smb_threshold_...(->sv_ssetup_ct) mechanism. However,
+ * due to occasional delays closing these auth. sockets, we need
+ * a little "slack" on the number of threads we'll allow, as
+ * compared with the in-kernel limit. We could perhaps just
+ * remove this limit now, but want it for extra safety.
+ */
+int smbd_authsvc_maxthread = SMB_AUTHSVC_MAXTHREAD + 32;
+int smbd_authsvc_thrcnt = 0; /* current thrcnt */
+int smbd_authsvc_hiwat = 0; /* largest thrcnt seen */
+#ifdef DEBUG
+int smbd_authsvc_slowdown = 0;
+#endif
+
+/*
+ * These are the mechanisms we support, in order of preference.
+ * But note: it's really the _client's_ preference that matters.
+ * See &pref in the spnegoIsMechTypeAvailable() calls below.
+ * Careful with this table; the code below knows its format and
+ * may skip the fist two entries to ommit Kerberos.
+ */
+static const spnego_mech_handler_t
+mech_table[] = {
+ {
+ spnego_mech_oid_Kerberos_V5,
+ smbd_krb5ssp_init,
+ smbd_krb5ssp_work,
+ smbd_krb5ssp_fini
+ },
+ {
+ spnego_mech_oid_Kerberos_V5_Legacy,
+ smbd_krb5ssp_init,
+ smbd_krb5ssp_work,
+ smbd_krb5ssp_fini
+ },
+#define MECH_TBL_IDX_NTLMSSP 2
+ {
+ spnego_mech_oid_NTLMSSP,
+ smbd_ntlmssp_init,
+ smbd_ntlmssp_work,
+ smbd_ntlmssp_fini
+ },
+ {
+ /* end marker */
+ spnego_mech_oid_NotUsed,
+ NULL, NULL, NULL
+ },
+};
+
+static const spnego_mech_handler_t
+smbd_auth_mech_raw_ntlmssp = {
+ special_mech_raw_NTLMSSP,
+ smbd_ntlmssp_init,
+ smbd_ntlmssp_work,
+ smbd_ntlmssp_fini
+};
+
+
+/*
+ * Start the authentication service.
+ * Returns non-zero on error.
+ */
+int
+smbd_authsvc_start(void)
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+ int rc;
+
+ rc = smbd_authsock_create();
+ if (rc)
+ return (rc);
+
+ (void) pthread_attr_init(&attr);
+ (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&tid, &attr, smbd_authsvc_listen, &smbd);
+ (void) pthread_attr_destroy(&attr);
+ if (rc) {
+ smbd_authsock_destroy();
+ return (rc);
+ }
+
+ smbd.s_authsvc_tid = tid;
+ return (0);
+}
+
+void
+smbd_authsvc_stop(void)
+{
+
+ if (smbd.s_authsvc_tid != 0) {
+ (void) pthread_kill(smbd.s_authsvc_tid, SIGTERM);
+ smbd.s_authsvc_tid = 0;
+ }
+}
+
+static int
+smbd_authsock_create(void)
+{
+ int sock = -1;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ smbd_report("authsvc, socket create failed, %d", errno);
+ return (errno);
+ }
+
+ (void) unlink(smbauth_sockname.sun_path);
+ if (bind(sock, (struct sockaddr *)&smbauth_sockname,
+ sizeof (smbauth_sockname)) < 0) {
+ smbd_report("authsvc, socket bind failed, %d", errno);
+ (void) close(sock);
+ return (errno);
+ }
+
+ if (listen(sock, SOMAXCONN) < 0) {
+ smbd_report("authsvc, socket listen failed, %d", errno);
+ (void) close(sock);
+ return (errno);
+ }
+
+ smbd.s_authsvc_sock = sock;
+ return (0);
+}
+
+static void
+smbd_authsock_destroy(void)
+{
+ int fid;
+
+ if ((fid = smbd.s_authsvc_sock) != -1) {
+ smbd.s_authsvc_sock = -1;
+ (void) close(fid);
+ }
+}
+
+static void *
+smbd_authsvc_listen(void *arg)
+{
+ authsvc_context_t *ctx;
+ pthread_attr_t attr;
+ pthread_t tid;
+ socklen_t slen;
+ int ls, ns, rc;
+
+ _NOTE(ARGUNUSED(arg))
+
+ (void) pthread_attr_init(&attr);
+ (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ ls = smbd.s_authsvc_sock;
+ for (;;) {
+
+ slen = 0;
+ ns = accept(ls, NULL, &slen);
+ if (ns < 0) {
+ switch (errno) {
+ case ECONNABORTED:
+ continue;
+ case EINTR:
+ /* normal termination */
+ goto out;
+ default:
+ smbd_report("authsvc, socket accept failed,"
+ " %d", errno);
+ goto out;
+ }
+ }
+
+ /*
+ * Limit the number of auth. sockets
+ * (and the threads that service them).
+ */
+ (void) mutex_lock(&smbd_authsvc_mutex);
+ if (smbd_authsvc_thrcnt >= smbd_authsvc_maxthread) {
+ (void) mutex_unlock(&smbd_authsvc_mutex);
+ (void) close(ns);
+ smbd_authsvc_flood();
+ continue;
+ }
+ smbd_authsvc_thrcnt++;
+ if (smbd_authsvc_hiwat < smbd_authsvc_thrcnt)
+ smbd_authsvc_hiwat = smbd_authsvc_thrcnt;
+ (void) mutex_unlock(&smbd_authsvc_mutex);
+
+ ctx = smbd_authctx_create();
+ if (ctx == NULL) {
+ smbd_report("authsvc, can't allocate context");
+ (void) mutex_lock(&smbd_authsvc_mutex);
+ smbd_authsvc_thrcnt--;
+ (void) mutex_unlock(&smbd_authsvc_mutex);
+ (void) close(ns);
+ goto out;
+ }
+ ctx->ctx_socket = ns;
+
+ rc = pthread_create(&tid, &attr, smbd_authsvc_work, ctx);
+ if (rc) {
+ smbd_report("authsvc, thread create failed, %d", rc);
+ (void) mutex_lock(&smbd_authsvc_mutex);
+ smbd_authsvc_thrcnt--;
+ (void) mutex_unlock(&smbd_authsvc_mutex);
+ smbd_authctx_destroy(ctx);
+ goto out;
+ }
+ ctx = NULL; /* given to the new thread */
+ }
+
+out:
+ (void) pthread_attr_destroy(&attr);
+ smbd_authsock_destroy();
+ return (NULL);
+}
+
+static void
+smbd_authsvc_flood(void)
+{
+ static uint_t count;
+ static time_t last_report;
+ time_t now = time(NULL);
+
+ count++;
+ if (last_report + 60 < now) {
+ last_report = now;
+ smbd_report("authsvc: flooded %u", count);
+ count = 0;
+ }
+}
+
+authsvc_context_t *
+smbd_authctx_create(void)
+{
+ authsvc_context_t *ctx;
+
+ ctx = malloc(sizeof (*ctx));
+ if (ctx == NULL)
+ return (NULL);
+ bzero(ctx, sizeof (*ctx));
+
+ ctx->ctx_irawlen = smbd_authsvc_bufsize;
+ ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen);
+ ctx->ctx_orawlen = smbd_authsvc_bufsize;
+ ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen);
+ if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL)
+ goto errout;
+
+ ctx->ctx_ibodylen = smbd_authsvc_bufsize;
+ ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen);
+ ctx->ctx_obodylen = smbd_authsvc_bufsize;
+ ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen);
+ if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL)
+ goto errout;
+
+ return (ctx);
+
+errout:
+ smbd_authctx_destroy(ctx);
+ return (NULL);
+}
+
+void
+smbd_authctx_destroy(authsvc_context_t *ctx)
+{
+ if (ctx->ctx_socket != -1) {
+ (void) close(ctx->ctx_socket);
+ ctx->ctx_socket = -1;
+ }
+
+ if (ctx->ctx_token != NULL)
+ smb_token_destroy(ctx->ctx_token);
+
+ if (ctx->ctx_itoken != NULL)
+ spnegoFreeData(ctx->ctx_itoken);
+ if (ctx->ctx_otoken != NULL)
+ spnegoFreeData(ctx->ctx_otoken);
+
+ free(ctx->ctx_irawbuf);
+ free(ctx->ctx_orawbuf);
+ free(ctx->ctx_ibodybuf);
+ free(ctx->ctx_obodybuf);
+
+ free(ctx);
+}
+
+/*
+ * Limit how long smbd_authsvc_work will wait for the client to
+ * send us the next part of the authentication sequence.
+ */
+static struct timeval recv_tmo = { 30, 0 };
+
+/*
+ * Also set a timeout for send, where we're sending a response to
+ * the client side (in smbsrv). That should always be waiting in
+ * recv by the time we send, so a short timeout is OK.
+ */
+static struct timeval send_tmo = { 15, 0 };
+
+static void *
+smbd_authsvc_work(void *arg)
+{
+ authsvc_context_t *ctx = arg;
+ smb_lsa_msg_hdr_t hdr;
+ int sock = ctx->ctx_socket;
+ int len, rc;
+
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+ (char *)&send_tmo, sizeof (send_tmo)) != 0) {
+ smbd_report("authsvc_work: set set timeout: %m");
+ goto out;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+ (char *)&recv_tmo, sizeof (recv_tmo)) != 0) {
+ smbd_report("authsvc_work: set recv timeout: %m");
+ goto out;
+ }
+
+ for (;;) {
+
+ len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL);
+ if (len <= 0) {
+ /* normal termination */
+ break;
+ }
+ if (len != sizeof (hdr)) {
+ smbd_report("authsvc_work: read header failed");
+ break;
+ }
+
+ if (hdr.lmh_msglen > smbd_authsvc_bufsize) {
+ smbd_report("authsvc_work: msg too large");
+ break;
+ }
+
+ if (hdr.lmh_msglen > 0) {
+ len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen,
+ MSG_WAITALL);
+ if (len != hdr.lmh_msglen) {
+ smbd_report("authsvc_work: read mesg failed");
+ break;
+ }
+ }
+ ctx->ctx_irawtype = hdr.lmh_msgtype;
+ ctx->ctx_irawlen = hdr.lmh_msglen;
+ ctx->ctx_orawlen = smbd_authsvc_bufsize;
+ ctx->ctx_ibodylen = smbd_authsvc_bufsize;
+ ctx->ctx_obodylen = smbd_authsvc_bufsize;
+
+ /*
+ * The real work happens here.
+ */
+ rc = smbd_authsvc_dispatch(ctx);
+ if (rc)
+ break;
+
+ hdr.lmh_msgtype = ctx->ctx_orawtype;
+ hdr.lmh_msglen = ctx->ctx_orawlen;
+ len = send(sock, &hdr, sizeof (hdr), 0);
+ if (len != sizeof (hdr)) {
+ smbd_report("authsvc_work: send failed");
+ break;
+ }
+
+ if (ctx->ctx_orawlen > 0) {
+ len = send(sock, ctx->ctx_orawbuf,
+ ctx->ctx_orawlen, 0);
+ if (len != ctx->ctx_orawlen) {
+ smbd_report("authsvc_work: send failed");
+ break;
+ }
+ }
+ }
+
+out:
+ if (ctx->ctx_mh_fini)
+ (ctx->ctx_mh_fini)(ctx);
+
+ smbd_authctx_destroy(ctx);
+
+ (void) mutex_lock(&smbd_authsvc_mutex);
+ smbd_authsvc_thrcnt--;
+ (void) mutex_unlock(&smbd_authsvc_mutex);
+
+ return (NULL); /* implied pthread_exit() */
+}
+
+/*
+ * Dispatch based on message type LSA_MTYPE_...
+ * Non-zero return here ends the conversation.
+ */
+int
+smbd_authsvc_dispatch(authsvc_context_t *ctx)
+{
+ int rc;
+
+ switch (ctx->ctx_irawtype) {
+
+ case LSA_MTYPE_OLDREQ:
+#ifdef DEBUG
+ if (smbd_authsvc_slowdown)
+ (void) sleep(smbd_authsvc_slowdown);
+#endif
+ rc = smbd_authsvc_oldreq(ctx);
+ break;
+
+ case LSA_MTYPE_CLINFO:
+ rc = smbd_authsvc_clinfo(ctx);
+ break;
+
+ case LSA_MTYPE_ESFIRST:
+ rc = smbd_authsvc_esfirst(ctx);
+ break;
+
+ case LSA_MTYPE_ESNEXT:
+#ifdef DEBUG
+ if (smbd_authsvc_slowdown)
+ (void) sleep(smbd_authsvc_slowdown);
+#endif
+ rc = smbd_authsvc_esnext(ctx);
+ break;
+
+ case LSA_MTYPE_GETTOK:
+ rc = smbd_authsvc_gettoken(ctx);
+ break;
+
+ /* response types */
+ case LSA_MTYPE_OK:
+ case LSA_MTYPE_ERROR:
+ case LSA_MTYPE_TOKEN:
+ case LSA_MTYPE_ES_CONT:
+ case LSA_MTYPE_ES_DONE:
+ default:
+ return (-1);
+ }
+
+ if (rc != 0) {
+ smb_lsa_eresp_t *er = ctx->ctx_orawbuf;
+ ctx->ctx_orawtype = LSA_MTYPE_ERROR;
+ ctx->ctx_orawlen = sizeof (*er);
+ er->ler_ntstatus = rc;
+ er->ler_errclass = 0;
+ er->ler_errcode = 0;
+ }
+ return (0);
+}
+
+static int
+smbd_authsvc_oldreq(authsvc_context_t *ctx)
+{
+ smb_logon_t user_info;
+ XDR xdrs;
+ smb_token_t *token = NULL;
+ int rc = 0;
+
+ bzero(&user_info, sizeof (user_info));
+ xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen,
+ XDR_DECODE);
+ if (!smb_logon_xdr(&xdrs, &user_info)) {
+ xdr_destroy(&xdrs);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+ xdr_destroy(&xdrs);
+
+ token = smbd_user_auth_logon(&user_info);
+ xdr_free(smb_logon_xdr, (char *)&user_info);
+ if (token == NULL)
+ return (NT_STATUS_ACCESS_DENIED);
+
+ ctx->ctx_token = token;
+
+ return (rc);
+}
+
+static int
+smbd_authsvc_clinfo(authsvc_context_t *ctx)
+{
+
+ if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t))
+ return (NT_STATUS_INTERNAL_ERROR);
+ (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf,
+ sizeof (smb_lsa_clinfo_t));
+
+ ctx->ctx_orawtype = LSA_MTYPE_OK;
+ ctx->ctx_orawlen = 0;
+ return (0);
+}
+
+/*
+ * Handle a security blob we've received from the client.
+ * Incoming type: LSA_MTYPE_ESFIRST
+ * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
+ * LSA_MTYPE_ERROR
+ */
+static int
+smbd_authsvc_esfirst(authsvc_context_t *ctx)
+{
+ const spnego_mech_handler_t *mh;
+ int idx, pref, rc;
+ int best_pref = 1000;
+ int best_mhidx = -1;
+
+ /*
+ * NTLMSSP header is 8+, SPNEGO is 10+
+ */
+ if (ctx->ctx_irawlen < 8) {
+ smbd_report("authsvc: short blob");
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ /*
+ * We could have "Raw NTLMSSP" here intead of SPNEGO.
+ */
+ if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
+ rc = smbd_raw_ntlmssp_esfirst(ctx);
+ return (rc);
+ }
+
+ /*
+ * Parse the SPNEGO token, check its type.
+ */
+ rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
+ ctx->ctx_irawlen, &ctx->ctx_itoken);
+ if (rc != 0) {
+ smbd_report("authsvc: spnego parse failed");
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
+ if (rc != 0) {
+ smbd_report("authsvc: spnego get token type failed");
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) {
+ smbd_report("authsvc: spnego wrong token type %d",
+ ctx->ctx_itoktype);
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ /*
+ * Figure out which mech type to use. We want to use the
+ * first of the client's supported mechanisms that we also
+ * support. Unfortunately, the spnego code does not have an
+ * interface to walk the token's mech list, so we have to
+ * ask about each mech type we know and keep track of which
+ * was earliest in the token's mech list.
+ *
+ * Also, skip the Kerberos mechanisms in workgroup mode.
+ */
+ idx = 0;
+ mh = mech_table;
+ if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
+ idx = MECH_TBL_IDX_NTLMSSP;
+ mh = &mech_table[idx];
+ }
+ for (; mh->mh_init != NULL; idx++, mh++) {
+
+ if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
+ mh->mh_oid, &pref) != 0)
+ continue;
+
+ if (pref < best_pref) {
+ best_pref = pref;
+ best_mhidx = idx;
+ }
+ }
+ if (best_mhidx == -1) {
+ smbd_report("authsvc: no supported spnego mechanism");
+ return (NT_STATUS_INVALID_PARAMETER);
+ }
+
+ /* Found a mutually agreeable mech. */
+ mh = &mech_table[best_mhidx];
+ ctx->ctx_mech_oid = mh->mh_oid;
+ ctx->ctx_mh_work = mh->mh_work;
+ ctx->ctx_mh_fini = mh->mh_fini;
+ rc = mh->mh_init(ctx);
+ if (rc != 0) {
+ smbd_report("authsvc: mech init failed");
+ return (rc);
+ }
+
+ /*
+ * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
+ */
+ rc = smbd_authsvc_escmn(ctx);
+ return (rc);
+}
+
+/*
+ * Handle a security blob we've received from the client.
+ * Incoming type: LSA_MTYPE_ESNEXT
+ * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
+ * LSA_MTYPE_ERROR
+ */
+static int
+smbd_authsvc_esnext(authsvc_context_t *ctx)
+{
+ int rc;
+
+ /*
+ * Make sure LSA_MTYPE_ESFIRST was handled
+ * previously, so we have a work function.
+ */
+ if (ctx->ctx_mh_work == NULL)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
+ rc = smbd_raw_ntlmssp_esnext(ctx);
+ return (rc);
+ }
+
+ /*
+ * Cleanup state from previous calls.
+ */
+ if (ctx->ctx_itoken != NULL) {
+ spnegoFreeData(ctx->ctx_itoken);
+ ctx->ctx_itoken = NULL;
+ }
+
+ /*
+ * Parse the SPNEGO token, check its type.
+ */
+ rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
+ ctx->ctx_irawlen, &ctx->ctx_itoken);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ rc = smbd_authsvc_escmn(ctx);
+ return (rc);
+}
+
+static int
+smbd_authsvc_escmn(authsvc_context_t *ctx)
+{
+ SPNEGO_MECH_OID oid;
+ ulong_t toklen;
+ int rc;
+
+ /*
+ * Cleanup state from previous calls.
+ */
+ if (ctx->ctx_otoken != NULL) {
+ spnegoFreeData(ctx->ctx_otoken);
+ ctx->ctx_otoken = NULL;
+ }
+
+ /*
+ * Extract the payload (mech token).
+ */
+ toklen = ctx->ctx_ibodylen;
+ rc = spnegoGetMechToken(ctx->ctx_itoken,
+ ctx->ctx_ibodybuf, &toklen);
+ switch (rc) {
+ case SPNEGO_E_SUCCESS:
+ break;
+ case SPNEGO_E_ELEMENT_UNAVAILABLE:
+ toklen = 0;
+ break;
+ case SPNEGO_E_BUFFER_TOO_SMALL:
+ return (NT_STATUS_BUFFER_TOO_SMALL);
+ default:
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ ctx->ctx_ibodylen = toklen;
+
+ /*
+ * Now that we have the incoming "body" (mech. token),
+ * call the back-end mech-specific work function to
+ * create the outgoing "body" (mech. token).
+ *
+ * The worker must fill in: ctx->ctx_negresult,
+ * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf
+ * is optional, and is typically NULL after the
+ * final message of an auth sequence, where
+ * negresult == spnego_negresult_complete.
+ */
+ rc = ctx->ctx_mh_work(ctx);
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * Wrap the outgoing body in a negTokenTarg SPNEGO token.
+ * The selected mech. OID is returned only when the
+ * incoming token was of type SPNEGO_TOKEN_INIT.
+ */
+ if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) {
+ /* tell the client the selected mech. */
+ oid = ctx->ctx_mech_oid;
+ } else {
+ /* Ommit the "supported mech." field. */
+ oid = spnego_mech_oid_NotUsed;
+ }
+
+ /*
+ * Determine the spnego "negresult" from the
+ * reply message type (from the work func).
+ */
+ switch (ctx->ctx_orawtype) {
+ case LSA_MTYPE_ERROR:
+ ctx->ctx_negresult = spnego_negresult_rejected;
+ break;
+ case LSA_MTYPE_ES_DONE:
+ ctx->ctx_negresult = spnego_negresult_success;
+ break;
+ case LSA_MTYPE_ES_CONT:
+ ctx->ctx_negresult = spnego_negresult_incomplete;
+ break;
+ default:
+ return (-1);
+ }
+
+ rc = spnegoCreateNegTokenTarg(
+ oid,
+ ctx->ctx_negresult,
+ ctx->ctx_obodybuf, /* may be NULL */
+ ctx->ctx_obodylen,
+ NULL, 0,
+ &ctx->ctx_otoken);
+
+ /*
+ * Convert the SPNEGO token into binary form,
+ * writing it to the output buffer.
+ */
+ toklen = smbd_authsvc_bufsize;
+ rc = spnegoTokenGetBinary(ctx->ctx_otoken,
+ (uchar_t *)ctx->ctx_orawbuf, &toklen);
+ if (rc)
+ rc = NT_STATUS_INTERNAL_ERROR;
+ ctx->ctx_orawlen = (uint_t)toklen;
+
+ return (rc);
+}
+
+/*
+ * Wrapper for "Raw NTLMSSP", which is exactly like the
+ * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
+ * Setup back-end handler for: special_mech_raw_NTLMSSP
+ * Compare with smbd_authsvc_esfirst().
+ */
+static int
+smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
+{
+ const spnego_mech_handler_t *mh;
+ int rc;
+
+ mh = &smbd_auth_mech_raw_ntlmssp;
+ rc = mh->mh_init(ctx);
+ if (rc != 0)
+ return (rc);
+
+ ctx->ctx_mech_oid = mh->mh_oid;
+ ctx->ctx_mh_work = mh->mh_work;
+ ctx->ctx_mh_fini = mh->mh_fini;
+
+ rc = smbd_raw_ntlmssp_esnext(ctx);
+
+ return (rc);
+}
+
+
+/*
+ * Wrapper for "Raw NTLMSSP", which is exactly like the
+ * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
+ * Just copy "raw" to "body", and vice versa.
+ * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn
+ */
+static int
+smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
+{
+ int rc;
+
+ ctx->ctx_ibodylen = ctx->ctx_irawlen;
+ (void) memcpy(ctx->ctx_ibodybuf,
+ ctx->ctx_irawbuf, ctx->ctx_irawlen);
+
+ rc = ctx->ctx_mh_work(ctx);
+
+ ctx->ctx_orawlen = ctx->ctx_obodylen;
+ (void) memcpy(ctx->ctx_orawbuf,
+ ctx->ctx_obodybuf, ctx->ctx_obodylen);
+
+ return (rc);
+}
+
+
+/*
+ * After a successful authentication, request the access token.
+ */
+static int
+smbd_authsvc_gettoken(authsvc_context_t *ctx)
+{
+ XDR xdrs;
+ smb_token_t *token = NULL;
+ int rc = 0;
+ int len;
+
+ if ((token = ctx->ctx_token) == NULL)
+ return (NT_STATUS_ACCESS_DENIED);
+
+ /*
+ * Encode the token response
+ */
+ len = xdr_sizeof(smb_token_xdr, token);
+ if (len > ctx->ctx_orawlen) {
+ if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) ==
+ NULL) {
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ ctx->ctx_orawtype = LSA_MTYPE_TOKEN;
+ ctx->ctx_orawlen = len;
+ xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE);
+ if (!smb_token_xdr(&xdrs, token))
+ rc = NT_STATUS_INTERNAL_ERROR;
+ xdr_destroy(&xdrs);
+
+ return (rc);
+}
+
+/*
+ * Initialization time code to figure out what mechanisms we support.
+ * Careful with this table; the code below knows its format and may
+ * skip the fist two entries to ommit Kerberos.
+ */
+static SPNEGO_MECH_OID MechTypeList[] = {
+ spnego_mech_oid_Kerberos_V5,
+ spnego_mech_oid_Kerberos_V5_Legacy,
+#define MECH_OID_IDX_NTLMSSP 2
+ spnego_mech_oid_NTLMSSP,
+};
+static int MechTypeCnt = sizeof (MechTypeList) /
+ sizeof (MechTypeList[0]);
+
+/* This string is just like Windows. */
+static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
+
+/*
+ * Build the SPNEGO "hint" token based on the
+ * configured authentication mechanisms.
+ * (NTLMSSP, and maybe Kerberos)
+ */
+void
+smbd_get_authconf(smb_kmod_cfg_t *kcfg)
+{
+ SPNEGO_MECH_OID *mechList = MechTypeList;
+ int mechCnt = MechTypeCnt;
+ SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
+ uchar_t *pBuf = kcfg->skc_negtok;
+ uint32_t *pBufLen = &kcfg->skc_negtok_len;
+ ulong_t tLen = sizeof (kcfg->skc_negtok);
+ int rc;
+
+ /*
+ * In workgroup mode, skip Kerberos.
+ */
+ if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
+ mechList += MECH_OID_IDX_NTLMSSP;
+ mechCnt -= MECH_OID_IDX_NTLMSSP;
+ }
+
+ rc = spnegoCreateNegTokenHint(mechList, mechCnt,
+ (uchar_t *)IgnoreSPN, &hSpnegoToken);
+ if (rc != SPNEGO_E_SUCCESS) {
+ syslog(LOG_DEBUG, "smb_config_get_negtok: "
+ "spnegoCreateNegTokenHint, rc=%d", rc);
+ *pBufLen = 0;
+ return;
+ }
+ rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen);
+ if (rc != SPNEGO_E_SUCCESS) {
+ syslog(LOG_DEBUG, "smb_config_get_negtok: "
+ "spnegoTokenGetBinary, rc=%d", rc);
+ *pBufLen = 0;
+ } else {
+ *pBufLen = (uint32_t)tLen;
+ }
+ spnegoFreeData(hSpnegoToken);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_authsvc.h b/usr/src/cmd/smbsrv/smbd/smbd_authsvc.h
new file mode 100644
index 0000000000..116eebfc84
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_authsvc.h
@@ -0,0 +1,82 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SMBD_AUTHSVC_H
+#define _SMBD_AUTHSVC_H
+
+/*
+ * Declarations shared with authsvc modules.
+ */
+
+#include <sys/types.h>
+#include <smbsrv/libsmb.h>
+
+/*
+ * This is the common authsvc_context shared by all back-ends.
+ * Note that ctx_mech_oid is really SPNEGO_MECH_OID, and the
+ * ctx_itoken, ctx_otoken members are SPNEGO_TOKEN_HANDLE,
+ * but this is using the underlying types so as to avoid
+ * dragging in spnego.h here.
+ */
+typedef struct authsvc_context {
+ int ctx_socket;
+ int ctx_mech_oid;
+ int (*ctx_mh_work)(struct authsvc_context *);
+ void (*ctx_mh_fini)(struct authsvc_context *);
+ int ctx_itoktype;
+ int ctx_negresult;
+
+ /* (in,out) SPNEGO token handles */
+ void *ctx_itoken;
+ void *ctx_otoken;
+
+ /* (in,out) raw (buf,len,type) */
+ void *ctx_irawbuf;
+ uint_t ctx_irawlen;
+ int ctx_irawtype;
+ void *ctx_orawbuf;
+ uint_t ctx_orawlen;
+ int ctx_orawtype;
+
+ /* (in,out) body (buf,len) */
+ void *ctx_ibodybuf;
+ uint_t ctx_ibodylen;
+ void *ctx_obodybuf;
+ uint_t ctx_obodylen;
+
+ /* who is the client */
+ smb_lsa_clinfo_t ctx_clinfo;
+
+ /* final authentication token */
+ struct smb_token *ctx_token;
+
+ /* private data for the back-end */
+ void *ctx_backend;
+} authsvc_context_t;
+
+int smbd_krb5ssp_init(authsvc_context_t *);
+int smbd_krb5ssp_work(authsvc_context_t *);
+void smbd_krb5ssp_fini(authsvc_context_t *);
+
+int smbd_ntlmssp_init(authsvc_context_t *);
+int smbd_ntlmssp_work(authsvc_context_t *);
+void smbd_ntlmssp_fini(authsvc_context_t *);
+
+/* Exposed for unit tests. */
+int smbd_authsvc_dispatch(authsvc_context_t *);
+authsvc_context_t *smbd_authctx_create(void);
+void smbd_authctx_destroy(authsvc_context_t *);
+
+#endif /* _SMBD_AUTHSVC_H */
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c
index e21a9beaf4..b8705b1d91 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c
+++ b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c
@@ -38,6 +38,7 @@
#include <fcntl.h>
#include <pthread.h>
#include <strings.h>
+#include <note.h>
#include <smbsrv/smb_door.h>
#include <smbsrv/smb_xdr.h>
#include <smbsrv/smb_token.h>
@@ -572,27 +573,10 @@ smbd_dop_user_auth_logoff(smbd_arg_t *arg)
static int
smbd_dop_user_auth_logon(smbd_arg_t *arg)
{
- smb_logon_t *user_info;
- smb_token_t *token;
+ _NOTE(ARGUNUSED(arg))
- user_info = smb_logon_decode((uint8_t *)arg->data,
- arg->datalen);
- if (user_info == NULL)
- return (SMB_DOP_DECODE_ERROR);
-
- token = smbd_user_auth_logon(user_info);
-
- smb_logon_free(user_info);
-
- if (token == NULL)
- return (SMB_DOP_EMPTYBUF);
-
- arg->rbuf = (char *)smb_token_encode(token, &arg->rsize);
- smb_token_destroy(token);
-
- if (arg->rbuf == NULL)
- return (SMB_DOP_ENCODE_ERROR);
- return (SMB_DOP_SUCCESS);
+ /* No longer used */
+ return (SMB_DOP_EMPTYBUF);
}
static int
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_krb5ssp.c b/usr/src/cmd/smbsrv/smbd/smbd_krb5ssp.c
new file mode 100644
index 0000000000..ff0dff251b
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_krb5ssp.c
@@ -0,0 +1,350 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * SPNEGO back-end for Kerberos. See [MS-KILE]
+ */
+
+#include <sys/types.h>
+#include <gssapi/gssapi_ext.h>
+#include <gssapi/gssapi_krb5.h>
+#include <krb5.h>
+#include "smbd.h"
+#include "smbd_authsvc.h"
+
+/* From krb5/krb/pac.c (should have been exported) */
+#define PAC_LOGON_INFO 1
+
+typedef struct krb5ssp_backend {
+ gss_ctx_id_t be_gssctx;
+ char *be_username;
+ gss_buffer_desc be_authz_pac;
+ krb5_context be_kctx;
+ krb5_pac be_kpac;
+ krb5_data be_pac;
+} krb5ssp_backend_t;
+
+static uint32_t
+get_authz_data_pac(
+ gss_ctx_id_t context_handle,
+ gss_buffer_t ad_data);
+
+static uint32_t
+get_ssnkey(authsvc_context_t *ctx);
+
+
+/*
+ * Initialize this context for Kerberos, if possible.
+ *
+ * Should not get here unless libsmb smb_config_get_negtok
+ * includes the Kerberos5 Mech OIDs in our spnego hint.
+ *
+ * Todo: allocate ctx->ctx_backend
+ * See: krb5_gss_accept_sec_context()
+ */
+int
+smbd_krb5ssp_init(authsvc_context_t *ctx)
+{
+ krb5ssp_backend_t *be;
+
+ be = malloc(sizeof (*be));
+ if (be == 0)
+ return (NT_STATUS_NO_MEMORY);
+ bzero(be, sizeof (*be));
+ be->be_gssctx = GSS_C_NO_CONTEXT;
+ ctx->ctx_backend = be;
+
+ return (0);
+}
+
+/*
+ * Todo: free ctx->ctx_backend
+ */
+void
+smbd_krb5ssp_fini(authsvc_context_t *ctx)
+{
+ krb5ssp_backend_t *be = ctx->ctx_backend;
+ uint32_t minor;
+
+ if (be == NULL)
+ return;
+
+ if (be->be_kctx != NULL) {
+ krb5_free_data_contents(be->be_kctx, &be->be_pac);
+
+ if (be->be_kpac != NULL)
+ krb5_pac_free(be->be_kctx, be->be_kpac);
+
+ krb5_free_context(be->be_kctx);
+ }
+
+ (void) gss_release_buffer(NULL, &be->be_authz_pac);
+
+ free(be->be_username);
+
+ if (be->be_gssctx != GSS_C_NO_CONTEXT) {
+ (void) gss_delete_sec_context(&minor, &be->be_gssctx,
+ GSS_C_NO_BUFFER);
+ }
+
+ free(be);
+}
+
+/*
+ * Handle a Kerberos auth message.
+ *
+ * State across messages is in ctx->ctx_backend
+ */
+int
+smbd_krb5ssp_work(authsvc_context_t *ctx)
+{
+ gss_buffer_desc intok, outtok;
+ gss_buffer_desc namebuf;
+ krb5ssp_backend_t *be = ctx->ctx_backend;
+ gss_name_t gname = NULL;
+ OM_uint32 major, minor, ret_flags;
+ gss_OID name_type = GSS_C_NULL_OID;
+ gss_OID mech_type = GSS_C_NULL_OID;
+ krb5_error_code kerr;
+ uint32_t status;
+
+ intok.length = ctx->ctx_ibodylen;
+ intok.value = ctx->ctx_ibodybuf;
+ bzero(&outtok, sizeof (gss_buffer_desc));
+ bzero(&namebuf, sizeof (gss_buffer_desc));
+
+ /* Do this early, for error message support. */
+ kerr = krb5_init_context(&be->be_kctx);
+ if (kerr != 0) {
+ smbd_report("krb5ssp, krb5_init_ctx: %s",
+ krb5_get_error_message(be->be_kctx, kerr));
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ major = gss_accept_sec_context(&minor, &be->be_gssctx,
+ GSS_C_NO_CREDENTIAL, &intok,
+ GSS_C_NO_CHANNEL_BINDINGS, &gname, &mech_type, &outtok,
+ &ret_flags, NULL, NULL);
+
+ if (outtok.length == 0)
+ ctx->ctx_obodylen = 0;
+ else if (outtok.length <= ctx->ctx_obodylen) {
+ ctx->ctx_obodylen = outtok.length;
+ (void) memcpy(ctx->ctx_obodybuf, outtok.value, outtok.length);
+ free(outtok.value);
+ outtok.value = NULL;
+ } else {
+ free(ctx->ctx_obodybuf);
+ ctx->ctx_obodybuf = outtok.value;
+ ctx->ctx_obodylen = outtok.length;
+ outtok.value = NULL;
+ }
+
+ if (GSS_ERROR(major)) {
+ smbd_report("krb5ssp: gss_accept_sec_context, "
+ "mech=0x%x, major=0x%x, minor=0x%x",
+ (int)mech_type, major, minor);
+ smbd_report(" krb5: %s",
+ krb5_get_error_message(be->be_kctx, minor));
+ return (NT_STATUS_WRONG_PASSWORD);
+ }
+
+ switch (major) {
+ case GSS_S_COMPLETE:
+ break;
+ case GSS_S_CONTINUE_NEEDED:
+ if (outtok.length > 0) {
+ ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
+ /* becomes NT_STATUS_MORE_PROCESSING_REQUIRED */
+ return (0);
+ }
+ return (NT_STATUS_WRONG_PASSWORD);
+ default:
+ return (NT_STATUS_WRONG_PASSWORD);
+ }
+
+ /*
+ * OK, we got GSS_S_COMPLETE. Get the name so we can use it
+ * in log messages if we get failures decoding the PAC etc.
+ * Then get the PAC, decode it, build the logon token.
+ */
+
+ if (gname != NULL && GSS_S_COMPLETE ==
+ gss_display_name(&minor, gname, &namebuf, &name_type)) {
+ /* Save the user name. */
+ be->be_username = strdup(namebuf.value);
+ (void) gss_release_buffer(&minor, &namebuf);
+ (void) gss_release_name(&minor, &gname);
+ if (be->be_username == NULL) {
+ return (NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ /*
+ * Extract the KRB5_AUTHDATA_WIN2K_PAC data.
+ */
+ status = get_authz_data_pac(be->be_gssctx,
+ &be->be_authz_pac);
+ if (status)
+ return (status);
+
+ kerr = krb5_pac_parse(be->be_kctx, be->be_authz_pac.value,
+ be->be_authz_pac.length, &be->be_kpac);
+ if (kerr) {
+ smbd_report("krb5ssp, krb5_pac_parse: %s",
+ krb5_get_error_message(be->be_kctx, kerr));
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ kerr = krb5_pac_get_buffer(be->be_kctx, be->be_kpac,
+ PAC_LOGON_INFO, &be->be_pac);
+ if (kerr) {
+ smbd_report("krb5ssp, krb5_pac_get_buffer: %s",
+ krb5_get_error_message(be->be_kctx, kerr));
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ ctx->ctx_token = calloc(1, sizeof (smb_token_t));
+ if (ctx->ctx_token == NULL)
+ return (NT_STATUS_NO_MEMORY);
+
+ status = smb_decode_krb5_pac(ctx->ctx_token, be->be_pac.data,
+ be->be_pac.length);
+ if (status)
+ return (status);
+
+ status = get_ssnkey(ctx);
+ if (status)
+ return (status);
+
+ if (!smb_token_setup_common(ctx->ctx_token))
+ return (NT_STATUS_UNSUCCESSFUL);
+
+ /* Success! */
+ ctx->ctx_orawtype = LSA_MTYPE_ES_DONE;
+
+ return (0);
+}
+
+/*
+ * See: GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID
+ * and: KRB5_AUTHDATA_WIN2K_PAC
+ */
+static const gss_OID_desc
+oid_ex_authz_data_pac = {
+ 13, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a\x81\x00" };
+
+/*
+ * See: krb5_gss_inquire_sec_context_by_oid()
+ * and krb5_gss_inquire_sec_context_by_oid_ops[],
+ * gss_krb5int_extract_authz_data_from_sec_context()
+ */
+static uint32_t
+get_authz_data_pac(
+ gss_ctx_id_t context_handle,
+ gss_buffer_t ad_data)
+{
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+ OM_uint32 major, minor;
+ uint32_t status = NT_STATUS_UNSUCCESSFUL;
+
+ if (ad_data == NULL)
+ goto out;
+
+ major = gss_inquire_sec_context_by_oid(
+ &minor,
+ context_handle,
+ (gss_OID)&oid_ex_authz_data_pac,
+ &data_set);
+ if (GSS_ERROR(major)) {
+ smbd_report("krb5ssp, gss_inquire...PAC, "
+ "major=0x%x, minor=0x%x", major, minor);
+ goto out;
+ }
+
+ if ((data_set == GSS_C_NO_BUFFER_SET) || (data_set->count == 0)) {
+ goto out;
+ }
+
+ /* Only need the first element? */
+ ad_data->length = data_set->elements[0].length;
+ ad_data->value = malloc(ad_data->length);
+ if (ad_data->value == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ bcopy(data_set->elements[0].value, ad_data->value, ad_data->length);
+ status = 0;
+
+out:
+ (void) gss_release_buffer_set(&minor, &data_set);
+
+ return (status);
+}
+
+/*
+ * Get the session key, and save it in the token.
+ *
+ * See: krb5_gss_inquire_sec_context_by_oid(),
+ * krb5_gss_inquire_sec_context_by_oid_ops[], and
+ * gss_krb5int_inq_session_key
+ */
+static uint32_t
+get_ssnkey(authsvc_context_t *ctx)
+{
+ krb5ssp_backend_t *be = ctx->ctx_backend;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+ OM_uint32 major, minor;
+ size_t keylen;
+ uint32_t status = NT_STATUS_UNSUCCESSFUL;
+
+ major = gss_inquire_sec_context_by_oid(&minor,
+ be->be_gssctx, GSS_C_INQ_SSPI_SESSION_KEY, &data_set);
+ if (GSS_ERROR(major)) {
+ smbd_report("krb5ssp, failed to get session key, "
+ "major=0x%x, minor=0x%x", major, minor);
+ goto out;
+ }
+
+ /*
+ * The key is in the first element
+ */
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count == 0 ||
+ data_set->elements[0].length == 0 ||
+ data_set->elements[0].value == NULL) {
+ smbd_report("krb5ssp: Session key is missing");
+ goto out;
+ }
+ if ((keylen = data_set->elements[0].length) < SMBAUTH_HASH_SZ) {
+ smbd_report("krb5ssp: Session key too short (%d)",
+ data_set->elements[0].length);
+ goto out;
+ }
+
+ ctx->ctx_token->tkn_ssnkey.val = malloc(keylen);
+ if (ctx->ctx_token->tkn_ssnkey.val == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ ctx->ctx_token->tkn_ssnkey.len = keylen;
+ bcopy(data_set->elements[0].value,
+ ctx->ctx_token->tkn_ssnkey.val, keylen);
+ status = 0;
+
+out:
+ (void) gss_release_buffer_set(&minor, &data_set);
+ return (status);
+}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_logon.c b/usr/src/cmd/smbsrv/smbd/smbd_logon.c
index ad19f46655..fa7dae801b 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd_logon.c
+++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -84,6 +85,7 @@ smbd_user_auth_logon(smb_logon_t *user_info)
smb_audit_t *entry;
adt_session_data_t *ah;
adt_event_data_t *event;
+ smb_logon_t tmp_user;
au_tid_addr_t termid;
char sidbuf[SMB_SID_STRSZ];
char *username;
@@ -94,12 +96,27 @@ smbd_user_auth_logon(smb_logon_t *user_info)
int status;
int retval;
- if ((token = smb_logon(user_info)) == NULL) {
+ if (user_info->lg_username == NULL ||
+ user_info->lg_domain == NULL ||
+ user_info->lg_workstation == NULL) {
+ return (NULL);
+ }
+
+ tmp_user = *user_info;
+ if (tmp_user.lg_username[0] == '\0') {
+ tmp_user.lg_flags |= SMB_ATF_ANON;
+ tmp_user.lg_e_username = "anonymous";
+ } else {
+ tmp_user.lg_e_username = tmp_user.lg_username;
+ }
+ tmp_user.lg_e_domain = tmp_user.lg_domain;
+
+ if ((token = smb_logon(&tmp_user)) == NULL) {
uid = ADT_NO_ATTRIB;
gid = ADT_NO_ATTRIB;
sid = NT_NULL_SIDSTR;
- username = user_info->lg_e_username;
- domain = user_info->lg_e_domain;
+ username = tmp_user.lg_e_username;
+ domain = tmp_user.lg_e_domain;
status = ADT_FAILURE;
retval = ADT_FAIL_VALUE_AUTH;
} else {
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_main.c b/usr/src/cmd/smbsrv/smbd/smbd_main.c
index 59b11eb702..b1c9dbc770 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -433,6 +433,7 @@ smbd_service_init(void)
{ SMB_SYSTEM32, 0755 },
{ SMB_VSS, 0755 },
{ SMB_PIPE_DIR, 0755 },
+ { "/var/smb/lipc", 0755 },
};
int rc, i;
@@ -457,6 +458,12 @@ smbd_service_init(void)
}
}
+ /*
+ * This environment variable tells mech_krb5 to give us
+ * MS-compatible behavior.
+ */
+ (void) putenv("MS_INTEROP=1");
+
if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) {
if (rc == -1)
smbd_report("mkdir %s: %s", SMB_VARRUN_DIR,
@@ -503,6 +510,11 @@ smbd_service_init(void)
return (-1);
}
+ if (smbd_authsvc_start() != 0) {
+ smbd_report("authsvc initialization failed");
+ return (-1);
+ }
+
smbd.s_door_srv = smbd_door_start();
if (smbd.s_door_srv < 0) {
smbd_report("door initialization failed %s", strerror(errno));
@@ -555,6 +567,7 @@ smbd_service_fini(void)
smb_lgrp_stop();
smbd_pipesvc_stop();
smbd_door_stop();
+ smbd_authsvc_stop();
smbd_spool_stop();
smbd_kernel_unbind();
smbd_share_stop();
@@ -708,6 +721,7 @@ smbd_kernel_bind(void)
if (smbd.s_kbound) {
smb_load_kconfig(&cfg);
+ smbd_get_authconf(&cfg);
rc = smb_kmod_setcfg(&cfg);
if (rc < 0)
smbd_report("kernel configuration update failed: %s",
@@ -738,6 +752,7 @@ smbd_kernel_start(void)
int rc;
smb_load_kconfig(&cfg);
+ smbd_get_authconf(&cfg);
rc = smb_kmod_setcfg(&cfg);
if (rc != 0) {
smbd_report("kernel config ioctl error: %s", strerror(rc));
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_ntlmssp.c b/usr/src/cmd/smbsrv/smbd/smbd_ntlmssp.c
new file mode 100644
index 0000000000..8027e3272b
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_ntlmssp.c
@@ -0,0 +1,595 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * SPNEGO back-end for NTLMSSP. See [MS-NLMP]
+ */
+
+#include <sys/types.h>
+#include <sys/byteorder.h>
+#include <strings.h>
+#include "smbd.h"
+#include "smbd_authsvc.h"
+#include "netsmb/ntlmssp.h"
+#include <assert.h>
+
+/* A shorter alias for a crazy long name from [MS-NLMP] */
+#define NTLMSSP_NEGOTIATE_NTLM2 \
+ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+
+/* Need this in a header somewhere */
+#ifdef _LITTLE_ENDIAN
+/* little-endian values on little-endian */
+#define htolel(x) ((uint32_t)(x))
+#define letohl(x) ((uint32_t)(x))
+#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
+/* little-endian values on big-endian (swap) */
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
+#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
+
+typedef struct ntlmssp_backend {
+ uint32_t expect_type;
+ uint32_t clnt_flags;
+ uint32_t srv_flags;
+ char srv_challenge[8];
+} ntlmssp_backend_t;
+
+struct genhdr {
+ char h_id[8]; /* "NTLMSSP" */
+ uint32_t h_type;
+};
+
+struct sec_buf {
+ uint16_t sb_length;
+ uint16_t sb_maxlen;
+ uint32_t sb_offset;
+};
+
+struct nego_hdr {
+ char h_id[8];
+ uint32_t h_type;
+ uint32_t h_flags;
+ /* workstation domain, name (place holders) */
+ uint16_t ws_dom[4];
+ uint16_t ws_name[4];
+};
+
+struct auth_hdr {
+ char h_id[8];
+ uint32_t h_type;
+ struct sec_buf h_lm_resp;
+ struct sec_buf h_nt_resp;
+ struct sec_buf h_domain;
+ struct sec_buf h_user;
+ struct sec_buf h_wksta;
+ struct sec_buf h_essn_key; /* encrypted session key */
+ uint32_t h_flags;
+ /* Version struct (optional) */
+ /* MIC hash (optional) */
+};
+
+/* Allow turning these off for debugging, etc. */
+int smbd_signing_enabled = 1;
+
+int smbd_constant_challenge = 0;
+static uint8_t constant_chal[8] = {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
+
+static int smbd_ntlmssp_negotiate(authsvc_context_t *);
+static int smbd_ntlmssp_authenticate(authsvc_context_t *);
+static int encode_avpair_str(smb_msgbuf_t *, uint16_t, char *);
+static int decode_secbuf_bin(smb_msgbuf_t *, struct sec_buf *, void **);
+static int decode_secbuf_str(smb_msgbuf_t *, struct sec_buf *, char **);
+
+/*
+ * Initialize this context for NTLMSSP, if possible.
+ */
+int
+smbd_ntlmssp_init(authsvc_context_t *ctx)
+{
+ ntlmssp_backend_t *be;
+
+ be = malloc(sizeof (*be));
+ if (be == 0)
+ return (NT_STATUS_NO_MEMORY);
+ bzero(be, sizeof (*be));
+ be->expect_type = NTLMSSP_MSGTYPE_NEGOTIATE;
+ ctx->ctx_backend = be;
+
+ return (0);
+}
+
+void
+smbd_ntlmssp_fini(authsvc_context_t *ctx)
+{
+ free(ctx->ctx_backend);
+}
+
+/*
+ * Handle an auth message
+ */
+int
+smbd_ntlmssp_work(authsvc_context_t *ctx)
+{
+ struct genhdr *ihdr = ctx->ctx_ibodybuf;
+ ntlmssp_backend_t *be = ctx->ctx_backend;
+ uint32_t mtype;
+ int rc;
+
+ if (ctx->ctx_ibodylen < sizeof (*ihdr))
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ if (bcmp(ihdr->h_id, "NTLMSSP", 8))
+ return (NT_STATUS_INVALID_PARAMETER);
+ mtype = letohl(ihdr->h_type);
+ if (mtype != be->expect_type)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ switch (mtype) {
+ case NTLMSSP_MSGTYPE_NEGOTIATE:
+ ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
+ rc = smbd_ntlmssp_negotiate(ctx);
+ break;
+ case NTLMSSP_MSGTYPE_AUTHENTICATE:
+ ctx->ctx_orawtype = LSA_MTYPE_ES_DONE;
+ rc = smbd_ntlmssp_authenticate(ctx);
+ break;
+
+ default:
+ case NTLMSSP_MSGTYPE_CHALLENGE:
+ /* Sent by servers, not received. */
+ rc = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return (rc);
+}
+
+#if (MAXHOSTNAMELEN < NETBIOS_NAME_SZ)
+#error "MAXHOSTNAMELEN < NETBIOS_NAME_SZ"
+#endif
+
+/*
+ * Handle an NTLMSSP_MSGTYPE_NEGOTIATE message, and reply
+ * with an NTLMSSP_MSGTYPE_CHALLENGE message.
+ * See: [MS-NLMP] 2.2.1.1, 3.2.5.1.1
+ */
+static int
+smbd_ntlmssp_negotiate(authsvc_context_t *ctx)
+{
+ char tmp_name[MAXHOSTNAMELEN];
+ ntlmssp_backend_t *be = ctx->ctx_backend;
+ struct nego_hdr *ihdr = ctx->ctx_ibodybuf;
+ smb_msgbuf_t mb;
+ uint8_t *save_scan;
+ int secmode;
+ int mbflags;
+ int rc;
+ size_t var_start, var_end;
+ uint16_t var_size;
+
+ if (ctx->ctx_ibodylen < sizeof (*ihdr))
+ return (NT_STATUS_INVALID_PARAMETER);
+ be->clnt_flags = letohl(ihdr->h_flags);
+
+ /*
+ * Looks like we can ignore ws_dom, ws_name.
+ * Otherwise would parse those here.
+ */
+
+ secmode = smb_config_get_secmode();
+ if (smbd_constant_challenge) {
+ (void) memcpy(be->srv_challenge, constant_chal,
+ sizeof (be->srv_challenge));
+ } else {
+ randomize(be->srv_challenge, sizeof (be->srv_challenge));
+ }
+
+ /*
+ * Compute srv_flags
+ */
+ be->srv_flags =
+ NTLMSSP_REQUEST_TARGET |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_TARGET_INFO;
+ be->srv_flags |= be->clnt_flags & (
+ NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH |
+ NTLMSSP_NEGOTIATE_56);
+
+ if (smbd_signing_enabled) {
+ be->srv_flags |= be->clnt_flags & (
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN);
+ }
+
+ if (be->clnt_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ be->srv_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ else if (be->clnt_flags & NTLMSSP_NEGOTIATE_OEM)
+ be->srv_flags |= NTLMSSP_NEGOTIATE_OEM;
+
+ /* LM Key is mutually exclusive with NTLM2 */
+ if ((be->srv_flags & NTLMSSP_NEGOTIATE_NTLM2) == 0 &&
+ (be->clnt_flags & NTLMSSP_NEGOTIATE_LM_KEY) != 0)
+ be->srv_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+
+ /* Get our "target name" */
+ if (secmode == SMB_SECMODE_DOMAIN) {
+ be->srv_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+ rc = smb_getdomainname(tmp_name, NETBIOS_NAME_SZ);
+ } else {
+ be->srv_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+ rc = smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ);
+ }
+ if (rc)
+ goto errout;
+
+ /*
+ * Build the NTLMSSP_MSGTYPE_CHALLENGE message.
+ */
+ mbflags = SMB_MSGBUF_NOTERM;
+ if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ mbflags |= SMB_MSGBUF_UNICODE;
+ smb_msgbuf_init(&mb, ctx->ctx_obodybuf, ctx->ctx_obodylen, mbflags);
+
+ /*
+ * Fixed size parts
+ */
+ rc = smb_msgbuf_encode(
+ &mb, "8clwwll8cllwwl", /* offset, name (fmt) */
+ "NTLMSSP", /* 0: signature (8c) */
+ NTLMSSP_MSGTYPE_CHALLENGE, /* 8: type (l) */
+ 0, 0, 0, /* filled later: 12: target name (wwl) */
+ be->srv_flags, /* 20: flags (l) */
+ be->srv_challenge, /* 24: (8c) */
+ 0, 0, /* 32: reserved (ll) */
+ 0, 0, 0); /* filled later: 40: target info (wwl) */
+#define TARGET_NAME_OFFSET 12
+#define TARGET_INFO_OFFSET 40
+ if (rc < 0)
+ goto errout;
+
+ /*
+ * Variable length parts.
+ *
+ * Target name
+ */
+ var_start = smb_msgbuf_used(&mb);
+ rc = smb_msgbuf_encode(&mb, "u", tmp_name);
+ var_end = smb_msgbuf_used(&mb);
+ var_size = (uint16_t)(var_end - var_start);
+ if (rc < 0)
+ goto errout;
+
+ /* overwrite target name offset+lengths */
+ save_scan = mb.scan;
+ mb.scan = mb.base + TARGET_NAME_OFFSET;
+ (void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
+ mb.scan = save_scan;
+
+ /*
+ * Target info (AvPairList)
+ *
+ * These AV pairs are like our name/value pairs, but have
+ * numeric identifiers instead of names. There are many
+ * of these, but we put only the four expected by Windows:
+ * NetBIOS computer name
+ * NetBIOS domain name
+ * DNS computer name
+ * DNS domain name
+ * Note that "domain" above (even "DNS domain") refers to
+ * the AD domain of which we're a member, which may be
+ * _different_ from the configured DNS domain.
+ *
+ * Also note that in "workgroup" mode (not a domain member)
+ * all "domain" fields should be set to the same values as
+ * the "computer" fields ("bare" host name, not FQDN).
+ */
+ var_start = smb_msgbuf_used(&mb);
+
+ /* NetBIOS Computer Name */
+ if (smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ))
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvNbComputerName, tmp_name) < 0)
+ goto errout;
+
+ if (secmode != SMB_SECMODE_DOMAIN) {
+ /*
+ * Workgroup mode. Set all to hostname.
+ * tmp_name = netbios hostname from above.
+ */
+ if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
+ goto errout;
+ /*
+ * Want the bare computer name here (not FQDN).
+ */
+ if (smb_gethostname(tmp_name, MAXHOSTNAMELEN, SMB_CASE_LOWER))
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
+ goto errout;
+ } else {
+ /*
+ * Domain mode. Use real host and domain values.
+ */
+
+ /* NetBIOS Domain Name */
+ if (smb_getdomainname(tmp_name, NETBIOS_NAME_SZ))
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
+ goto errout;
+
+ /* DNS Computer Name */
+ if (smb_getfqhostname(tmp_name, MAXHOSTNAMELEN))
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
+ goto errout;
+
+ /* DNS Domain Name */
+ if (smb_getfqdomainname(tmp_name, MAXHOSTNAMELEN))
+ goto errout;
+ if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
+ goto errout;
+ }
+
+ /* End marker */
+ if (smb_msgbuf_encode(&mb, "ww", MsvAvEOL, 0) < 0)
+ goto errout;
+ var_end = smb_msgbuf_used(&mb);
+ var_size = (uint16_t)(var_end - var_start);
+
+ /* overwrite target offset+lengths */
+ save_scan = mb.scan;
+ mb.scan = mb.base + TARGET_INFO_OFFSET;
+ (void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
+ mb.scan = save_scan;
+
+ ctx->ctx_obodylen = smb_msgbuf_used(&mb);
+ smb_msgbuf_term(&mb);
+
+ be->expect_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
+
+ return (0);
+
+errout:
+ smb_msgbuf_term(&mb);
+ return (NT_STATUS_INTERNAL_ERROR);
+}
+
+static int
+encode_avpair_str(smb_msgbuf_t *mb, uint16_t AvId, char *name)
+{
+ int rc;
+ uint16_t len;
+
+ len = smb_wcequiv_strlen(name);
+ rc = smb_msgbuf_encode(mb, "wwU", AvId, len, name);
+ return (rc);
+}
+
+/*
+ * Handle an NTLMSSP_MSGTYPE_AUTHENTICATE message.
+ * See: [MS-NLMP] 2.2.1.3, 3.2.5.1.2
+ */
+static int
+smbd_ntlmssp_authenticate(authsvc_context_t *ctx)
+{
+ struct auth_hdr hdr;
+ smb_msgbuf_t mb;
+ smb_logon_t user_info;
+ smb_token_t *token = NULL;
+ ntlmssp_backend_t *be = ctx->ctx_backend;
+ void *lm_resp;
+ void *nt_resp;
+ char *domain;
+ char *user;
+ char *wksta;
+ void *essn_key; /* encrypted session key (optional) */
+ int mbflags;
+ uint_t status = NT_STATUS_INTERNAL_ERROR;
+ char combined_challenge[SMBAUTH_CHAL_SZ];
+ unsigned char kxkey[SMBAUTH_HASH_SZ];
+ boolean_t ntlm_v1x = B_FALSE;
+
+ bzero(&user_info, sizeof (user_info));
+
+ /*
+ * Parse the NTLMSSP_MSGTYPE_AUTHENTICATE message.
+ */
+ if (ctx->ctx_ibodylen < sizeof (hdr))
+ return (NT_STATUS_INVALID_PARAMETER);
+ mbflags = SMB_MSGBUF_NOTERM;
+ if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ mbflags |= SMB_MSGBUF_UNICODE;
+ smb_msgbuf_init(&mb, ctx->ctx_ibodybuf, ctx->ctx_ibodylen, mbflags);
+ bzero(&hdr, sizeof (hdr));
+
+ if (smb_msgbuf_decode(&mb, "12.") < 0)
+ goto errout;
+ if (decode_secbuf_bin(&mb, &hdr.h_lm_resp, &lm_resp) < 0)
+ goto errout;
+ if (decode_secbuf_bin(&mb, &hdr.h_nt_resp, &nt_resp) < 0)
+ goto errout;
+ if (decode_secbuf_str(&mb, &hdr.h_domain, &domain) < 0)
+ goto errout;
+ if (decode_secbuf_str(&mb, &hdr.h_user, &user) < 0)
+ goto errout;
+ if (decode_secbuf_str(&mb, &hdr.h_wksta, &wksta) < 0)
+ goto errout;
+ if (decode_secbuf_bin(&mb, &hdr.h_essn_key, &essn_key) < 0)
+ goto errout;
+ if (smb_msgbuf_decode(&mb, "l", &be->clnt_flags) < 0)
+ goto errout;
+
+ if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ if (hdr.h_essn_key.sb_length < 16 || essn_key == NULL)
+ goto errout;
+ }
+
+ user_info.lg_level = NETR_NETWORK_LOGON;
+ user_info.lg_flags = 0;
+
+ user_info.lg_ntlm_flags = be->clnt_flags;
+ user_info.lg_username = (user) ? user : "";
+ user_info.lg_domain = (domain) ? domain : "";
+ user_info.lg_workstation = (wksta) ? wksta : "";
+
+ user_info.lg_clnt_ipaddr =
+ ctx->ctx_clinfo.lci_clnt_ipaddr;
+ user_info.lg_local_port = 445;
+
+ user_info.lg_challenge_key.len = SMBAUTH_CHAL_SZ;
+ user_info.lg_challenge_key.val = (uint8_t *)be->srv_challenge;
+
+ user_info.lg_nt_password.len = hdr.h_nt_resp.sb_length;
+ user_info.lg_nt_password.val = nt_resp;
+
+ user_info.lg_lm_password.len = hdr.h_lm_resp.sb_length;
+ user_info.lg_lm_password.val = lm_resp;
+
+ user_info.lg_native_os = ctx->ctx_clinfo.lci_native_os;
+ user_info.lg_native_lm = ctx->ctx_clinfo.lci_native_lm;
+
+ /*
+ * If we're doing extended session security, the challenge
+ * this OWF was computed with is different. [MS-NLMP 3.3.1]
+ * It's: MD5(concat(ServerChallenge,ClientChallenge))
+ * where the ClientChallenge is in the LM resp. field.
+ */
+ if (user_info.lg_nt_password.len == SMBAUTH_LM_RESP_SZ &&
+ user_info.lg_lm_password.len >= SMBAUTH_CHAL_SZ &&
+ (be->clnt_flags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
+ smb_auth_ntlm2_mkchallenge(combined_challenge,
+ be->srv_challenge, lm_resp);
+ user_info.lg_challenge_key.val =
+ (uint8_t *)combined_challenge;
+ user_info.lg_lm_password.len = 0;
+ ntlm_v1x = B_TRUE;
+ }
+
+ /*
+ * This (indirectly) calls smb_auth_validate() to
+ * check that the client gave us a valid hash.
+ */
+ token = smbd_user_auth_logon(&user_info);
+ if (token == NULL) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto errout;
+ }
+
+ if (token->tkn_ssnkey.val != NULL &&
+ token->tkn_ssnkey.len == SMBAUTH_HASH_SZ) {
+
+ /*
+ * At this point, token->tkn_session_key is the
+ * "Session Base Key" [MS-NLMP] 3.2.5.1.2
+ * Compute the final session key. First need the
+ * "Key Exchange Key" [MS-NLMP] 3.4.5.1
+ */
+ if (ntlm_v1x) {
+ smb_auth_ntlm2_kxkey(kxkey,
+ be->srv_challenge, lm_resp,
+ token->tkn_ssnkey.val);
+ } else {
+ /* KXKEY is the Session Base Key. */
+ (void) memcpy(kxkey, token->tkn_ssnkey.val,
+ SMBAUTH_HASH_SZ);
+ }
+
+ /*
+ * If the client give us an encrypted session key,
+ * decrypt it (RC4) using the "key exchange key".
+ */
+ if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ /* RC4 args: result, key, data */
+ (void) smb_auth_RC4(token->tkn_ssnkey.val,
+ SMBAUTH_HASH_SZ, kxkey, SMBAUTH_HASH_SZ,
+ essn_key, hdr.h_essn_key.sb_length);
+ } else {
+ /* Final key is the KXKEY */
+ (void) memcpy(token->tkn_ssnkey.val, kxkey,
+ SMBAUTH_HASH_SZ);
+ }
+ }
+
+ ctx->ctx_token = token;
+ ctx->ctx_obodylen = 0;
+
+ smb_msgbuf_term(&mb);
+ return (0);
+
+errout:
+ smb_msgbuf_term(&mb);
+ return (status);
+}
+
+static int
+decode_secbuf_bin(smb_msgbuf_t *mb, struct sec_buf *sb, void **binp)
+{
+ int rc;
+
+ *binp = NULL;
+ rc = smb_msgbuf_decode(
+ mb, "wwl",
+ &sb->sb_length,
+ &sb->sb_maxlen,
+ &sb->sb_offset);
+ if (rc < 0)
+ return (rc);
+
+ if (sb->sb_offset > mb->max)
+ return (SMB_MSGBUF_UNDERFLOW);
+ if (sb->sb_length > (mb->max - sb->sb_offset))
+ return (SMB_MSGBUF_UNDERFLOW);
+ if (sb->sb_length == 0)
+ return (rc);
+
+ *binp = mb->base + sb->sb_offset;
+ return (0);
+}
+
+static int
+decode_secbuf_str(smb_msgbuf_t *mb, struct sec_buf *sb, char **cpp)
+{
+ uint8_t *save_scan;
+ int rc;
+
+ *cpp = NULL;
+ rc = smb_msgbuf_decode(
+ mb, "wwl",
+ &sb->sb_length,
+ &sb->sb_maxlen,
+ &sb->sb_offset);
+ if (rc < 0)
+ return (rc);
+
+ if (sb->sb_offset > mb->max)
+ return (SMB_MSGBUF_UNDERFLOW);
+ if (sb->sb_length > (mb->max - sb->sb_offset))
+ return (SMB_MSGBUF_UNDERFLOW);
+ if (sb->sb_length == 0)
+ return (rc);
+
+ save_scan = mb->scan;
+ mb->scan = mb->base + sb->sb_offset;
+ rc = smb_msgbuf_decode(mb, "#u", (int)sb->sb_length, cpp);
+ mb->scan = save_scan;
+
+ return (rc);
+}
diff --git a/usr/src/common/smbsrv/smb_msgbuf.c b/usr/src/common/smbsrv/smb_msgbuf.c
index ff94a6243b..54cb75e066 100644
--- a/usr/src/common/smbsrv/smb_msgbuf.c
+++ b/usr/src/common/smbsrv/smb_msgbuf.c
@@ -52,7 +52,6 @@ static int buf_decode(smb_msgbuf_t *, char *, va_list ap);
static int buf_encode(smb_msgbuf_t *, char *, va_list ap);
static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t);
static int smb_msgbuf_chkerc(char *text, int erc);
-static void buf_decode_wcs(smb_wchar_t *, smb_wchar_t *, int wcstrlen);
/*
* Returns the offset or number of bytes used within the buffer.
@@ -216,16 +215,19 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
{
uint32_t ival;
uint8_t c;
- uint8_t *cvalp;
- uint8_t **cvalpp;
+ uint8_t *bvalp;
uint16_t *wvalp;
uint32_t *lvalp;
uint64_t *llvalp;
- smb_wchar_t *wcs;
+ char *cvalp;
+ char **cvalpp;
+ smb_wchar_t wchar;
+ boolean_t repc_specified;
int repc;
int rc;
while ((c = *fmt++) != 0) {
+ repc_specified = B_FALSE;
repc = 1;
if (c == ' ' || c == '\t')
@@ -247,9 +249,11 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
repc = repc * 10 + c - '0';
c = *fmt++;
} while ('0' <= c && c <= '9');
+ repc_specified = B_TRUE;
} else if (c == '#') {
repc = va_arg(ap, int);
c = *fmt++;
+ repc_specified = B_TRUE;
}
switch (c) {
@@ -260,26 +264,26 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
mb->scan += repc;
break;
- case 'c':
+ case 'c': /* get char */
if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_UNDERFLOW);
- cvalp = va_arg(ap, uint8_t *);
- bcopy(mb->scan, cvalp, repc);
+ bvalp = va_arg(ap, uint8_t *);
+ bcopy(mb->scan, bvalp, repc);
mb->scan += repc;
break;
- case 'b':
+ case 'b': /* get byte */
if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_UNDERFLOW);
- cvalp = va_arg(ap, uint8_t *);
+ bvalp = va_arg(ap, uint8_t *);
while (repc-- > 0) {
- *cvalp++ = *mb->scan++;
+ *bvalp++ = *mb->scan++;
}
break;
- case 'w':
+ case 'w': /* get word */
rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
@@ -291,7 +295,7 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
}
break;
- case 'l':
+ case 'l': /* get long */
rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
@@ -303,7 +307,7 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
}
break;
- case 'q':
+ case 'q': /* get quad */
rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
@@ -320,26 +324,30 @@ buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
goto unicode_translation;
/*FALLTHROUGH*/
- case 's':
- ival = strlen((const char *)mb->scan) + 1;
- if (smb_msgbuf_has_space(mb, ival) == 0)
+ case 's': /* get string */
+ if (!repc_specified)
+ repc = strlen((const char *)mb->scan) + 1;
+ if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_UNDERFLOW);
-
- if ((cvalp = smb_msgbuf_malloc(mb, ival * 2)) == 0)
+ if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
return (SMB_MSGBUF_UNDERFLOW);
-
- if ((ival = smb_stombs((char *)cvalp,
- (char *)mb->scan, ival * 2)) ==
- (uint32_t)-1) {
- return (SMB_MSGBUF_DATA_ERROR);
- }
-
- cvalpp = va_arg(ap, uint8_t **);
+ cvalpp = va_arg(ap, char **);
*cvalpp = cvalp;
- mb->scan += (ival+1);
+ /* Translate OEM to mbs */
+ while (repc > 0) {
+ wchar = *mb->scan++;
+ repc--;
+ if (wchar == 0)
+ break;
+ ival = smb_wctomb(cvalp, wchar);
+ cvalp += ival;
+ }
+ *cvalp = '\0';
+ if (repc > 0)
+ mb->scan += repc;
break;
- case 'U': /* Convert from unicode */
+ case 'U': /* get unicode string */
unicode_translation:
/*
* Unicode strings are always word aligned.
@@ -348,35 +356,43 @@ unicode_translation:
* may be longer than the wide-chars.
*/
smb_msgbuf_word_align(mb);
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- wcs = (smb_wchar_t *)mb->scan;
-
- /* count the null wchar */
- repc = sizeof (smb_wchar_t);
- while (*wcs++)
- repc += sizeof (smb_wchar_t);
-
+ if (!repc_specified) {
+ /*
+ * Count bytes, including the null.
+ */
+ uint8_t *tmp_scan = mb->scan;
+ repc = 2; /* the null */
+ while ((wchar = LE_IN16(tmp_scan)) != 0) {
+ tmp_scan += 2;
+ repc += 2;
+ }
+ }
if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_UNDERFLOW);
-
- /* Decode wchar string into host byte-order */
- if ((wcs = smb_msgbuf_malloc(mb, repc)) == 0)
- return (SMB_MSGBUF_UNDERFLOW);
-
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- buf_decode_wcs(wcs, (smb_wchar_t *)mb->scan,
- repc / sizeof (smb_wchar_t));
-
- /* Get space for translated string */
+ /*
+ * Get space for translated string
+ * Allocates worst-case size.
+ */
if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
return (SMB_MSGBUF_UNDERFLOW);
-
- /* Translate string */
- (void) smb_wcstombs((char *)cvalp, wcs, repc * 2);
-
- cvalpp = va_arg(ap, uint8_t **);
+ cvalpp = va_arg(ap, char **);
*cvalpp = cvalp;
- mb->scan += repc;
+ /*
+ * Translate unicode to mbs, stopping after
+ * null or repc limit.
+ */
+ while (repc >= 2) {
+ wchar = LE_IN16(mb->scan);
+ mb->scan += 2;
+ repc -= 2;
+ if (wchar == 0)
+ break;
+ ival = smb_wctomb(cvalp, wchar);
+ cvalp += ival;
+ }
+ *cvalp = '\0';
+ if (repc > 0)
+ mb->scan += repc;
break;
case 'M':
@@ -447,15 +463,17 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
uint16_t wval;
uint32_t lval;
uint64_t llval;
- uint32_t ival;
- uint8_t *cvalp;
+ uint8_t *bvalp;
+ char *cvalp;
uint8_t c;
- smb_wchar_t wcval;
+ smb_wchar_t wchar;
int count;
- int repc = 1;
+ boolean_t repc_specified;
+ int repc;
int rc;
while ((c = *fmt++) != 0) {
+ repc_specified = B_FALSE;
repc = 1;
if (c == ' ' || c == '\t')
@@ -477,9 +495,11 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
repc = repc * 10 + c - '0';
c = *fmt++;
} while ('0' <= c && c <= '9');
+ repc_specified = B_TRUE;
} else if (c == '#') {
repc = va_arg(ap, int);
c = *fmt++;
+ repc_specified = B_TRUE;
}
switch (c) {
@@ -491,16 +511,16 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
*mb->scan++ = 0;
break;
- case 'c':
+ case 'c': /* put char */
if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_OVERFLOW);
- cvalp = va_arg(ap, uint8_t *);
- bcopy(cvalp, mb->scan, repc);
+ bvalp = va_arg(ap, uint8_t *);
+ bcopy(bvalp, mb->scan, repc);
mb->scan += repc;
break;
- case 'b':
+ case 'b': /* put byte */
if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_OVERFLOW);
@@ -510,7 +530,7 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
}
break;
- case 'w':
+ case 'w': /* put word */
rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
@@ -522,7 +542,7 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
}
break;
- case 'l':
+ case 'l': /* put long */
rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
@@ -534,7 +554,7 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
}
break;
- case 'q':
+ case 'q': /* put quad */
rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
@@ -551,66 +571,79 @@ buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
goto unicode_translation;
/* FALLTHROUGH */
- case 's':
- cvalp = va_arg(ap, uint8_t *);
- ival = strlen((const char *)cvalp) + 1;
-
- if (smb_msgbuf_has_space(mb, ival) == 0)
+ case 's': /* put string */
+ cvalp = va_arg(ap, char *);
+ if (!repc_specified) {
+ repc = smb_sbequiv_strlen(cvalp);
+ if (repc == -1)
+ return (SMB_MSGBUF_OVERFLOW);
+ if (!(mb->flags & SMB_MSGBUF_NOTERM))
+ repc++;
+ }
+ if (smb_msgbuf_has_space(mb, repc) == 0)
return (SMB_MSGBUF_OVERFLOW);
-
- ival =
- smb_mbstos((char *)mb->scan, (const char *)cvalp);
- mb->scan += ival + 1;
+ while (repc > 0) {
+ count = smb_mbtowc(&wchar, cvalp,
+ MTS_MB_CHAR_MAX);
+ if (count < 0)
+ return (SMB_MSGBUF_DATA_ERROR);
+ cvalp += count;
+ if (wchar == 0)
+ break;
+ *mb->scan++ = (uint8_t)wchar;
+ repc--;
+ if (wchar & 0xff00) {
+ *mb->scan++ = wchar >> 8;
+ repc--;
+ }
+ }
+ if (*cvalp == '\0' && repc > 0 &&
+ (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
+ *mb->scan++ = 0;
+ repc--;
+ }
+ while (repc > 0) {
+ *mb->scan++ = 0;
+ repc--;
+ }
break;
- case 'U': /* unicode */
+ case 'U': /* put unicode string */
unicode_translation:
/*
* Unicode strings are always word aligned.
*/
smb_msgbuf_word_align(mb);
- cvalp = va_arg(ap, uint8_t *);
-
- for (;;) {
- rc = smb_msgbuf_has_space(mb,
- sizeof (smb_wchar_t));
- if (rc == 0)
- return (SMB_MSGBUF_OVERFLOW);
-
- count = smb_mbtowc(&wcval, (const char *)cvalp,
+ cvalp = va_arg(ap, char *);
+ if (!repc_specified) {
+ repc = smb_wcequiv_strlen(cvalp);
+ if (!(mb->flags & SMB_MSGBUF_NOTERM))
+ repc += 2;
+ }
+ if (!smb_msgbuf_has_space(mb, repc))
+ return (SMB_MSGBUF_OVERFLOW);
+ while (repc >= 2) {
+ count = smb_mbtowc(&wchar, cvalp,
MTS_MB_CHAR_MAX);
-
- if (count < 0) {
+ if (count < 0)
return (SMB_MSGBUF_DATA_ERROR);
- } else if (count == 0) {
- /*
- * No longer need to do this now that
- * mbtowc correctly writes the null
- * before returning zero but paranoia
- * wins.
- */
- wcval = 0;
- count = 1;
- }
-
- /* Write wchar in wire-format */
- LE_OUT16(mb->scan, wcval);
-
- if (*cvalp == 0) {
- /*
- * End of string. Check to see whether
- * or not to include the null
- * terminator.
- */
- if ((mb->flags & SMB_MSGBUF_NOTERM) ==
- 0)
- mb->scan +=
- sizeof (smb_wchar_t);
+ cvalp += count;
+ if (wchar == 0)
break;
- }
- mb->scan += sizeof (smb_wchar_t);
- cvalp += count;
+ LE_OUT16(mb->scan, wchar);
+ mb->scan += 2;
+ repc -= 2;
+ }
+ if (*cvalp == '\0' && repc >= 2 &&
+ (mb->flags & SMB_MSGBUF_NOTERM) == 0) {
+ LE_OUT16(mb->scan, 0);
+ mb->scan += 2;
+ repc -= 2;
+ }
+ while (repc > 0) {
+ *mb->scan++ = 0;
+ repc--;
}
break;
@@ -695,15 +728,3 @@ smb_msgbuf_chkerc(char *text, int erc)
}
return (erc);
}
-
-static void
-buf_decode_wcs(smb_wchar_t *dst_wcstr, smb_wchar_t *src_wcstr, int wcstrlen)
-{
- int i;
-
- for (i = 0; i < wcstrlen; i++) {
- *dst_wcstr = LE_IN16(src_wcstr);
- dst_wcstr++;
- src_wcstr++;
- }
-}
diff --git a/usr/src/common/smbsrv/smb_token.c b/usr/src/common/smbsrv/smb_token.c
index b77b9a44a0..e1f63c6df7 100644
--- a/usr/src/common/smbsrv/smb_token.c
+++ b/usr/src/common/smbsrv/smb_token.c
@@ -165,17 +165,4 @@ smb_logon_free(smb_logon_t *obj)
xdr_free(smb_logon_xdr, (char *)obj);
free(obj);
}
-#else /* _KERNEL */
-/*
- * Tokens are allocated in the kernel via XDR.
- * Call xdr_free before freeing the token structure.
- */
-void
-smb_token_free(smb_token_t *token)
-{
- if (token != NULL) {
- xdr_free(smb_token_xdr, (char *)token);
- kmem_free(token, sizeof (smb_token_t));
- }
-}
#endif /* _KERNEL */
diff --git a/usr/src/common/smbsrv/smb_token_xdr.c b/usr/src/common/smbsrv/smb_token_xdr.c
index 6b44899768..fdad7ed5ca 100644
--- a/usr/src/common/smbsrv/smb_token_xdr.c
+++ b/usr/src/common/smbsrv/smb_token_xdr.c
@@ -21,6 +21,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -154,15 +156,6 @@ smb_posix_grps_helper_xdr(XDR *xdrs, char **identity)
return (TRUE);
}
-static bool_t
-smb_session_key_xdr(XDR *xdrs, smb_session_key_t *objp)
-{
- if (!xdr_vector(xdrs, (char *)objp->data, 16,
- sizeof (uint8_t), (xdrproc_t)xdr_uint8_t))
- return (FALSE);
- return (TRUE);
-}
-
bool_t
smb_logon_xdr(XDR *xdrs, smb_logon_t *objp)
{
@@ -190,6 +183,8 @@ smb_logon_xdr(XDR *xdrs, smb_logon_t *objp)
return (FALSE);
if (!smb_buf32_xdr(xdrs, &objp->lg_lm_password))
return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->lg_ntlm_flags))
+ return (FALSE);
if (!xdr_int(xdrs, &objp->lg_native_os))
return (FALSE);
if (!xdr_int(xdrs, &objp->lg_native_lm))
@@ -278,8 +273,7 @@ smb_token_xdr(XDR *xdrs, smb_token_t *objp)
return (FALSE);
if (!xdr_uint32_t(xdrs, &objp->tkn_audit_sid))
return (FALSE);
- if (!xdr_pointer(xdrs, (char **)&objp->tkn_session_key,
- sizeof (smb_session_key_t), (xdrproc_t)smb_session_key_xdr))
+ if (!smb_buf32_xdr(xdrs, &objp->tkn_ssnkey))
return (FALSE);
if (!smb_posix_grps_helper_xdr(xdrs, (char **)&objp->tkn_posix_grps))
return (FALSE);
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 704d7ba772..544a04dd33 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -19,11 +19,11 @@
# CDDL HEADER END
#
-# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright (c) 2013 Gary Mills
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright (c) 2015 Gary Mills
@@ -660,7 +660,8 @@ libexacct/demo: libexacct libproject libsocket libnsl
libtsalarm: libpcp
smbsrv: libsocket libnsl libmd libxnet libpthread librt \
libshare libidmap pkcs11 libsqlite libcryptoutil \
- libreparse libcmdutils libfakekernel
+ libreparse libcmdutils libresolv libsmbfs libuuid \
+ libfakekernel
libv12n: libds libuuid
libvrrpadm: libsocket libdladm libscf
libvscan: libscf
diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c
index 3138920e9b..967c8f7fe4 100644
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c
@@ -1,5 +1,7 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/*
* lib/krb5/krb/get_in_tkt.c
*
@@ -130,6 +132,12 @@ send_as_request2(krb5_context context,
reply.data = 0;
+ /* Solaris Kerberos (illumos) */
+ if (krb5_getenv("MS_INTEROP")) {
+ /* Don't bother with UDP. */
+ tcp_only = 1;
+ }
+
/* set the nonce if the caller expects us to do it */
if (request->nonce == 0) {
if ((retval = krb5_timeofday(context, &time_now)))
diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c
index f3e159e6f9..10cdcdd502 100644
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -176,6 +177,12 @@ krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions,
if (!in_cred->ticket.length)
return(KRB5_NO_TKT_SUPPLIED);
+ /* Solaris Kerberos (illumos) */
+ if (krb5_getenv("MS_INTEROP")) {
+ /* Don't bother with UDP. */
+ tcp_only = 1;
+ }
+
memset((char *)&tgsreq, 0, sizeof(tgsreq));
tgsreq.kdc_options = kdcoptions;
diff --git a/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c b/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c
index b15cbbf14b..b5ec62c921 100644
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -258,10 +259,12 @@ gss_krb5int_extract_authz_data_from_sec_context(
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
+ gss_buffer_desc ad_data;
OM_uint32 major_status;
+ krb5_error_code code;
krb5_gss_ctx_id_rec *ctx;
int ad_type = 0;
- size_t i;
+ int i, j;
*data_set = GSS_C_NO_BUFFER_SET;
@@ -280,7 +283,6 @@ gss_krb5int_extract_authz_data_from_sec_context(
if (ctx->authdata != NULL) {
for (i = 0; ctx->authdata[i] != NULL; i++) {
if (ctx->authdata[i]->ad_type == ad_type) {
- gss_buffer_desc ad_data;
ad_data.length = ctx->authdata[i]->length;
ad_data.value = ctx->authdata[i]->contents;
@@ -289,10 +291,39 @@ gss_krb5int_extract_authz_data_from_sec_context(
&ad_data, data_set);
if (GSS_ERROR(major_status))
break;
+ } else if (ctx->authdata[i]->ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
+ /*
+ * Solaris Kerberos (illumos)
+ * Unwrap the AD-IF-RELEVANT object and look inside.
+ */
+ krb5_authdata **ad_if_relevant = NULL;
+ code = krb5_decode_authdata_container(ctx->k5_context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ ctx->authdata[i],
+ &ad_if_relevant);
+ if (code != 0)
+ continue;
+
+ for (j = 0; ad_if_relevant[j] != NULL; j++) {
+ if (ad_if_relevant[j]->ad_type == ad_type) {
+ ad_data.length = ad_if_relevant[j]->length;
+ ad_data.value = ad_if_relevant[j]->contents;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status,
+ &ad_data, data_set);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_authdata(ctx->k5_context, ad_if_relevant);
+ goto break2;
+ }
+ }
+ }
+ krb5_free_authdata(ctx->k5_context, ad_if_relevant);
+ /* Solaris Kerberos (illumos) */
}
}
}
+break2:
if (GSS_ERROR(major_status)) {
OM_uint32 tmp;
diff --git a/usr/src/lib/libshare/smb/Makefile.com b/usr/src/lib/libshare/smb/Makefile.com
index 0fc5f66142..ea69f59b22 100644
--- a/usr/src/lib/libshare/smb/Makefile.com
+++ b/usr/src/lib/libshare/smb/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
#
LIBRARY = libshare_smb.a
@@ -45,8 +45,7 @@ LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
lintcheck := SRCS = $(LIBSRCS)
LIBS = $(DYNLIB)
-LDLIBS += -lshare -ldlpi -lnsl -lnvpair -lscf -lumem -lc
-all install := LDLIBS += -lxml2
+LDLIBS += -lshare -lscf -luuid -ldlpi -lnsl -lnvpair -lxml2 -lumem -lc
CFLAGS += $(CCVERBOSE)
CERRWARN += -_gcc=-Wno-char-subscripts
diff --git a/usr/src/lib/libsmbfs/Makefile b/usr/src/lib/libsmbfs/Makefile
index 47c14c6bfa..b708bd0571 100644
--- a/usr/src/lib/libsmbfs/Makefile
+++ b/usr/src/lib/libsmbfs/Makefile
@@ -19,10 +19,11 @@
# 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.
+#
#
# lib/libsmbfs/Makefile
@@ -30,7 +31,7 @@
include $(SRC)/lib/Makefile.lib
-HDRS= smbfs_acl.h smbfs_api.h smb_keychain.h
+HDRS= ntlmssp.h smbfs_acl.h smbfs_api.h smb_keychain.h spnego.h
HDRDIR= netsmb
ROOTHDRDIR= $(ROOT)/usr/include/netsmb
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index a3ec0fb397..f5801a18db 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -23,6 +23,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+#
#
# lib/libsmbfs/Makefile.com
@@ -101,7 +103,7 @@ CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-unused-variable
CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
- -I$(SRCDIR) -I.. \
+ -I$(SRCDIR) -I.. -I../netsmb \
-I$(SRC)/uts/common \
-I$(SRC)/common/smbclnt
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.h b/usr/src/lib/libsmbfs/netsmb/ntlmssp.h
index 5f3e09ac0d..f4cfc34783 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.h
+++ b/usr/src/lib/libsmbfs/netsmb/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.
*/
@@ -37,6 +38,10 @@
* http://msdn.microsoft.com/en-us/library/cc236621(PROT.10).aspx
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* NTLMSSP Message Types
* [MS-NLMP] sec. 2.2.1
@@ -82,4 +87,28 @@
#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000
+/*
+ * NTLMSSP AV_PAIR types
+ * [MS-NLMP] sec. 2.2.2.1
+ *
+ * The names are all LE-Unicode.
+ */
+typedef enum ntlmssp_AvId {
+ MsvAvEOL = 0, /* End Of List */
+ MsvAvNbComputerName, /* server's NetBIOS name */
+ MsvAvNbDomainName, /* server's NetBIOS domain */
+ MsvAvDnsComputerName, /* server's DNS name */
+ MsvAvDnsDomainName, /* server's DNS domain */
+ MsvAvDnsTreeName, /* server's Forest name */
+ MsvAvFlags, /* 32-bit (LE) flags */
+ MsvAvTimestamp, /* 64-bit time, [MS-DTYP] sec. 2.3.1 */
+ MsvAvRestrictions, /* struct, [MS-NLMP] sec. 2.2.2.2 */
+ MsvAvTargetName, /* SPN of the server */
+ MsvChannelBindings, /* MD5 hash of GSS challen bindings */
+} ntlmssp_AvId_t;
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _NTLMSSP_H */
diff --git a/usr/src/lib/libsmbfs/netsmb/spnego.h b/usr/src/lib/libsmbfs/netsmb/spnego.h
new file mode 100644
index 0000000000..1a60436740
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/spnego.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2002 Microsoft Corporation
+ * All rights reserved.
+ *
+ * THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+ * AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Date - 10/08/2002
+ * Author - Sanj Surati
+ */
+
+/*
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * spnego.h
+ *
+ * SPNEGO Token Handler Header File
+ *
+ * Contains the definitions required to interpret and create
+ * SPNEGO tokens so that Kerberos GSS tokens can be
+ * Unpackaged/packaged.
+ */
+
+#ifndef _SPNEGO_H
+#define _SPNEGO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Type Definitions
+ */
+
+/*
+ * Users of SPNEGO Token Handler API will request
+ * these as well as free them,
+ */
+typedef void* SPNEGO_TOKEN_HANDLE;
+
+/*
+ * Defines the element types that are found
+ * in each of the tokens.
+ */
+
+typedef enum spnego_element_type
+{
+ spnego_element_min, /* Lower bound */
+
+ /* Init token elements */
+ spnego_init_mechtypes,
+ spnego_init_reqFlags,
+ spnego_init_mechToken,
+ spnego_init_mechListMIC,
+
+ /* Targ token elements */
+ spnego_targ_negResult,
+ spnego_targ_supportedMech,
+ spnego_targ_responseToken,
+ spnego_targ_mechListMIC,
+
+ spnego_element_max /* Upper bound */
+
+} SPNEGO_ELEMENT_TYPE;
+
+/*
+ * Token Element Availability. Elements in both
+ * token types are optional. Since there are only
+ * 4 elements in each Token, we will allocate space
+ * to hold the information, but we need a way to
+ * indicate whether or not an element is available
+ */
+
+#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0
+#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1
+
+/*
+ * Token type values. SPNEGO has 2 token types:
+ * NegTokenInit and NegTokenTarg
+ */
+
+#define SPNEGO_TOKEN_INIT 0
+#define SPNEGO_TOKEN_TARG 1
+
+/*
+ * GSS Mechanism OID enumeration. We only really handle
+ * 3 different OIDs. These are stored in an array structure
+ * defined in the parsing code.
+ */
+
+typedef enum spnego_mech_oid
+{
+ /* Init token elements */
+ spnego_mech_oid_Kerberos_V5_Legacy, /* Really V5, but OID off by 1 */
+ spnego_mech_oid_Kerberos_V5,
+ spnego_mech_oid_Spnego,
+ spnego_mech_oid_NTLMSSP,
+ spnego_mech_oid_NotUsed = -1
+
+} SPNEGO_MECH_OID;
+
+/*
+ * Defines the negResult values.
+ */
+
+typedef enum spnego_negResult
+{
+ spnego_negresult_success,
+ spnego_negresult_incomplete,
+ spnego_negresult_rejected,
+ spnego_negresult_NotUsed = -1
+} SPNEGO_NEGRESULT;
+
+/*
+ * Context Flags in NegTokenInit
+ */
+
+/*
+ * ContextFlags values MUST be zero or a combination
+ * of the below
+ */
+
+#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80
+#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40
+#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20
+#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10
+#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8
+#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4
+#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2
+
+/*
+ * Mask to retrieve valid values.
+ */
+
+#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE
+
+/*
+ * SPNEGO API return codes.
+ */
+
+/* API function was successful */
+#define SPNEGO_E_SUCCESS 0
+
+/* The supplied Token was invalid */
+#define SPNEGO_E_INVALID_TOKEN -1
+
+/* An invalid length was encountered */
+#define SPNEGO_E_INVALID_LENGTH -2
+
+/* The Token Parse failed */
+#define SPNEGO_E_PARSE_FAILED -3
+
+/* The requested value was not found */
+#define SPNEGO_E_NOT_FOUND -4
+
+/* The requested element is not available */
+#define SPNEGO_E_ELEMENT_UNAVAILABLE -5
+
+/* Out of Memory */
+#define SPNEGO_E_OUT_OF_MEMORY -6
+
+/* Not Implemented */
+#define SPNEGO_E_NOT_IMPLEMENTED -7
+
+/* Invalid Parameter */
+#define SPNEGO_E_INVALID_PARAMETER -8
+
+/* Token Handler encountered an unexpected OID */
+#define SPNEGO_E_UNEXPECTED_OID -9
+
+/* The requested token was not found */
+#define SPNEGO_E_TOKEN_NOT_FOUND -10
+
+/* An unexpected type was encountered in the encoding */
+#define SPNEGO_E_UNEXPECTED_TYPE -11
+
+/* The buffer was too small */
+#define SPNEGO_E_BUFFER_TOO_SMALL -12
+
+/* A Token Element was invalid (e.g. improper length or value) */
+#define SPNEGO_E_INVALID_ELEMENT -13
+
+/* Miscelaneous API Functions */
+
+/* Frees opaque data */
+void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken);
+
+/* Initializes SPNEGO_TOKEN structure from DER encoded binary data */
+int spnegoInitFromBinary(unsigned char *pbTokenData, unsigned long ulLength,
+ SPNEGO_TOKEN_HANDLE* phSpnegoToken);
+
+/* Initializes SPNEGO_TOKEN structure for a NegTokenInit type */
+int spnegoCreateNegTokenHint(SPNEGO_MECH_OID *pMechTypeList, int MechTypeCnt,
+ unsigned char *pbPrincipal, SPNEGO_TOKEN_HANDLE* phSpnegoToken);
+
+/* Initializes SPNEGO_TOKEN structure for a NegTokenInit type */
+int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType,
+ unsigned char ucContextFlags, unsigned char *pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char *pbMechTokenMIC,
+ unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE *phSpnegoToken);
+
+/* Initializes SPNEGO_TOKEN structure for a NegTokenTarg type */
+int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT spnegoNegResult, unsigned char *pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char *pbMechListMIC,
+ unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken);
+
+/* Copies binary representation of SPNEGO Data into user supplied buffer */
+int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ unsigned char *pbTokenData, unsigned long *pulDataLen);
+
+/* Returns SPNEGO Token Type */
+int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int *piTokenType);
+
+/* Reading an Init Token */
+
+/* Returns the Initial Mech Type in the MechList element in the NegInitToken. */
+int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ SPNEGO_MECH_OID MechOID, int *piMechTypeIndex);
+
+/* Returns the value from the context flags element in the NegInitToken */
+int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ unsigned char *pucContextFlags);
+
+/* Reading a Response Token */
+
+/*
+ * Returns the value from the negResult element
+ * (Status code of GSS call - 0,1,2)
+ */
+int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ SPNEGO_NEGRESULT* pnegResult);
+
+/* Returns the Supported Mech Type from the NegTokenTarg. */
+int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ SPNEGO_MECH_OID* pMechOID);
+
+/* Reading either Token Type */
+
+/*
+ * Returns the actual Mechanism data from the token
+ * (this is what is passed into GSS-API functions
+ */
+int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ unsigned char *pbTokenData, unsigned long *pulDataLen);
+
+/* Returns the Message Integrity BLOB in the token */
+int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken,
+ unsigned char *pbMICData, unsigned long *pulDataLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SPNEGO_H */
diff --git a/usr/src/lib/libsmbfs/smb/derparse.c b/usr/src/lib/libsmbfs/smb/derparse.c
index f92da913c2..f21a277d5a 100644
--- a/usr/src/lib/libsmbfs/smb/derparse.c
+++ b/usr/src/lib/libsmbfs/smb/derparse.c
@@ -1,3 +1,4 @@
+// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -451,29 +452,37 @@ long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
// Comments :
// Helper function to calculate a MechList length. A mechlist consists
// of a NegTokenInit sequence token, a sequence token for the MechList
-// and finally a list of OIDs. In our case, we only really have one
-// OID.
+// and finally a list of OIDs.
//
////////////////////////////////////////////////////////////////////////////
-long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID *mechOidLst, int mechOidCnt,
+ long* pnInternalLength )
{
- // First the OID
- long nTotalLength = g_stcMechOIDList[mechoid].iLen;
-
- // Next add in a sequence token
- nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
-
- // Internal length is the length without the element sequence token
- if ( NULL != pnInternalLength )
- {
- *pnInternalLength = nTotalLength;
- }
-
- // Finally add in the element's sequence token
- nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
-
- return nTotalLength;
+ // First the OID
+ SPNEGO_MECH_OID oid_idx;
+ long nTotalLength;
+ int i;
+
+ nTotalLength = 0;
+ for (i = 0; i < mechOidCnt; i++) {
+ oid_idx = mechOidLst[i];
+ nTotalLength += g_stcMechOIDList[oid_idx].iLen;
+ }
+
+ // Next add in a sequence token
+ nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Internal length is the length without the element sequence token
+ if ( NULL != pnInternalLength )
+ {
+ *pnInternalLength = nTotalLength;
+ }
+
+ // Finally add in the element's sequence token
+ nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ return nTotalLength;
}
@@ -646,9 +655,12 @@ int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
{
- memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
+ if (pbData != NULL) {
+ memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid,
+ g_stcMechOIDList[eMechOID].iLen );
+ }
- return g_stcMechOIDList[eMechOID].iLen;
+ return g_stcMechOIDList[eMechOID].iLen;
}
@@ -671,27 +683,35 @@ int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
//
////////////////////////////////////////////////////////////////////////////
-long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt )
{
- // First get the length
- long nInternalLength = 0L;
- long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
- long nTempLength = 0L;
-
- nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
+ // First get the length
+ long nInternalLength = 0L;
+ long nMechListLength;
+ long nTempLength = 0L;
+ int i;
+
+ nMechListLength = ASNDerCalcMechListLength(mechOidLst, mechOidCnt, &nInternalLength);
+ nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
NULL, nInternalLength );
- // Adjust the data pointer
- pbData += nTempLength;
+ // Adjust the data pointer
+ pbData += nTempLength;
+ nInternalLength -= nTempLength;
+
+ // Now write the Sequence token and the OID (the OID is a BLOB in the global
+ // structure.
- // Now write the Sequence token and the OID (the OID is a BLOB in the global
- // structure.
+ nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ NULL, nInternalLength);
+ pbData += nTempLength;
- nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
- g_stcMechOIDList[mechoid].ucOid,
- g_stcMechOIDList[mechoid].iLen );
+ for (i = 0; i < mechOidCnt; i++) {
+ nTempLength = ASNDerWriteOID( pbData, mechOidLst[i] );
+ pbData += nTempLength;
+ }
- return nMechListLength;
+ return nMechListLength;
}
diff --git a/usr/src/lib/libsmbfs/smb/derparse.h b/usr/src/lib/libsmbfs/smb/derparse.h
index dcdf5828dc..b1801c8e1c 100644
--- a/usr/src/lib/libsmbfs/smb/derparse.h
+++ b/usr/src/lib/libsmbfs/smb/derparse.h
@@ -1,3 +1,4 @@
+// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -21,8 +22,6 @@
//
/////////////////////////////////////////////////////////////
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef __DERPARSE_H__
#define __DERPARSE_H__
@@ -178,12 +177,13 @@ int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long n
int ASNDerCalcNumLengthBytes( long nLength );
long ASNDerCalcTokenLength( long nLength, long nDataLength );
long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength );
-long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength );
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID *mechOidLst, int mechOidCnt,
+ long* pnInternalLength );
int ASNDerWriteLength( unsigned char* pbData, long nLength );
int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
unsigned char* pbTokenValue, long nLength );
int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID );
-long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid );
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt );
int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
unsigned char ucType, unsigned char* pbTokenValue, long nLength );
diff --git a/usr/src/lib/libsmbfs/smb/llib-lsmbfs b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
index e8e05e4272..1096482541 100644
--- a/usr/src/lib/libsmbfs/smb/llib-lsmbfs
+++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*LINTLIBRARY*/
@@ -34,4 +36,5 @@
#include <netsmb/smb_keychain.h>
#include <netsmb/smb_netshareenum.h>
#include <netsmb/smb_rap.h>
+#include <netsmb/spnego.h>
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 1c2a5d6fa9..24bffec63d 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -18,8 +18,8 @@
# CDDL HEADER END
#
#
-# 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.
#
#
@@ -151,6 +151,20 @@ SYMBOL_VERSION SUNWprivate {
smbfs_set_default_user;
smbutil_std_opts;
+
+ spnegoCreateNegTokenHint;
+ spnegoCreateNegTokenInit;
+ spnegoCreateNegTokenTarg;
+ spnegoFreeData;
+ spnegoGetContextFlags;
+ spnegoGetMechListMIC;
+ spnegoGetMechToken;
+ spnegoGetNegotiationResult;
+ spnegoGetSupportedMechType;
+ spnegoGetTokenType;
+ spnegoInitFromBinary;
+ spnegoIsMechTypeAvailable;
+ spnegoTokenGetBinary;
local:
*;
};
diff --git a/usr/src/lib/libsmbfs/smb/spnego.c b/usr/src/lib/libsmbfs/smb/spnego.c
index 3e300cd606..a15303da30 100644
--- a/usr/src/lib/libsmbfs/smb/spnego.c
+++ b/usr/src/lib/libsmbfs/smb/spnego.c
@@ -1,3 +1,4 @@
+// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -21,10 +22,9 @@
//
/////////////////////////////////////////////////////////////
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <memory.h>
#include "spnego.h"
#include "derparse.h"
@@ -89,6 +89,111 @@ int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SP
/////////////////////////////////////////////////////////////////////////////
//
// Function:
+// spnegoCreateNegTokenHint
+//
+// Parameters:
+// [in] pMechTypeList - List of MechTypes (OIDs) to include
+// [in] MechTypeCnt - Length of MechTypes array
+// [in] pbPrincipal - Principal name for MechListMIC
+// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type token
+// from the supplied parameters. The token created is the "hint"
+// used (for example) in the response to an SMB negotiate protocol.
+// Returned data structure must be freed by calling spnegoFreeData().
+//
+// The "hint" tells the client what authentication methods this
+// server supports (the ones in the MechTypeList). The Principal
+// name historically was the server's own SPN, but recent versions
+// of windows only supply: "not_defined_in_RFC4178@please_ignore"
+// So if you want to be nice to your clients, provide the host SPN,
+// otherwise provide the bogus SPN string like recent windows.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoCreateNegTokenHint( SPNEGO_MECH_OID *pMechTypeList, int MechTypeCnt,
+ unsigned char *pbPrincipal, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+ int nReturn;
+ long nTokenLength = 0L;
+ long nInternalTokenLength = 0L;
+ unsigned long ulPrincipalLen;
+ unsigned char* pbMechListMIC;
+ unsigned long ulMechListMICLen;
+ unsigned char* pbTokenData = NULL;
+ SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+ if ( NULL == ppSpnegoToken || NULL == pbPrincipal )
+ return (SPNEGO_E_INVALID_PARAMETER);
+
+ /*
+ * Get the actual token size
+ */
+ ulPrincipalLen = strlen((char *)pbPrincipal);
+ ulMechListMICLen = ASNDerCalcElementLength( ulPrincipalLen, NULL );
+ nReturn = CalculateMinSpnegoInitTokenSize(
+ 0, /* ulMechTokenLen */
+ ulMechListMICLen,
+ pMechTypeList,
+ MechTypeCnt,
+ 0, /* nReqFlagsAvailable */
+ &nTokenLength,
+ &nInternalTokenLength );
+ if ( nReturn != SPNEGO_E_SUCCESS )
+ return (nReturn);
+
+ // Allocate a buffer to hold the data.
+ pbTokenData = calloc( 1, nTokenLength );
+
+ if ( NULL == pbTokenData )
+ return ( SPNEGO_E_OUT_OF_MEMORY );
+
+ /*
+ * Construct the MechListMIC
+ */
+ pbMechListMIC = pbTokenData + (nTokenLength - ulMechListMICLen);
+ (void) ASNDerWriteElement( pbMechListMIC, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
+ GENERALSTR, pbPrincipal, ulPrincipalLen );
+
+ // Now write the token
+ nReturn = CreateSpnegoInitToken(
+ pMechTypeList,
+ MechTypeCnt,
+ 0, /* ContextFlags */
+ NULL, 0, /* MechToken, len */
+ pbMechListMIC,
+ ulMechListMICLen,
+ pbTokenData,
+ nTokenLength,
+ nInternalTokenLength );
+ if ( nReturn != SPNEGO_E_SUCCESS ) {
+ free( pbTokenData );
+ return (nReturn);
+ }
+
+ // This will copy our allocated pointer, and ensure that the sructure cleans
+ // up the data later
+ nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
+ SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
+ pbTokenData, nTokenLength, ppSpnegoToken );
+
+ // Cleanup on failure
+ if ( nReturn != SPNEGO_E_SUCCESS ) {
+ free( pbTokenData );
+ return (nReturn);
+ }
+
+ return (SPNEGO_E_SUCCESS);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
// spnegoCreateNegTokenInit
//
// Parameters:
@@ -131,7 +236,7 @@ int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
// Get the actual token size
if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen,
- MechType, ( ucContextFlags != 0L ),
+ &MechType, 1, ( ucContextFlags != 0L ),
&nTokenLength, &nInternalTokenLength ) )
== SPNEGO_E_SUCCESS )
{
@@ -142,7 +247,7 @@ int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
{
// Now write the token
- if ( ( nReturn = CreateSpnegoInitToken( MechType,
+ if ( ( nReturn = CreateSpnegoInitToken( &MechType, 1,
ucContextFlags, pbMechToken,
ulMechTokenLen, pbMechListMIC,
ulMechListMICLen, pbTokenData,
@@ -227,11 +332,7 @@ int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType,
spnego_mech_oid_NotUsed == MechType ) &&
( IsValidNegResult( spnegoNegResult ) ||
- spnego_negresult_NotUsed == spnegoNegResult ) &&
-
- !( !IsValidMechOid( MechType ) &&
- ( spnego_negresult_success == spnegoNegResult ||
- spnego_negresult_incomplete == spnegoNegResult ) ) )
+ spnego_negresult_NotUsed == spnegoNegResult ) )
{
// Get the actual token size
diff --git a/usr/src/lib/libsmbfs/smb/spnego.h b/usr/src/lib/libsmbfs/smb/spnego.h
deleted file mode 100644
index 9865fbd85d..0000000000
--- a/usr/src/lib/libsmbfs/smb/spnego.h
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (C) 2002 Microsoft Corporation
-// All rights reserved.
-//
-// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
-// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-// OR IMPLIED, INCLUDING BUT NOT LIMITED
-// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
-// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Date - 10/08/2002
-// Author - Sanj Surati
-
-/////////////////////////////////////////////////////////////
-//
-// SPNEGO.H
-//
-// SPNEGO Token Handler Header File
-//
-// Contains the definitions required to interpret and create
-// SPNEGO tokens so that Kerberos GSS tokens can be
-// Unpackaged/packaged.
-//
-/////////////////////////////////////////////////////////////
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifndef __SPNEGO_H__
-#define __SPNEGO_H__
-
-// C++ Specific
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
-
-// Type Definitions
-
-//
-// Users of SPNEGO Token Handler API will request
-// these as well as free them,
-//
-typedef void* SPNEGO_TOKEN_HANDLE;
-
-//
-// Defines the element types that are found
-// in each of the tokens.
-//
-
-typedef enum spnego_element_type
-{
- spnego_element_min, // Lower bound
-
- // Init token elements
- spnego_init_mechtypes,
- spnego_init_reqFlags,
- spnego_init_mechToken,
- spnego_init_mechListMIC,
-
- // Targ token elements
- spnego_targ_negResult,
- spnego_targ_supportedMech,
- spnego_targ_responseToken,
- spnego_targ_mechListMIC,
-
- spnego_element_max // Upper bound
-
-} SPNEGO_ELEMENT_TYPE;
-
-//
-// Token Element Availability. Elements in both
-// token types are optional. Since there are only
-// 4 elements in each Token, we will allocate space
-// to hold the information, but we need a way to
-// indicate whether or not an element is available
-//
-
-#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0
-#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1
-
-//
-// Token type values. SPNEGO has 2 token types:
-// NegTokenInit and NegTokenTarg
-//
-
-#define SPNEGO_TOKEN_INIT 0
-#define SPNEGO_TOKEN_TARG 1
-
-//
-// GSS Mechanism OID enumeration. We only really handle
-// 3 different OIDs. These are stored in an array structure
-// defined in the parsing code.
-//
-
-typedef enum spnego_mech_oid
-{
- // Init token elements
- spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit
- spnego_mech_oid_Kerberos_V5,
- spnego_mech_oid_Spnego,
- spnego_mech_oid_NTLMSSP,
- spnego_mech_oid_NotUsed = -1
-
-} SPNEGO_MECH_OID;
-
-//
-// Defines the negResult values.
-//
-
-typedef enum spnego_negResult
-{
- spnego_negresult_success,
- spnego_negresult_incomplete,
- spnego_negresult_rejected,
- spnego_negresult_NotUsed = -1
-} SPNEGO_NEGRESULT;
-
-//
-// Context Flags in NegTokenInit
-//
-
-//
-// ContextFlags values MUST be zero or a combination
-// of the below
-//
-
-#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80
-#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40
-#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20
-#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10
-#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8
-#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4
-#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2
-
-//
-// Mask to retrieve valid values.
-//
-
-#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags
-
-//
-// SPNEGO API return codes.
-//
-
-// API function was successful
-#define SPNEGO_E_SUCCESS 0
-
-// The supplied Token was invalid
-#define SPNEGO_E_INVALID_TOKEN -1
-
-// An invalid length was encountered
-#define SPNEGO_E_INVALID_LENGTH -2
-
-// The Token Parse failed
-#define SPNEGO_E_PARSE_FAILED -3
-
-// The requested value was not found
-#define SPNEGO_E_NOT_FOUND -4
-
-// The requested element is not available
-#define SPNEGO_E_ELEMENT_UNAVAILABLE -5
-
-// Out of Memory
-#define SPNEGO_E_OUT_OF_MEMORY -6
-
-// Not Implemented
-#define SPNEGO_E_NOT_IMPLEMENTED -7
-
-// Invalid Parameter
-#define SPNEGO_E_INVALID_PARAMETER -8
-
-// Token Handler encountered an unexpected OID
-#define SPNEGO_E_UNEXPECTED_OID -9
-
-// The requested token was not found
-#define SPNEGO_E_TOKEN_NOT_FOUND -10
-
-// An unexpected type was encountered in the encoding
-#define SPNEGO_E_UNEXPECTED_TYPE -11
-
-// The buffer was too small
-#define SPNEGO_E_BUFFER_TOO_SMALL -12
-
-// A Token Element was invalid (e.g. improper length or value)
-#define SPNEGO_E_INVALID_ELEMENT -13
-
-/* Miscelaneous API Functions */
-
-// Frees opaque data
-void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken );
-
-// Initializes SPNEGO_TOKEN structure from DER encoded binary data
-int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
-
-// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the
-// supplied parameters
-int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
- unsigned char ucContextFlags, unsigned char* pbMechToken,
- unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC,
- unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
-
-// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the
-// supplied parameters
-int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType,
- SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
- unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
- unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
-
-// Copies binary representation of SPNEGO Data into user supplied buffer
-int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
- unsigned long * pulDataLen );
-
-// Returns SPNEGO Token Type
-int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType );
-
-/* Reading an Init Token */
-
-// Returns the Initial Mech Type in the MechList element in the NegInitToken.
-int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex );
-
-// Returns the value from the context flags element in the NegInitToken as an unsigned long
-int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags );
-
-/* Reading a Response Token */
-
-// Returns the value from the negResult element (Status code of GSS call - 0,1,2)
-int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult );
-
-// Returns the Supported Mech Type from the NegTokenTarg.
-int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID );
-
-/* Reading either Token Type */
-
-// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions
-int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen );
-
-// Returns the Message Integrity BLOB in the token
-int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen );
-
-// C++ Specific
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.c b/usr/src/lib/libsmbfs/smb/spnegoparse.c
index e9f1e2781b..ea5fb03a70 100644
--- a/usr/src/lib/libsmbfs/smb/spnegoparse.c
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c
@@ -1,3 +1,4 @@
+// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -54,6 +55,7 @@ extern MECH_OID g_stcMechOIDList [];
// Parameters:
// [in] nMechTokenLength - Length of the MechToken Element
// [in] nMechListMICLength - Length of the MechListMIC Element
+// (or negHints, if no MechToken)
// [in] mechOID - OID for MechList
// [in] nReqFlagsAvailable - Is ContextFlags element available
// [out] pnTokenSize - Filled out with total size of token
@@ -75,7 +77,7 @@ extern MECH_OID g_stcMechOIDList [];
////////////////////////////////////////////////////////////////////////////
int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
- long nMechListMICLength, SPNEGO_MECH_OID mechOid,
+ long nMechListMICLength, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt,
int nReqFlagsAvailable, long* pnTokenSize,
long* pnInternalTokenLength )
{
@@ -87,7 +89,7 @@ int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
// We will calculate this by walking the token backwards
- // Start with MIC Element
+ // Start with MIC Element (or negHints)
if ( nMechListMICLength > 0L )
{
nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL );
@@ -130,7 +132,7 @@ int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
}
// Next is the MechList - This is REQUIRED
- nTempLength += ASNDerCalcMechListLength( mechOid, NULL );
+ nTempLength += ASNDerCalcMechListLength( mechOidLst, mechOidCnt, NULL );
// Check for rollover error
if ( nTempLength < nTotalLength )
@@ -205,11 +207,12 @@ xEndTokenInitLength:
// CreateSpnegoInitToken
//
// Parameters:
-// [in] MechType - OID in MechList
+// [in] pMechTypeList - OID array
+// [in] MechTypeCnt - OID array length
// [in] ucContextFlags - ContextFlags value
// [in] pbMechToken - Mech Token Binary Data
// [in] ulMechTokenLen - Length of Mech Token
-// [in] pbMechListMIC - MechListMIC Binary Data
+// [in] pbMechListMIC - MechListMIC Binary Data (or negHints)
// [in] ulMechListMICn - Length of MechListMIC
// [out] pbTokenData - Buffer to write token into.
// [in] nTokenLength - Length of pbTokenData buffer
@@ -227,9 +230,18 @@ xEndTokenInitLength:
// backwards, so we always know how many bytes we will potentially be
// writing out.
//
+// This function is also used to create an SPNEGO "hint", as described in
+// [MS-SPNG] sec. 2.2.1 negTokenInit2. The "hint" looks almost identical
+// to a NegTokenInit, but has a "negHints" field inserted before the MIC.
+// A normal SPNEGO negTokenInit2 contains only the mech list and the
+// negHints. To avoid a giant copy/paste of this function, we pass the
+// negHints as the MIC arg, and pass NULL as the MechToken to indicate
+// that we're creating a Hint rather than an Init, and use the correct
+// type when writing out the MIC (or negHints) element.
+//
////////////////////////////////////////////////////////////////////////////
-int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+int CreateSpnegoInitToken( SPNEGO_MECH_OID *pMechTypeList, long MechTypeCnt,
unsigned char ucContextFlags, unsigned char* pbMechToken,
unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
unsigned long ulMechListMICLen, unsigned char* pbTokenData,
@@ -251,17 +263,22 @@ int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
// We will write the token out backwards to properly handle the cases
// where the length bytes become adjustable
- // Start with MIC Element
+ // Start with MIC Element (or negHints)
if ( ulMechListMICLen > 0L )
{
+ unsigned char ucType;
nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
- // Decrease the pbWriteTokenData, now we know the length and
- // write it out.
+ // Decrease the pbWriteTokenData, now we know the length and write it out.
+ // Note: When MechTokenLen == 0, we're writing a negTokenInit2 and the
+ // MIC arg is really negHints, written as a constructed sequence.
+ // Otherwise we're writing a negTokenInit, and the MIC is an OCTETSTRING.
+ ucType = (ulMechTokenLen == 0) ?
+ SPNEGO_CONSTRUCTED_SEQUENCE : OCTETSTRING;
pbWriteTokenData -= nTempLength;
nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC,
- OCTETSTRING, pbMechListMIC, ulMechListMICLen );
+ ucType, pbMechListMIC, ulMechListMICLen );
// Adjust Values and sanity check
nTotalBytesWritten += nTempLength;
@@ -325,12 +342,12 @@ int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
} // IF ContextFlags
// Next is the MechList - This is REQUIRED
- nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength );
+ nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength );
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
pbWriteTokenData -= nTempLength;
- nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType );
+ nTempLength = ASNDerWriteMechList( pbWriteTokenData, pMechTypeList, MechTypeCnt );
// Adjust Values and sanity check
nTotalBytesWritten += nTempLength;
@@ -1281,8 +1298,6 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD
long nElementLength = 0L;
long nActualTokenLength = 0L;
unsigned char* pbElements = NULL;
- unsigned char * ptok;
- long tlen, elen, len;
// Point to the correct array
switch( pSpnegoToken->ucTokenType )
@@ -1370,37 +1385,32 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD
nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
OCTETSTRING, spnego_init_mechToken,
&pSpnegoToken->aElementArray[nCtr] );
- }
+ }
break;
- case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC:
+ case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: // xA3
{
//
- // This is an OCTETSTRING which contains a message integrity BLOB.
+ // Don't yet know if this is a negTokenInit, or negTokenInit2.
+ // Unfortunately, both have the same type: SPNEGO_TOKEN_INIT
+ // If it's negTokenInit, this element should be an OCTETSTRING
+ // containing the MIC. If it's a negTokenInit2, this element
+ // should be an SPNEGO_CONSTRUCTED_SEQUENCE containing the
+ // negHints (GENERALSTR, ignored)
//
nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
- OCTETSTRING, spnego_init_mechListMIC,
- &pSpnegoToken->aElementArray[nCtr] );
- /*
- * don't believe everything you read in RFCs (and MS
- * sample code)... win2k is sending not an octet string,
- * but a "general string", wrapped in a sequence.
- */
- if (nReturn != SPNEGO_E_UNEXPECTED_TYPE)
- break;
- ptok = pbTokenData;
- elen = nElementLength;
- if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
- break;
- elen -= tlen;
- ptok += tlen;
-
- if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
- break;
- elen -= tlen;
- ptok += tlen;
- nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]);
+ OCTETSTRING, spnego_init_mechListMIC,
+ &pSpnegoToken->aElementArray[nCtr] );
+
+ if (nReturn == SPNEGO_E_UNEXPECTED_TYPE) {
+ // This is really a negHints element. Check the type and length,
+ // but otherwise just ignore it.
+ long elen, tlen;
+ nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ nElementLength, nElementLength,
+ &elen, &tlen );
+ }
}
break;
@@ -1408,6 +1418,7 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD
}
else
{
+ /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */
switch( pbElements[nCtr] )
{
@@ -1453,12 +1464,13 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD
case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC:
{
//
- // This is an OCTETSTRING which specifies a message integrity BLOB.
+ // This is an OCTETSTRING, typically 16 bytes,
+ // which contains a message integrity BLOB.
//
nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
- OCTETSTRING, spnego_targ_mechListMIC,
- &pSpnegoToken->aElementArray[nCtr] );
+ OCTETSTRING, spnego_targ_mechListMIC,
+ &pSpnegoToken->aElementArray[nCtr] );
}
break;
diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.h b/usr/src/lib/libsmbfs/smb/spnegoparse.h
index b874dc453d..1f7fde7486 100644
--- a/usr/src/lib/libsmbfs/smb/spnegoparse.h
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.h
@@ -1,3 +1,4 @@
+// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -21,8 +22,6 @@
//
/////////////////////////////////////////////////////////////
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef __SPNEGOPARSE_H__
#define __SPNEGOPARSE_H__
@@ -136,13 +135,13 @@ int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechO
int * piMechTypeIndex );
int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength );
int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength,
- SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable,
+ SPNEGO_MECH_OID *mechOid, int mechOidCnt, int nReqFlagsAvailable,
long* plTokenSize, long* plInternalLength );
int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult,
long nMechTokenLen,
long nMechTokenMIC, long* pnTokenSize,
long* pnInternalTokenLength );
-int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+int CreateSpnegoInitToken( SPNEGO_MECH_OID *MechTypeList, long nMechTypes,
unsigned char ucContextFlags, unsigned char* pbMechToken,
unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
unsigned long ulMechListMICLen, unsigned char* pbTokenData,
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
index d40fa8d629..20c8f74f77 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
+++ b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
@@ -51,6 +51,7 @@ OBJS_LOCAL = \
OBJS_FS_SMBSRV = \
smb_acl.o \
smb_alloc.o \
+ smb_authenticate.o \
smb_close.o \
smb_common_open.o \
smb_common_transact.o \
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
index 881535d2f3..685a760e16 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
@@ -70,6 +70,10 @@ extern void mlsvc_fini(void);
extern DWORD mlsvc_netlogon(char *, char *);
extern DWORD mlsvc_join(smb_domainex_t *, char *, char *);
+extern void smb_logon_domain(smb_logon_t *, smb_token_t *);
+extern uint32_t smb_decode_krb5_pac(smb_token_t *, char *, uint_t);
+extern boolean_t smb_token_setup_common(smb_token_t *);
+
/*
* The maximum number of domains (NT limit).
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
index 29af98f2ac..eece54e174 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -53,6 +54,7 @@ SYMBOL_VERSION SUNWprivate {
mlsvc_netlogon;
smb_autohome_add;
smb_autohome_remove;
+ smb_decode_krb5_pac;
smb_locate_dc;
smb_logon;
smb_logon_abort;
@@ -76,6 +78,7 @@ SYMBOL_VERSION SUNWprivate {
smb_shr_stop;
smb_token_destroy;
smb_token_log;
+ smb_token_setup_common;
spoolss_register_copyfile;
local:
*;
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
index 566837fe2d..a3fbb4d96f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -61,6 +61,8 @@ static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
static boolean_t netr_isadmin(struct netr_validation_info3 *);
static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
smb_ids_t *);
+static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
+ smb_token_t *);
static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
smb_token_t *);
@@ -75,6 +77,83 @@ static boolean_t netlogon_busy = B_FALSE;
static boolean_t netlogon_abort = B_FALSE;
/*
+ * Helper for Kerberos authentication
+ */
+uint32_t
+smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
+{
+ struct krb5_validation_info info;
+ ndr_buf_t *nbuf;
+ uint32_t status = NT_STATUS_NO_MEMORY;
+ int rc;
+
+ bzero(&info, sizeof (info));
+
+ /* Need to keep this until we're done with &info */
+ nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
+ if (nbuf == NULL)
+ goto out;
+
+ rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
+ NETR_OPNUM_decode_krb5_pac, data, len, &info);
+ if (rc != NDR_DRC_OK) {
+ status = RPC_NT_PROTOCOL_ERROR;
+ goto out;
+ }
+
+ status = netr_setup_token_info3(&info.info3, token);
+
+ /* Deal with the "resource groups"? */
+
+
+out:
+ if (nbuf != NULL)
+ ndr_buf_fini(nbuf);
+
+ return (status);
+}
+
+/*
+ * Code factored out of netr_setup_token()
+ */
+static uint32_t
+netr_setup_token_info3(struct netr_validation_info3 *info3,
+ smb_token_t *token)
+{
+ smb_sid_t *domsid;
+
+ domsid = (smb_sid_t *)info3->LogonDomainId;
+
+ token->tkn_user.i_sid = smb_sid_splice(domsid,
+ info3->UserId);
+ if (token->tkn_user.i_sid == NULL)
+ goto errout;
+
+ token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
+ info3->PrimaryGroupId);
+ if (token->tkn_primary_grp.i_sid == NULL)
+ goto errout;
+
+ if (info3->EffectiveName.str) {
+ token->tkn_account_name =
+ strdup((char *)info3->EffectiveName.str);
+ if (token->tkn_account_name == NULL)
+ goto errout;
+ }
+
+ if (info3->LogonDomainName.str) {
+ token->tkn_domain_name =
+ strdup((char *)info3->LogonDomainName.str);
+ if (token->tkn_domain_name == NULL)
+ goto errout;
+ }
+
+ return (netr_setup_token_wingrps(info3, token));
+errout:
+ return (NT_STATUS_INSUFF_SERVER_RESOURCES);
+}
+
+/*
* Abort impending domain logon requests.
*/
void
@@ -254,13 +333,14 @@ netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
* exclusively ored with the 16 byte UserSessionKey to recover
* the the clear form.
*/
- if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
+ if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
return (NT_STATUS_NO_MEMORY);
+ token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
- bcopy(info3->UserSessionKey.data, token->tkn_session_key,
+ bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
SMBAUTH_SESSION_KEY_SZ);
- rand_hash((unsigned char *)token->tkn_session_key,
+ rand_hash((unsigned char *)token->tkn_ssnkey.val,
SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
return (NT_STATUS_SUCCESS);
@@ -603,7 +683,14 @@ netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
(void) mutex_unlock(&logon_id_mutex);
- identity->parameter_control = 0;
+ /*
+ * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
+ * ParameterControl to the 'E' + 'K' bits. Those are:
+ * (1 << 5) | (1 << 11), a.k.a
+ */
+ identity->parameter_control =
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
identity->logon_id.LowPart = logon_id;
identity->logon_id.HighPart = 0;
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
index 8ffc4f6f28..c9e634f515 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -82,6 +83,9 @@ smb_autohome_add(const smb_token_t *token)
uid_t uid;
gid_t gid;
+ if (token->tkn_flags & SMB_ATF_ANON)
+ return;
+
uid = token->tkn_user.i_id;
gid = token->tkn_primary_grp.i_id;
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
index 4b7a1cd178..24baa848e7 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <unistd.h>
@@ -44,7 +45,6 @@ static rwlock_t smb_logoninit_rwl;
typedef void (*smb_logonop_t)(smb_logon_t *, smb_token_t *);
-extern void smb_logon_domain(smb_logon_t *, smb_token_t *);
static void smb_logon_local(smb_logon_t *, smb_token_t *);
static void smb_logon_guest(smb_logon_t *, smb_token_t *);
static void smb_logon_anon(smb_logon_t *, smb_token_t *);
@@ -158,8 +158,8 @@ smb_token_sids2ids(smb_token_t *token)
}
stat = smb_idmap_batch_getmappings(&sib);
- smb_idmap_batch_destroy(&sib);
smb_idmap_check("smb_idmap_batch_getmappings", stat);
+ smb_idmap_batch_destroy(&sib);
return (stat == IDMAP_SUCCESS ? 0 : -1);
}
@@ -253,7 +253,7 @@ smb_token_destroy(smb_token_t *token)
free(token->tkn_posix_grps);
free(token->tkn_account_name);
free(token->tkn_domain_name);
- free(token->tkn_session_key);
+ free(token->tkn_ssnkey.val);
bzero(token, sizeof (smb_token_t));
free(token);
}
@@ -344,8 +344,10 @@ smb_token_set_flags(smb_token_t *token)
* has been done.
*
* Note that the order of calls in this function are important.
+ *
+ * Returns B_TRUE for success.
*/
-static boolean_t
+boolean_t
smb_token_setup_common(smb_token_t *token)
{
smb_token_set_flags(token);
@@ -475,7 +477,6 @@ smb_logon_local(smb_logon_t *user_info, smb_token_t *token)
char guest[SMB_USERNAME_MAXLEN];
smb_passwd_t smbpw;
uint32_t status;
- boolean_t isguest;
if (user_info->lg_secmode == SMB_SECMODE_DOMAIN) {
if ((user_info->lg_domain_type != SMB_DOMAIN_LOCAL) &&
@@ -483,16 +484,18 @@ smb_logon_local(smb_logon_t *user_info, smb_token_t *token)
return;
}
+ /*
+ * If the requested account name is "guest" (or whatever
+ * our guest account is named) then don't handle it here.
+ * Let this request fall through to smb_logon_guest().
+ */
smb_guest_account(guest, SMB_USERNAME_MAXLEN);
- isguest = (smb_strcasecmp(guest, user_info->lg_e_username, 0) == 0);
+ if (smb_strcasecmp(guest, user_info->lg_e_username, 0) == 0)
+ return;
status = smb_token_auth_local(user_info, token, &smbpw);
- if (status == NT_STATUS_SUCCESS) {
- if (isguest)
- status = smb_token_setup_guest(user_info, token);
- else
- status = smb_token_setup_local(&smbpw, token);
- }
+ if (status == NT_STATUS_SUCCESS)
+ status = smb_token_setup_local(&smbpw, token);
user_info->lg_status = status;
}
@@ -514,23 +517,31 @@ smb_logon_guest(smb_logon_t *user_info, smb_token_t *token)
char guest[SMB_USERNAME_MAXLEN];
smb_passwd_t smbpw;
char *temp;
- uint32_t status;
if (user_info->lg_status != NT_STATUS_NO_SUCH_USER)
return;
+ /* Get the name of the guest account. */
smb_guest_account(guest, SMB_USERNAME_MAXLEN);
- temp = user_info->lg_e_username;
- user_info->lg_e_username = guest;
- status = smb_token_auth_local(user_info, token, &smbpw);
- if ((status == NT_STATUS_SUCCESS) ||
- (status == NT_STATUS_NO_SUCH_USER)) {
- status = smb_token_setup_guest(user_info, token);
- }
+ /* Does the guest account exist? */
+ if (smb_pwd_getpwnam(guest, &smbpw) == NULL)
+ return;
+ /* Is it enabled? (empty p/w is OK) */
+ if (smbpw.pw_flags & SMB_PWF_DISABLE)
+ return;
+
+ /*
+ * OK, give the client a guest logon. Note that on entry,
+ * lg_e_username is typically something other than "guest"
+ * so we need to set the effective username when createing
+ * the guest token.
+ */
+ temp = user_info->lg_e_username;
+ user_info->lg_e_username = guest;
+ user_info->lg_status = smb_token_setup_guest(user_info, token);
user_info->lg_e_username = temp;
- user_info->lg_status = status;
}
/*
@@ -552,7 +563,7 @@ static uint32_t
smb_token_auth_local(smb_logon_t *user_info, smb_token_t *token,
smb_passwd_t *smbpw)
{
- boolean_t lm_ok, nt_ok;
+ boolean_t ok;
uint32_t status = NT_STATUS_SUCCESS;
if (smb_pwd_getpwnam(user_info->lg_e_username, smbpw) == NULL)
@@ -561,41 +572,42 @@ smb_token_auth_local(smb_logon_t *user_info, smb_token_t *token,
if (smbpw->pw_flags & SMB_PWF_DISABLE)
return (NT_STATUS_ACCOUNT_DISABLED);
- nt_ok = lm_ok = B_FALSE;
- if ((smbpw->pw_flags & SMB_PWF_LM) &&
- (user_info->lg_lm_password.len != 0)) {
- lm_ok = smb_auth_validate_lm(
- user_info->lg_challenge_key.val,
- user_info->lg_challenge_key.len,
- smbpw,
- user_info->lg_lm_password.val,
- user_info->lg_lm_password.len,
- user_info->lg_domain,
- user_info->lg_username);
- token->tkn_session_key = NULL;
- }
-
- if (!lm_ok && (user_info->lg_nt_password.len != 0)) {
- token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ);
- if (token->tkn_session_key == NULL)
- return (NT_STATUS_NO_MEMORY);
- nt_ok = smb_auth_validate_nt(
- user_info->lg_challenge_key.val,
- user_info->lg_challenge_key.len,
- smbpw,
- user_info->lg_nt_password.val,
- user_info->lg_nt_password.len,
- user_info->lg_domain,
- user_info->lg_username,
- (uchar_t *)token->tkn_session_key);
+ if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)) == 0) {
+ /*
+ * The SMB passwords have not been set.
+ * Return an error that suggests the
+ * password needs to be set.
+ */
+ return (NT_STATUS_PASSWORD_EXPIRED);
}
- if (!nt_ok && !lm_ok) {
- status = NT_STATUS_WRONG_PASSWORD;
- syslog(LOG_NOTICE, "logon[%s\\%s]: %s",
- user_info->lg_e_domain, user_info->lg_e_username,
- xlate_nt_status(status));
- }
+ token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ);
+ if (token->tkn_ssnkey.val == NULL)
+ return (NT_STATUS_NO_MEMORY);
+ token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
+
+ ok = smb_auth_validate(
+ smbpw,
+ user_info->lg_domain,
+ user_info->lg_username,
+ user_info->lg_challenge_key.val,
+ user_info->lg_challenge_key.len,
+ user_info->lg_nt_password.val,
+ user_info->lg_nt_password.len,
+ user_info->lg_lm_password.val,
+ user_info->lg_lm_password.len,
+ token->tkn_ssnkey.val);
+ if (ok)
+ return (NT_STATUS_SUCCESS);
+
+ free(token->tkn_ssnkey.val);
+ token->tkn_ssnkey.val = NULL;
+ token->tkn_ssnkey.len = 0;
+
+ status = NT_STATUS_WRONG_PASSWORD;
+ syslog(LOG_NOTICE, "logon[%s\\%s]: %s",
+ user_info->lg_e_domain, user_info->lg_e_username,
+ xlate_nt_status(status));
return (status);
}
diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com
index 0c972a66f0..78dc4fdcfa 100644
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com
@@ -54,7 +54,6 @@ OBJS_COMMON = \
smb_info.o \
smb_kmod.o \
smb_lgrp.o \
- smb_mac.o \
smb_nic.o \
smb_pwdutil.o \
smb_privilege.o \
@@ -73,14 +72,16 @@ include ../../../Makefile.lib
include ../../Makefile.lib
INCS += -I$(SRC)/common/smbsrv
+INCS += -I$(SRC)/lib/libsmbfs/smb
LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2
LINTCHECKFLAGS += -erroff=E_BAD_FORMAT_STR2
LDLIBS += $(MACH_LDLIBS)
+# perfer to keep libs ordered by dependence
LDLIBS += -lscf -lmd -luuid -lpkcs11 -lcryptoutil
-LDLIBS += -lsec -lidmap -lnsl -lsocket -lresolv
-LDLIBS += -lreparse -lnvpair -lcmdutils -lavl -lc
+LDLIBS += -lsec -lidmap -lreparse -lcmdutils -lavl
+LDLIBS += -lnvpair -lresolv -lsocket -lnsl -lc
CPPFLAGS += $(INCS) -D_REENTRANT
CPPFLAGS += -Dsyslog=smb_syslog
CERRWARN += -_gcc=-Wno-uninitialized
diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
index 7c5f88976a..82bbe995c3 100644
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _LIBSMB_H
@@ -139,6 +139,7 @@ typedef enum {
SMB_CI_DYNDNS_ENABLE,
SMB_CI_MACHINE_PASSWD,
+ SMB_CI_MACHINE_UUID,
SMB_CI_KPASSWD_SRV,
SMB_CI_KPASSWD_DOMAIN,
SMB_CI_KPASSWD_SEQNUM,
@@ -193,6 +194,7 @@ extern boolean_t smb_config_get_ads_enable(void);
extern int smb_config_get_debug(void);
extern uint8_t smb_config_get_fg_flag(void);
extern char *smb_config_get_localsid(void);
+extern int smb_config_get_localuuid(uuid_t);
extern int smb_config_secmode_fromstr(char *);
extern char *smb_config_secmode_tostr(int);
extern int smb_config_get_secmode(void);
@@ -202,7 +204,7 @@ extern int smb_config_refresh_idmap(void);
extern int smb_config_getip(smb_cfg_id_t, smb_inaddr_t *);
extern void smb_config_get_version(smb_version_t *);
uint32_t smb_config_get_execinfo(char *, char *, size_t);
-
+extern void smb_config_get_negtok(uchar_t *, uint32_t *);
extern void smb_load_kconfig(smb_kmod_cfg_t *kcfg);
extern uint32_t smb_crc_gen(uint8_t *, size_t);
@@ -303,7 +305,7 @@ void libsmb_redirect_syslog(__FILE_TAG *fp, int priority);
#define SMBAUTH_HASH_SZ 16 /* also LM/NTLM/NTLMv2 Hash size */
#define SMBAUTH_LM_RESP_SZ 24 /* also NTLM Response size */
#define SMBAUTH_LM_PWD_SZ 14 /* LM password size */
-#define SMBAUTH_V2_CLNT_CHALLENGE_SZ 8 /* both LMv2 and NTLMv2 */
+#define SMBAUTH_CHAL_SZ 8 /* both LMv2 and NTLMv2 */
#define SMBAUTH_SESSION_KEY_SZ SMBAUTH_HASH_SZ
#define SMBAUTH_HEXHASH_SZ (SMBAUTH_HASH_SZ * 2)
@@ -364,7 +366,7 @@ typedef struct smb_auth_data_blob {
unsigned char ndb_signature[4];
unsigned char ndb_reserved[4];
uint64_t ndb_timestamp;
- unsigned char ndb_clnt_challenge[SMBAUTH_V2_CLNT_CHALLENGE_SZ];
+ unsigned char ndb_clnt_challenge[SMBAUTH_CHAL_SZ];
unsigned char ndb_unknown[4];
smb_auth_name_entry_t ndb_names[2];
unsigned char ndb_unknown2[4];
@@ -488,6 +490,9 @@ extern int smb_auth_RC4(unsigned char *, int, unsigned char *, int,
extern int smb_auth_md4(unsigned char *, unsigned char *, int);
extern int smb_auth_lm_hash(const char *, unsigned char *);
extern int smb_auth_ntlm_hash(const char *, unsigned char *);
+extern void smb_auth_ntlm2_mkchallenge(char *, const char *, const char *);
+extern void smb_auth_ntlm2_kxkey(unsigned char *, const char *, const char *,
+ unsigned char *);
extern int smb_auth_set_info(char *, char *,
unsigned char *, char *, unsigned char *,
@@ -496,12 +501,8 @@ extern int smb_auth_set_info(char *, char *,
extern int smb_auth_ntlmv2_hash(unsigned char *,
char *, char *, unsigned char *);
-extern int smb_auth_gen_session_key(smb_auth_info_t *, unsigned char *);
-
-boolean_t smb_auth_validate_lm(unsigned char *, uint32_t, smb_passwd_t *,
- unsigned char *, int, char *, char *);
-boolean_t smb_auth_validate_nt(unsigned char *, uint32_t, smb_passwd_t *,
- unsigned char *, int, char *, char *, uchar_t *);
+boolean_t smb_auth_validate(smb_passwd_t *, char *, char *,
+ uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *);
int smb_gen_random_passwd(char *passwd, size_t bufsz);
@@ -516,14 +517,6 @@ extern void smb_ipc_rollback(void);
extern void smb_ipc_set(char *, uint8_t *);
/*
- * SMB MAC Signing
- */
-
-#define SMB_MAC_KEY_SZ (SMBAUTH_SESSION_KEY_SZ + SMBAUTH_CS_MAXLEN)
-#define SMB_SIG_OFFS 14 /* signature field offset within header */
-#define SMB_SIG_SIZE 8 /* SMB signature size */
-
-/*
* Signing flags:
*
* SMB_SCF_ENABLE Signing is enabled.
@@ -547,38 +540,6 @@ extern void smb_ipc_set(char *, uint8_t *);
#define SMB_SCF_KEY_ISSET_THIS_LOGON 0x08
/*
- * smb_sign_ctx
- *
- * SMB signing context.
- *
- * ssc_seqnum sequence number
- * ssc_keylen mac key length
- * ssc_mid multiplex id - reserved
- * ssc_flags flags
- * ssc_mackey mac key
- * ssc_sign mac signature
- *
- */
-typedef struct smb_sign_ctx {
- unsigned int ssc_seqnum;
- unsigned short ssc_keylen;
- unsigned short ssc_mid;
- unsigned int ssc_flags;
- unsigned char ssc_mackey[SMB_MAC_KEY_SZ];
- unsigned char ssc_sign[SMB_SIG_SIZE];
-} smb_sign_ctx_t;
-
-extern int smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth);
-extern int smb_mac_calc(smb_sign_ctx_t *sign_ctx,
- const unsigned char *buf, size_t buf_len, unsigned char *mac_sign);
-extern int smb_mac_chk(smb_sign_ctx_t *sign_ctx,
- const unsigned char *buf, size_t buf_len);
-extern int smb_mac_sign(smb_sign_ctx_t *sign_ctx,
- unsigned char *buf, size_t buf_len);
-extern void smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx);
-extern void smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx);
-
-/*
* Each domain is categorized using the enum values below.
* The local domain refers to the local machine and is named
* after the local hostname. The primary domain is the domain
diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
index 3570d05ba4..c4c3814864 100644
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers
@@ -75,13 +75,13 @@ SYMBOL_VERSION SUNWprivate {
smb_acl_to_zfs;
smb_auth_DES;
smb_auth_RC4;
- smb_auth_gen_session_key;
smb_auth_hmac_md5;
smb_auth_ntlm_hash;
+ smb_auth_ntlm2_kxkey;
+ smb_auth_ntlm2_mkchallenge;
smb_auth_ntlmv2_hash;
smb_auth_qnd_unicode;
- smb_auth_validate_lm;
- smb_auth_validate_nt;
+ smb_auth_validate;
smb_buf32_xdr;
smb_cache_add;
smb_cache_create;
@@ -265,11 +265,6 @@ SYMBOL_VERSION SUNWprivate {
smb_logon_xdr;
smb_lookup_name;
smb_lookup_sid;
- smb_mac_chk;
- smb_mac_dec_seqnum;
- smb_mac_inc_seqnum;
- smb_mac_init;
- smb_mac_sign;
smb_match_netlogon_seqnum;
smb_mbstos;
smb_mbstowcs;
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
index 9f4100e805..29918639e7 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
@@ -21,15 +21,70 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <strings.h>
#include <stdlib.h>
+#include <syslog.h>
+#include <sys/md5.h>
#include <smbsrv/string.h>
#include <smbsrv/libsmb.h>
+#include <netsmb/spnego.h> /* libsmbfs */
#include <assert.h>
+#define NTLM_CHAL_SZ SMBAUTH_CHAL_SZ /* challenge size */
+
+/*
+ * Compute the combined (server+client) challenge per. [MS-NLMP 3.3.1]
+ * MD5(concat(ServerChallenge,ClientChallenge))
+ */
+void
+smb_auth_ntlm2_mkchallenge(char *result,
+ const char *srv_chal, const char *clnt_chal)
+{
+ MD5_CTX context;
+ uchar_t challenges[2 * NTLM_CHAL_SZ];
+ uchar_t digest[SMBAUTH_HASH_SZ];
+
+ /*
+ * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
+ */
+ (void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ);
+ (void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ);
+
+ /*
+ * digest = MD5(challenges)
+ */
+ MD5Init(&context);
+ MD5Update(&context, challenges, sizeof (challenges));
+ MD5Final(digest, &context);
+
+ /*
+ * result = digest[0..7]
+ */
+ (void) memcpy(result, digest, NTLM_CHAL_SZ);
+}
+
+void
+smb_auth_ntlm2_kxkey(unsigned char *result, const char *srv_chal,
+ const char *clnt_chal, unsigned char *ssn_base_key)
+{
+ uchar_t challenges[2 * NTLM_CHAL_SZ];
+
+ /*
+ * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
+ */
+ (void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ);
+ (void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ);
+
+ /* HMAC_MD5(SessionBaseKey, concat(...)) */
+ /* SMBAUTH_HMACT64 args: D, Dsz, K, Ksz, digest */
+ (void) SMBAUTH_HMACT64(challenges, sizeof (challenges),
+ ssn_base_key, SMBAUTH_HASH_SZ, result);
+}
+
/*
* smb_auth_qnd_unicode
*
@@ -117,7 +172,7 @@ smb_auth_lm_hash(const char *password, unsigned char *lm_hash)
*/
static int
smb_auth_lm_response(unsigned char *hash,
- unsigned char *challenge, int clen,
+ unsigned char *challenge, /* NTLM_CHAL_SZ */
unsigned char *lm_rsp)
{
unsigned char S21[21];
@@ -131,7 +186,7 @@ smb_auth_lm_response(unsigned char *hash,
/* padded LM Hash -> LM Response */
return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
- challenge, clen));
+ challenge, NTLM_CHAL_SZ));
}
/*
@@ -174,7 +229,7 @@ smb_auth_ntlm_hash(const char *password, unsigned char *hash)
*/
static int
smb_auth_ntlm_response(unsigned char *hash,
- unsigned char *challenge, int clen,
+ unsigned char *challenge, /* NTLM_CHAL_SZ */
unsigned char *ntlm_rsp)
{
unsigned char S21[21];
@@ -182,7 +237,7 @@ smb_auth_ntlm_response(unsigned char *hash,
bcopy(hash, S21, SMBAUTH_HASH_SZ);
bzero(&S21[SMBAUTH_HASH_SZ], 5);
if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
- S21, 21, challenge, clen) == SMBAUTH_FAILURE)
+ S21, 21, challenge, NTLM_CHAL_SZ) == SMBAUTH_FAILURE)
return (0);
return (SMBAUTH_LM_RESP_SZ);
}
@@ -253,13 +308,14 @@ smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
static int
smb_auth_v2_response(
unsigned char *hash,
- unsigned char *srv_challenge, int slen,
+ unsigned char *srv_challenge, /* NTLM_CHAL_SZ */
unsigned char *clnt_data, int clen,
unsigned char *v2_rsp)
{
unsigned char *hmac_data;
+ int slen = NTLM_CHAL_SZ;
- hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char));
+ hmac_data = malloc(NTLM_CHAL_SZ + clen);
if (!hmac_data) {
return (-1);
}
@@ -275,70 +331,39 @@ smb_auth_v2_response(
return (SMBAUTH_HASH_SZ + clen);
}
-/*
- * smb_auth_gen_session_key
- *
- * Generate the NTLM user session key if LMCompatibilityLevel is 2 or
- * NTLMv2 user session key if LMCompatibilityLevel is 3 or above.
- *
- * NTLM_Session_Key = MD4(NTLM_Hash);
- *
- * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16)
- *
- * Prior to calling this function, the auth instance should be set
- * via smb_auth_set_info().
- *
- * Returns the appropriate session key.
- */
-int
-smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key)
-{
- int rc;
-
- if (auth->lmcompatibility_lvl == 2)
- rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ);
- else
- rc = SMBAUTH_HMACT64((unsigned char *)auth->cs,
- SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2,
- SMBAUTH_SESSION_KEY_SZ, session_key);
-
- return (rc);
-}
static boolean_t
smb_lm_password_ok(
unsigned char *challenge,
- uint32_t clen,
unsigned char *lm_hash,
- unsigned char *passwd)
+ unsigned char *lm_resp)
{
- unsigned char lm_resp[SMBAUTH_LM_RESP_SZ];
+ unsigned char ok_resp[SMBAUTH_LM_RESP_SZ];
int rc;
- rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp);
+ rc = smb_auth_lm_response(lm_hash, challenge, ok_resp);
if (rc != SMBAUTH_SUCCESS)
return (B_FALSE);
- return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
+ return (bcmp(ok_resp, lm_resp, SMBAUTH_LM_RESP_SZ) == 0);
}
static boolean_t
smb_ntlm_password_ok(
unsigned char *challenge,
- uint32_t clen,
unsigned char *ntlm_hash,
- unsigned char *passwd,
+ unsigned char *nt_resp,
unsigned char *session_key)
{
- unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ];
+ unsigned char ok_resp[SMBAUTH_LM_RESP_SZ];
int rc;
boolean_t ok;
- rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp);
+ rc = smb_auth_ntlm_response(ntlm_hash, challenge, ok_resp);
if (rc != SMBAUTH_LM_RESP_SZ)
return (B_FALSE);
- ok = (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
+ ok = (bcmp(ok_resp, nt_resp, SMBAUTH_LM_RESP_SZ) == 0);
if (ok && (session_key)) {
rc = smb_auth_md4(session_key, ntlm_hash, SMBAUTH_HASH_SZ);
if (rc != SMBAUTH_SUCCESS)
@@ -350,7 +375,6 @@ smb_ntlm_password_ok(
static boolean_t
smb_ntlmv2_password_ok(
unsigned char *challenge,
- uint32_t clen,
unsigned char *ntlm_hash,
unsigned char *passwd,
int pwdlen,
@@ -404,7 +428,7 @@ smb_ntlmv2_password_ok(
break;
if (smb_auth_v2_response(ntlmv2_hash, challenge,
- clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
+ clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
break;
ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
@@ -426,8 +450,7 @@ smb_ntlmv2_password_ok(
static boolean_t
smb_lmv2_password_ok(
- unsigned char *challenge,
- uint32_t clen,
+ unsigned char *srv_challenge,
unsigned char *ntlm_hash,
unsigned char *passwd,
char *domain,
@@ -469,8 +492,8 @@ smb_lmv2_password_ok(
ntlmv2_hash) != SMBAUTH_SUCCESS)
break;
- if (smb_auth_v2_response(ntlmv2_hash, challenge,
- clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
+ if (smb_auth_v2_response(ntlmv2_hash, srv_challenge,
+ clnt_challenge, SMBAUTH_CHAL_SZ,
lmv2_resp) < 0)
break;
@@ -484,81 +507,83 @@ smb_lmv2_password_ok(
}
/*
- * smb_auth_validate_lm
+ * smb_auth_validate
*
- * Validates given LM/LMv2 client response, passed in passwd arg, against
- * stored user's password, passed in smbpw
- *
- * If LM level <=3 server accepts LM responses, otherwise LMv2
+ * Validates given NTLMv2 (or NTLM, LMv2, LM) client responses against
+ * the stored user's password, passed in smbpw. Try those in the order
+ * strongest to weakest, stopping at a point determined by the configured
+ * lmauth_level (LM Compatibility Level).
*/
boolean_t
-smb_auth_validate_lm(
- unsigned char *challenge,
- uint32_t clen,
+smb_auth_validate(
smb_passwd_t *smbpw,
- unsigned char *passwd,
- int pwdlen,
char *domain,
- char *username)
+ char *username,
+ unsigned char *challenge,
+ uint_t clen,
+ unsigned char *nt_resp,
+ uint_t nt_len,
+ unsigned char *lm_resp,
+ uint_t lm_len,
+ uchar_t *session_key)
{
- boolean_t ok = B_FALSE;
int64_t lmlevel;
-
- if (pwdlen != SMBAUTH_LM_RESP_SZ)
- return (B_FALSE);
+ boolean_t ok = B_FALSE;
if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
return (B_FALSE);
- if (lmlevel <= 3) {
- ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
- passwd);
- }
-
- if (!ok)
- ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
- passwd, domain, username);
+ if (lmlevel > 5)
+ return (B_FALSE);
- return (ok);
-}
+ if (clen != NTLM_CHAL_SZ)
+ return (B_FALSE);
-/*
- * smb_auth_validate_nt
- *
- * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against
- * stored user's password, passed in smbpw
- *
- * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2
- */
-boolean_t
-smb_auth_validate_nt(
- unsigned char *challenge,
- uint32_t clen,
- smb_passwd_t *smbpw,
- unsigned char *passwd,
- int pwdlen,
- char *domain,
- char *username,
- uchar_t *session_key)
-{
- int64_t lmlevel;
- boolean_t ok;
+ /*
+ * Accept NTLMv2 at any LM level (0-5).
+ */
+ if (nt_len > SMBAUTH_LM_RESP_SZ) {
+ ok = smb_ntlmv2_password_ok(challenge,
+ smbpw->pw_nthash, nt_resp, nt_len,
+ domain, username, session_key);
+ if (ok)
+ return (ok);
+ }
- if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
+ if (lmlevel == 5)
return (B_FALSE);
- if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
+ /*
+ * Accept NTLM at levels 0-4
+ */
+ if (nt_len == SMBAUTH_LM_RESP_SZ) {
+ ok = smb_ntlm_password_ok(challenge, smbpw->pw_nthash,
+ nt_resp, session_key);
+ if (ok)
+ return (ok);
+ }
+
+ if (lmlevel == 4)
return (B_FALSE);
- if (pwdlen > SMBAUTH_LM_RESP_SZ)
- ok = smb_ntlmv2_password_ok(challenge, clen,
- smbpw->pw_nthash, passwd, pwdlen,
- domain, username, session_key);
- else
- ok = smb_ntlm_password_ok(challenge, clen,
- smbpw->pw_nthash, passwd, session_key);
- return (ok);
+ /*
+ * Accept LM/LMv2 auth at levels 0-3
+ */
+ if (lm_len != SMBAUTH_LM_RESP_SZ)
+ return (B_FALSE);
+ if (session_key)
+ (void) smb_auth_md4(session_key, smbpw->pw_nthash,
+ SMBAUTH_HASH_SZ);
+ ok = smb_lmv2_password_ok(challenge, smbpw->pw_nthash,
+ lm_resp, domain, username);
+ if (ok)
+ return (ok);
+ ok = smb_lm_password_ok(challenge, smbpw->pw_lmhash, lm_resp);
+ if (ok)
+ return (ok);
+
+ return (B_FALSE);
}
/*
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
index 08ab3376be..1110fd8792 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
@@ -58,6 +58,7 @@ typedef struct smb_cfg_param {
/* idmap SMF fmri and Property Group */
#define IDMAP_FMRI_PREFIX "system/idmap"
#define MACHINE_SID "machine_sid"
+#define MACHINE_UUID "machine_uuid"
#define IDMAP_DOMAIN "domain_name"
#define IDMAP_PG_NAME "config"
@@ -121,14 +122,12 @@ static smb_cfg_param_t smb_cfg_table[] =
{SMB_CI_MACHINE_PASSWD, "machine_passwd", SCF_TYPE_ASTRING,
SMB_CF_PROTECTED},
- {SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING,
- 0},
- {SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING,
- 0},
- {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER,
- 0},
- {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER,
- 0},
+
+ {SMB_CI_MACHINE_UUID, "machine_uuid", SCF_TYPE_ASTRING, 0},
+ {SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING, 0},
+ {SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING, 0},
+ {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, 0},
+ {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, 0},
{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
{SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0},
{SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
@@ -136,6 +135,7 @@ static smb_cfg_param_t smb_cfg_table[] =
{SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
{SMB_CI_DFS_STDROOT_NUM, "dfs_stdroot_num", SCF_TYPE_INTEGER, 0},
{SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0},
+
/* SMB_CI_MAX */
};
@@ -800,7 +800,7 @@ smb_config_get_ads_enable(void)
*
* Returns value of the "config/machine_sid" parameter
* from the IDMAP SMF configuration repository.
- *
+ * Result is allocated; caller should free.
*/
char *
smb_config_get_localsid(void)
@@ -810,6 +810,32 @@ smb_config_get_localsid(void)
}
/*
+ * smb_config_get_localuuid
+ *
+ * Returns value of the "config/machine_uuid" parameter
+ * from the IDMAP SMF configuration repository.
+ *
+ */
+int
+smb_config_get_localuuid(uuid_t uu)
+{
+ char *s;
+
+ uuid_clear(uu);
+ s = smb_config_getenv_generic(MACHINE_UUID, IDMAP_FMRI_PREFIX,
+ IDMAP_PG_NAME);
+ if (s == NULL)
+ return (-1);
+
+ if (uuid_parse(s, uu) < 0) {
+ free(s);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
* smb_config_set_idmap_domain
*
* Set the "config/domain_name" parameter from IDMAP SMF repository.
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_info.c b/usr/src/lib/smbsrv/libsmb/common/smb_info.c
index ea6707951e..0dcae43179 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c
@@ -20,11 +20,14 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
-#include <assert.h>
#include <sys/types.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
@@ -39,11 +42,11 @@
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
-#include <sys/sockio.h>
-#include <sys/socket.h>
+
#include <smbsrv/smbinfo.h>
#include <smbsrv/netbios.h>
#include <smbsrv/libsmb.h>
+#include <assert.h>
static mutex_t seqnum_mtx;
@@ -67,6 +70,7 @@ static rwlock_t smb_ipc_lock;
void
smb_load_kconfig(smb_kmod_cfg_t *kcfg)
{
+ struct utsname uts;
int64_t citem;
bzero(kcfg, sizeof (smb_kmod_cfg_t));
@@ -106,6 +110,18 @@ smb_load_kconfig(smb_kmod_cfg_t *kcfg)
sizeof (kcfg->skc_system_comment));
smb_config_get_version(&kcfg->skc_version);
kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0);
+ if (smb_config_get_localuuid(kcfg->skc_machine_uuid) < 0) {
+ syslog(LOG_ERR, "smb_load_kconfig: no machine_uuid");
+ uuid_generate_time(kcfg->skc_machine_uuid);
+ }
+ /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */
+
+ (void) uname(&uts);
+ (void) snprintf(kcfg->skc_native_os, sizeof (kcfg->skc_native_os),
+ "%s %s %s", uts.sysname, uts.release, uts.version);
+
+ (void) strlcpy(kcfg->skc_native_lm, "Native SMB service",
+ sizeof (kcfg->skc_native_lm));
}
/*
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c
index 145d8da21c..8b7b32fb19 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c
@@ -69,6 +69,7 @@ smb_kmod_isbound(void)
return ((smbdrv_fd == -1) ? B_FALSE : B_TRUE);
}
+/* See also: smbsrv smb_server_store_cfg */
int
smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
{
@@ -83,13 +84,21 @@ smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
ioc.oplock_enable = cfg->skc_oplock_enable;
ioc.sync_enable = cfg->skc_sync_enable;
ioc.secmode = cfg->skc_secmode;
- ioc.ipv6_enable = cfg->skc_ipv6_enable;
ioc.netbios_enable = cfg->skc_netbios_enable;
+ ioc.ipv6_enable = cfg->skc_ipv6_enable;
ioc.print_enable = cfg->skc_print_enable;
ioc.traverse_mounts = cfg->skc_traverse_mounts;
ioc.exec_flags = cfg->skc_execflags;
+ ioc.negtok_len = cfg->skc_negtok_len;
ioc.version = cfg->skc_version;
+ (void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t));
+ (void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok));
+ (void) memcpy(ioc.native_os, cfg->skc_native_os,
+ sizeof (ioc.native_os));
+ (void) memcpy(ioc.native_lm, cfg->skc_native_lm,
+ sizeof (ioc.native_lm));
+
(void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain));
(void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn));
(void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname));
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_mac.c b/usr/src/lib/smbsrv/libsmb/common/smb_mac.c
deleted file mode 100644
index 57fb74530c..0000000000
--- a/usr/src/lib/smbsrv/libsmb/common/smb_mac.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * SMB MAC Signing support.
- */
-
-#include <strings.h>
-#include <security/cryptoki.h>
-#include <security/pkcs11.h>
-
-#include <smbsrv/libsmb.h>
-
-#include <smbsrv/smb.h>
-
-/*
- * smb_mac_init
- *
- * Calculates the MAC key using the specified user session
- * key (NTLM or NTLMv2).
- *
- * Returns SMBAUTH_SUCCESS if key generation was successful,
- * SMBAUTH_FAILURE if not.
- */
-int
-smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth)
-{
- unsigned char S16[SMBAUTH_SESSION_KEY_SZ];
-
- if (smb_auth_gen_session_key(auth, S16) != SMBAUTH_SUCCESS)
- return (SMBAUTH_FAILURE);
- bcopy(S16, sign_ctx->ssc_mackey, SMBAUTH_SESSION_KEY_SZ);
- bcopy(auth->cs, &(sign_ctx->ssc_mackey[SMBAUTH_SESSION_KEY_SZ]),
- auth->cs_len);
- sign_ctx->ssc_keylen = SMBAUTH_SESSION_KEY_SZ + auth->cs_len;
- return (SMBAUTH_SUCCESS);
-}
-
-/*
- * smb_mac_calc
- *
- * Calculates MAC signature for the given buffer and returns
- * it in the mac_sign parameter.
- *
- * The MAC signature is calculated as follows:
- *
- * data = concat(MAC_Key, MAC_Key_Len, SMB_Msg, SMB_Msg_Len);
- * hash = MD5(data);
- * MAC = head(hash, 8);
- *
- * The tricky part is that a sequence number should be used
- * in calculation instead of the signature field in the
- * SMB header.
- *
- * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
- * SMBAUTH_FAILURE if not.
- */
-int
-smb_mac_calc(smb_sign_ctx_t *sign_ctx, const unsigned char *buf,
- size_t buf_len, unsigned char *mac_sign)
-{
- CK_RV rv;
- CK_MECHANISM mechanism;
- CK_SESSION_HANDLE hSession;
- unsigned long diglen = MD_DIGEST_LEN;
- int rc = SMBAUTH_FAILURE;
-
- int offset_end_of_sig = (SMB_SIG_OFFS + SMB_SIG_SIZE);
- unsigned char seq_buf[SMB_SIG_SIZE];
- unsigned char mac[16];
-
- /*
- * put seq_num into the first 4 bytes and
- * zero out the next 4 bytes
- */
- bcopy(&sign_ctx->ssc_seqnum, seq_buf, 4);
- bzero(seq_buf + 4, 4);
-
- mechanism.mechanism = CKM_MD5;
- mechanism.pParameter = 0;
- mechanism.ulParameterLen = 0;
-
- rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
- if (rv != CKR_OK)
- return (SMBAUTH_FAILURE);
-
- /* Initialize the digest operation in the session */
- rv = C_DigestInit(hSession, &mechanism);
- if (rv != CKR_OK)
- goto smbmacdone;
-
- /* init with the MAC key */
- rv = C_DigestUpdate(hSession, sign_ctx->ssc_mackey,
- sign_ctx->ssc_keylen);
- if (rv != CKR_OK)
- goto smbmacdone;
-
- /* copy in SMB packet info till signature field */
- rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf, SMB_SIG_OFFS);
- if (rv != CKR_OK)
- goto smbmacdone;
-
- /* copy in the seq_buf instead of the signature */
- rv = C_DigestUpdate(hSession, seq_buf, sizeof (seq_buf));
- if (rv != CKR_OK)
- goto smbmacdone;
-
- /* copy in the rest of the packet, skipping the signature */
- rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf + offset_end_of_sig,
- buf_len - offset_end_of_sig);
- if (rv != CKR_OK)
- goto smbmacdone;
-
- rv = C_DigestFinal(hSession, mac, &diglen);
- if (rv != CKR_OK)
- goto smbmacdone;
-
- bcopy(mac, mac_sign, SMB_SIG_SIZE);
- rc = SMBAUTH_SUCCESS;
-
-smbmacdone:
- (void) C_CloseSession(hSession);
- return (rc);
-}
-
-/*
- * smb_mac_chk
- *
- * Calculates MAC signature for the given buffer
- * and compares it to the signature in the given context.
- * Return 1 if the signature are match, otherwise, return (0);
- */
-int
-smb_mac_chk(smb_sign_ctx_t *sign_ctx,
- const unsigned char *buf, size_t buf_len)
-{
- unsigned char mac_sign[SMB_SIG_SIZE];
-
- /* calculate mac signature */
- if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
- return (0);
-
- /* compare the signatures */
- if (memcmp(sign_ctx->ssc_sign, mac_sign, SMB_SIG_SIZE) == 0)
- return (1);
-
- return (0);
-}
-
-/*
- * smb_mac_sign
- *
- * Calculates MAC signature for the given buffer,
- * and write it to the buffer's signature field.
- *
- * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
- * SMBAUTH_FAILURE if not.
- */
-int
-smb_mac_sign(smb_sign_ctx_t *sign_ctx, unsigned char *buf, size_t buf_len)
-{
- unsigned char mac_sign[SMB_SIG_SIZE];
-
- /* calculate mac signature */
- if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
- return (SMBAUTH_FAILURE);
-
- /* put mac signature in the header's signature field */
- (void) memcpy(buf + SMB_SIG_OFFS, mac_sign, SMB_SIG_SIZE);
- return (SMBAUTH_SUCCESS);
-}
-
-void
-smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx)
-{
- sign_ctx->ssc_seqnum++;
-}
-
-void
-smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx)
-{
- sign_ctx->ssc_seqnum--;
-}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c
index b359d32d5d..19cb5166a1 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c
@@ -21,6 +21,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <syslog.h>
@@ -262,10 +264,13 @@ smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw)
return (smb_pwd_ops.pwop_getpwnam(name, smbpw));
err = smb_pwd_lock();
- if (err != SMB_PWE_SUCCESS)
+ if (err != SMB_PWE_SUCCESS) {
+ syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err);
return (NULL);
+ }
if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
+ syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
(void) smb_pwd_unlock();
return (NULL);
}
@@ -274,8 +279,7 @@ smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw)
while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
if (strcmp(name, smbpw->pw_name) == 0) {
- if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
- found = B_TRUE;
+ found = B_TRUE;
break;
}
}
@@ -311,10 +315,13 @@ smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw)
return (smb_pwd_ops.pwop_getpwuid(uid, smbpw));
err = smb_pwd_lock();
- if (err != SMB_PWE_SUCCESS)
+ if (err != SMB_PWE_SUCCESS) {
+ syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err);
return (NULL);
+ }
if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
+ syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
(void) smb_pwd_unlock();
return (NULL);
}
@@ -323,8 +330,7 @@ smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw)
while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) {
if (uid == smbpw->pw_uid) {
- if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)))
- found = B_TRUE;
+ found = B_TRUE;
break;
}
}
@@ -1002,10 +1008,13 @@ smb_lucache_do_update(void)
void *cookie = NULL;
FILE *fp;
- if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS)
+ if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) {
+ syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", rc);
return (rc);
+ }
if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) {
+ syslog(LOG_WARNING, "smb_pwdutil: open failed, %m");
(void) smb_pwd_unlock();
return (SMB_PWE_OPEN_FAILED);
}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h
index 279634afc2..d60bca8785 100644
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_SMB_KRB_H
@@ -40,6 +41,7 @@ extern "C" {
#define SMB_PN_SALT 0x0008 /* w/ REALM */
#define SMB_PN_SVC_HOST "host"
+#define SMB_PN_SVC_CIFS "cifs"
#define SMB_PN_SVC_NFS "nfs"
#define SMB_PN_SVC_HTTP "HTTP"
#define SMB_PN_SVC_ROOT "root"
@@ -47,7 +49,11 @@ extern "C" {
/* Assign an identifier for each principal name format */
typedef enum smb_krb5_pn_id {
SMB_KRB5_PN_ID_SALT,
- SMB_KRB5_PN_ID_HOST_FQHN,
+ SMB_KRB5_PN_ID_HOST_FQHN, /* fully qualified name */
+ SMB_KRB5_PN_ID_HOST_SHORT, /* short name */
+ SMB_KRB5_PN_ID_CIFS_FQHN,
+ SMB_KRB5_PN_ID_CIFS_SHORT,
+ SMB_KRB5_PN_ID_MACHINE, /* the machine account */
SMB_KRB5_PN_ID_NFS_FQHN,
SMB_KRB5_PN_ID_HTTP_FQHN,
SMB_KRB5_PN_ID_ROOT_FQHN,
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c
index 946ca6461a..7a6a3491a1 100644
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -49,9 +50,17 @@ static smb_krb5_pn_t smb_krb5_pn_tab[] = {
*/
{SMB_KRB5_PN_ID_SALT, SMB_PN_SVC_HOST, SMB_PN_SALT},
- /* HOST */
+ /* CIFS SPNs. (HOST, CIFS, ...) */
{SMB_KRB5_PN_ID_HOST_FQHN, SMB_PN_SVC_HOST,
SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR | SMB_PN_UPN_ATTR},
+ {SMB_KRB5_PN_ID_HOST_SHORT, SMB_PN_SVC_HOST,
+ SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
+ {SMB_KRB5_PN_ID_CIFS_FQHN, SMB_PN_SVC_CIFS,
+ SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
+ {SMB_KRB5_PN_ID_CIFS_SHORT, SMB_PN_SVC_CIFS,
+ SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
+ {SMB_KRB5_PN_ID_MACHINE, NULL,
+ SMB_PN_KEYTAB_ENTRY},
/* NFS */
{SMB_KRB5_PN_ID_NFS_FQHN, SMB_PN_SVC_NFS,
@@ -529,12 +538,30 @@ smb_krb5_get_pn_by_id(smb_krb5_pn_id_t id, uint32_t type,
break;
case SMB_KRB5_PN_ID_HOST_FQHN:
+ case SMB_KRB5_PN_ID_CIFS_FQHN:
case SMB_KRB5_PN_ID_NFS_FQHN:
case SMB_KRB5_PN_ID_HTTP_FQHN:
case SMB_KRB5_PN_ID_ROOT_FQHN:
(void) asprintf(&buf, "%s/%s.%s",
pn->p_svc, hostname, fqdn);
break;
+
+ case SMB_KRB5_PN_ID_HOST_SHORT:
+ case SMB_KRB5_PN_ID_CIFS_SHORT:
+ (void) asprintf(&buf, "%s/%s",
+ pn->p_svc, nbname);
+ break;
+
+ /*
+ * SPN for the machine account, which is simply the
+ * (short) machine name with a dollar sign appended.
+ */
+ case SMB_KRB5_PN_ID_MACHINE:
+ (void) asprintf(&buf, "%s$", nbname);
+ break;
+
+ default:
+ return (NULL);
}
/*
diff --git a/usr/src/tools/quick/make-smbsrv b/usr/src/tools/quick/make-smbsrv
index 3eca17ff83..2dc2651ce6 100755
--- a/usr/src/tools/quick/make-smbsrv
+++ b/usr/src/tools/quick/make-smbsrv
@@ -88,10 +88,10 @@ then
(cd $SRC/head && $make install_h)
# always update the smbsrv headers to be safe
- # test -f $ROOT/usr/include/smbsrv/wintypes.h ||
- (cd $SRC/uts/common/sys && $make -k install_h)
- (cd $SRC/uts/common/smb && $make -k install_h)
- (cd $SRC/uts/common/smbsrv && $make -k install_h)
+ (cd $SRC/uts/common/gssapi && $make -k install_h)
+ (cd $SRC/uts/common/sys && $make -k install_h)
+ (cd $SRC/uts/common/smb && $make -k install_h)
+ (cd $SRC/uts/common/smbsrv && $make -k install_h)
fi
@@ -102,6 +102,8 @@ for lib in \
libcryptoutil \
libdevid \
libfakekernel \
+ libgss \
+ libkrb5 \
libidmap \
libpam \
libsec \
@@ -140,6 +142,8 @@ do_lib1() {
for lib in \
libavl \
+ libgss \
+ libkrb5 \
libcmdutils \
libsqlite \
libuutil
@@ -241,8 +245,12 @@ do_tags() {
find uts/common/smbsrv -name '*.ndl' -print |sort
find uts/common/smbsrv -name '*.[ch]' -print |sort
find uts/common/fs/smbsrv -name '*.[ch]' -print |sort
- find lib/libsmbfs -name '*.[ch]' -print |sort
+ find uts/common/gssapi -name '*.[ch]' -print |sort
+ find head -name '*.h' -print |sort
find lib/smbsrv -name '*.[ch]' -print |sort
+ find lib/libsmbfs -name '*.[ch]' -print |sort
+ find lib/libads -name '*.[ch]' -print |sort
+ find lib/libgss -name '*.[ch]' -print |sort
find cmd/smbsrv -name '*.[ch]' -print |sort
find common/smbsrv -name '*.[ch]' -print |sort
) > $SRC/cscope.files
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index cd9da11ac8..c90a5c1773 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1182,10 +1182,12 @@ SMBSRV_SHARED_OBJS += \
SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
smb_acl.o \
smb_alloc.o \
+ smb_authenticate.o \
smb_close.o \
smb_common_open.o \
smb_common_transact.o \
smb_create.o \
+ smb_cred.o \
smb_delete.o \
smb_directory.o \
smb_dispatch.o \
diff --git a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
new file mode 100644
index 0000000000..ffc553cada
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
@@ -0,0 +1,706 @@
+/*
+ * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Authentication support for SMB session setup
+ */
+
+#include <sys/types.h>
+#include <sys/sid.h>
+#include <sys/priv_names.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_idmap.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_token.h>
+
+static uint32_t smb_authsock_open(smb_user_t *);
+static int smb_authsock_send(ksocket_t, void *, size_t);
+static int smb_authsock_recv(ksocket_t, void *, size_t);
+static uint32_t smb_authsock_sendrecv(smb_user_t *, smb_lsa_msg_hdr_t *hdr,
+ void *sndbuf, void **recvbuf);
+/* void smb_authsock_close(smb_user_t *); kproto.h */
+
+static uint32_t smb_auth_do_clinfo(smb_request_t *);
+static uint32_t smb_auth_do_oldreq(smb_request_t *);
+static uint32_t smb_auth_get_token(smb_request_t *);
+static uint32_t smb_priv_xlate(smb_token_t *);
+
+/*
+ * Handle old-style session setup (non-extended security)
+ *
+ * The user information is passed to smbd for authentication.
+ * If smbd can authenticate the user an access token is returned and we
+ * generate a cred and new user based on the token.
+ */
+int
+smb_authenticate_old(smb_request_t *sr)
+{
+ smb_user_t *user = NULL;
+ uint32_t status;
+
+ user = smb_user_new(sr->session);
+ if (user == NULL)
+ return (NT_STATUS_TOO_MANY_SESSIONS);
+
+ /* user cleanup in smb_request_free */
+ sr->uid_user = user;
+ sr->smb_uid = user->u_uid;
+
+ /*
+ * Open a connection to the local logon service.
+ * If we can't, it may be busy, or not running.
+ * Don't log here - this may be frequent.
+ */
+ if ((status = smb_authsock_open(user)) != 0)
+ goto errout;
+
+ /*
+ * Tell the auth. svc who this client is.
+ */
+ if ((status = smb_auth_do_clinfo(sr)) != 0)
+ goto errout;
+
+ /*
+ * Authentication proper
+ */
+ if ((status = smb_auth_do_oldreq(sr)) != 0)
+ goto errout;
+
+ /*
+ * Get the final auth. token.
+ */
+ if ((status = smb_auth_get_token(sr)) != 0)
+ goto errout;
+
+ return (0);
+
+errout:
+ smb_user_logoff(user);
+ return (status);
+}
+
+/*
+ * Build an authentication request message and
+ * send it to the local logon service.
+ */
+static uint32_t
+smb_auth_do_oldreq(smb_request_t *sr)
+{
+ smb_lsa_msg_hdr_t msg_hdr;
+ smb_logon_t user_info;
+ XDR xdrs;
+ smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
+ smb_user_t *user = sr->uid_user;
+ void *sbuf = NULL;
+ void *rbuf = NULL;
+ uint32_t slen = 0;
+ uint32_t rlen = 0;
+ uint32_t status;
+ bool_t ok;
+
+ bzero(&user_info, sizeof (smb_logon_t));
+
+ user_info.lg_level = NETR_NETWORK_LOGON;
+ user_info.lg_username = sinfo->ssi_user;
+ user_info.lg_domain = sinfo->ssi_domain;
+ user_info.lg_workstation = sr->session->workstation;
+ user_info.lg_clnt_ipaddr = sr->session->ipaddr;
+ user_info.lg_local_ipaddr = sr->session->local_ipaddr;
+ user_info.lg_local_port = sr->session->s_local_port;
+ user_info.lg_challenge_key.val = sr->session->challenge_key;
+ user_info.lg_challenge_key.len = sr->session->challenge_len;
+ user_info.lg_nt_password.val = sinfo->ssi_ntpwd;
+ user_info.lg_nt_password.len = sinfo->ssi_ntpwlen;
+ user_info.lg_lm_password.val = sinfo->ssi_lmpwd;
+ user_info.lg_lm_password.len = sinfo->ssi_lmpwlen;
+ user_info.lg_native_os = sr->session->native_os;
+ user_info.lg_native_lm = sr->session->native_lm;
+ /* lg_flags? */
+
+ slen = xdr_sizeof(smb_logon_xdr, &user_info);
+ sbuf = kmem_alloc(slen, KM_SLEEP);
+ xdrmem_create(&xdrs, sbuf, slen, XDR_ENCODE);
+ ok = smb_logon_xdr(&xdrs, &user_info);
+ xdr_destroy(&xdrs);
+ if (!ok) {
+ status = RPC_NT_BAD_STUB_DATA;
+ goto out;
+ }
+
+ msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ;
+ msg_hdr.lmh_msglen = slen;
+ status = smb_authsock_sendrecv(user, &msg_hdr, sbuf, &rbuf);
+ if (status != 0)
+ goto out;
+ rlen = msg_hdr.lmh_msglen;
+ kmem_free(sbuf, slen);
+ sbuf = NULL;
+
+ /*
+ * Decode the response message.
+ */
+ switch (msg_hdr.lmh_msgtype) {
+
+ case LSA_MTYPE_OK:
+ status = 0;
+ break;
+
+ case LSA_MTYPE_ERROR:
+ if (rlen == sizeof (smb_lsa_eresp_t)) {
+ smb_lsa_eresp_t *ler = rbuf;
+ status = ler->ler_ntstatus;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default: /* Bogus message type */
+ status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+
+out:
+ if (rbuf != NULL)
+ kmem_free(rbuf, rlen);
+ if (sbuf != NULL)
+ kmem_free(sbuf, slen);
+
+ return (status);
+}
+
+/*
+ * Handle new-style (extended security) session setup.
+ * Returns zero: success, non-zero: error (value not used)
+ *
+ * Note that this style uses a sequence of session setup requests,
+ * where the first has SMB UID=0, and subsequent requests in the
+ * same authentication sequence have the SMB UID returned for that
+ * first request. We allocate a USER object when the first request
+ * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that
+ * to maintain state between requests in this sequence. The state
+ * for one sequence includes an AF_UNIX "authsock" connection to the
+ * user-space smbd. The neat part of this is: in smbd, the handler
+ * for the server-side of one authsock gets only request specific to
+ * one authentication sequence, simplifying it's work immensely.
+ * When the authentication sequence is finished, with either success
+ * or failure, the local side of the authsock is closed.
+ *
+ * As with the old-style authentication, if we succeed, then the
+ * last message from smbd will be an smb_token_t encoding the
+ * information about the new user.
+ *
+ * Outline:
+ * (a) On the first request (UID==0) create a USER object,
+ * and on subsequent requests, find USER by SMB UID.
+ * (b) Send message / recv. response as above,
+ * (c) If response says "we're done", close authsock
+ * (both success and failure must close authsock)
+ */
+int
+smb_authenticate_ext(smb_request_t *sr)
+{
+ smb_lsa_msg_hdr_t msg_hdr;
+ smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
+ smb_user_t *user = NULL;
+ void *rbuf = NULL;
+ uint32_t rlen = 0;
+ uint32_t status;
+
+ ASSERT(sr->uid_user == NULL);
+
+ /*
+ * On the first request (UID==0) create a USER object.
+ * On subsequent requests (UID!=0) find the USER object.
+ * Either way, sr->uid_user is set, so our ref. on the
+ * user object is dropped during normal cleanup work
+ * for the smb_request (sr). Ditto u_authsock.
+ */
+ if (sr->smb_uid == 0) {
+ user = smb_user_new(sr->session);
+ if (user == NULL)
+ return (NT_STATUS_TOO_MANY_SESSIONS);
+
+ /* user cleanup in smb_request_free */
+ sr->uid_user = user;
+ sr->smb_uid = user->u_uid;
+
+ /*
+ * Open a connection to the local logon service.
+ * If we can't, it may be busy, or not running.
+ * Don't log here - this may be frequent.
+ */
+ if ((status = smb_authsock_open(user)) != 0)
+ goto errout;
+
+ /*
+ * Tell the auth. svc who this client is.
+ */
+ if ((status = smb_auth_do_clinfo(sr)) != 0)
+ goto errout;
+
+ msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST;
+ } else {
+ user = smb_session_lookup_uid_st(sr->session,
+ sr->smb_uid, SMB_USER_STATE_LOGGING_ON);
+ if (user == NULL)
+ return (NT_STATUS_USER_SESSION_DELETED);
+
+ /* user cleanup in smb_request_free */
+ sr->uid_user = user;
+
+ msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT;
+ }
+
+ /*
+ * Wrap the "security blob" with our header
+ * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT)
+ * and send it up the authsock with either
+ */
+ msg_hdr.lmh_msglen = sinfo->ssi_iseclen;
+ status = smb_authsock_sendrecv(user, &msg_hdr,
+ sinfo->ssi_isecblob, &rbuf);
+ if (status != 0)
+ goto errout;
+ rlen = msg_hdr.lmh_msglen;
+
+ /*
+ * Decode the response message.
+ * Note: allocated rbuf
+ */
+ switch (msg_hdr.lmh_msgtype) {
+
+ case LSA_MTYPE_ES_CONT:
+ sinfo->ssi_oseclen = (uint16_t)rlen;
+ sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
+ bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
+ /*
+ * This is not really an error, but tells the client
+ * it should send another session setup request.
+ */
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ break;
+
+ case LSA_MTYPE_ES_DONE:
+ sinfo->ssi_oseclen = (uint16_t)rlen;
+ sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
+ bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
+ sinfo->ssi_ntpwlen = 0;
+ /*
+ * Get the final auth. token.
+ */
+ status = smb_auth_get_token(sr);
+ break;
+
+ case LSA_MTYPE_ERROR:
+ /*
+ * Authentication failed. Return the error
+ * provided in the reply message.
+ */
+ if (rlen == sizeof (smb_lsa_eresp_t)) {
+ smb_lsa_eresp_t *ler = rbuf;
+ status = ler->ler_ntstatus;
+ goto errout;
+ }
+ /* FALLTHROUGH */
+
+ default: /* Bogus message type */
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto errout;
+ }
+
+ if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
+ errout:
+ smb_user_logoff(user);
+ }
+
+ if (rbuf != NULL)
+ kmem_free(rbuf, rlen);
+
+ return (status);
+}
+
+/*
+ * Send the "client info" up to the auth service.
+ */
+static uint32_t
+smb_auth_do_clinfo(smb_request_t *sr)
+{
+ smb_lsa_msg_hdr_t msg_hdr;
+ smb_lsa_clinfo_t clinfo;
+ smb_user_t *user = sr->uid_user;
+ void *rbuf = NULL;
+ uint32_t status;
+
+ /*
+ * Send a message with info. about the client
+ * (IP address, etc) and wait for an ACK.
+ */
+ msg_hdr.lmh_msgtype = LSA_MTYPE_CLINFO;
+ msg_hdr.lmh_msglen = sizeof (clinfo);
+ clinfo.lci_clnt_ipaddr = sr->session->ipaddr;
+ (void) memcpy(clinfo.lci_challenge_key,
+ sr->session->challenge_key,
+ sizeof (clinfo.lci_challenge_key));
+ status = smb_authsock_sendrecv(user, &msg_hdr, &clinfo, &rbuf);
+ /* We don't use this response. */
+ if (rbuf != NULL) {
+ kmem_free(rbuf, msg_hdr.lmh_msglen);
+ rbuf = NULL;
+ }
+
+ return (status);
+}
+
+/*
+ * After a successful authentication, ask the authsvc to
+ * send us the authentication token.
+ */
+static uint32_t
+smb_auth_get_token(smb_request_t *sr)
+{
+ smb_lsa_msg_hdr_t msg_hdr;
+ XDR xdrs;
+ smb_user_t *user = sr->uid_user;
+ smb_token_t *token = NULL;
+ cred_t *cr = NULL;
+ void *rbuf = NULL;
+ uint32_t rlen = 0;
+ uint32_t privileges;
+ uint32_t status;
+ bool_t ok;
+
+ msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK;
+ msg_hdr.lmh_msglen = 0;
+
+ status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf);
+ if (status != 0)
+ goto errout;
+
+ rlen = msg_hdr.lmh_msglen;
+ switch (msg_hdr.lmh_msgtype) {
+
+ case LSA_MTYPE_TOKEN:
+ status = 0;
+ break;
+
+ case LSA_MTYPE_ERROR:
+ if (rlen == sizeof (smb_lsa_eresp_t)) {
+ smb_lsa_eresp_t *ler = rbuf;
+ status = ler->ler_ntstatus;
+ goto errout;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto errout;
+ }
+
+ /*
+ * Authenticated. Decode the LSA_MTYPE_TOKEN.
+ */
+ xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE);
+ token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
+ ok = smb_token_xdr(&xdrs, token);
+ xdr_destroy(&xdrs);
+ if (!ok) {
+ status = RPC_NT_BAD_STUB_DATA;
+ goto errout;
+ }
+ kmem_free(rbuf, rlen);
+ rbuf = NULL;
+
+ /*
+ * Setup the logon object.
+ */
+ cr = smb_cred_create(token);
+ if (cr == NULL)
+ goto errout;
+ privileges = smb_priv_xlate(token);
+ (void) smb_user_logon(user, cr,
+ token->tkn_domain_name, token->tkn_account_name,
+ token->tkn_flags, privileges, token->tkn_audit_sid);
+ crfree(cr);
+
+ /*
+ * Save the session key, and (maybe) enable signing,
+ * but only for real logon (not ANON or GUEST).
+ */
+ if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) {
+ if (smb_sign_begin(sr, token) != 0) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto errout;
+ }
+ }
+
+ smb_token_free(token);
+
+ sr->user_cr = user->u_cred;
+ return (0);
+
+errout:
+ if (rbuf != NULL)
+ kmem_free(rbuf, rlen);
+ if (token != NULL)
+ smb_token_free(token);
+ return (status);
+}
+
+/*
+ * Tokens are allocated in the kernel via XDR.
+ * Call xdr_free before freeing the token structure.
+ */
+void
+smb_token_free(smb_token_t *token)
+{
+ if (token != NULL) {
+ xdr_free(smb_token_xdr, (char *)token);
+ kmem_free(token, sizeof (smb_token_t));
+ }
+}
+
+/*
+ * Convert access token privileges to local definitions.
+ */
+static uint32_t
+smb_priv_xlate(smb_token_t *token)
+{
+ uint32_t privileges = 0;
+
+ if (smb_token_query_privilege(token, SE_BACKUP_LUID))
+ privileges |= SMB_USER_PRIV_BACKUP;
+
+ if (smb_token_query_privilege(token, SE_RESTORE_LUID))
+ privileges |= SMB_USER_PRIV_RESTORE;
+
+ if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
+ privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
+
+ if (smb_token_query_privilege(token, SE_SECURITY_LUID))
+ privileges |= SMB_USER_PRIV_SECURITY;
+
+ return (privileges);
+}
+
+/*
+ * Send/recv a request/reply sequence on the auth socket.
+ * Returns zero or an NT status.
+ *
+ * Errors here mean we can't communicate with the smbd_authsvc.
+ * With limited authsock instances, this should be rare.
+ */
+static uint32_t
+smb_authsock_sendrecv(smb_user_t *user, smb_lsa_msg_hdr_t *hdr,
+ void *sndbuf, void **recvbuf)
+{
+ ksocket_t so;
+ uint32_t status;
+ int rc;
+
+ /*
+ * Get a hold on the auth socket.
+ */
+ mutex_enter(&user->u_mutex);
+ so = user->u_authsock;
+ if (so == NULL) {
+ mutex_exit(&user->u_mutex);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ ksocket_hold(so);
+ mutex_exit(&user->u_mutex);
+
+ rc = smb_authsock_send(so, hdr, sizeof (*hdr));
+ if (rc == 0 && hdr->lmh_msglen != 0) {
+ rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
+ }
+ if (rc)
+ goto out;
+
+ rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
+ if (rc == 0 && hdr->lmh_msglen != 0) {
+ *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
+ rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
+ if (rc) {
+ kmem_free(*recvbuf, hdr->lmh_msglen);
+ *recvbuf = NULL;
+ }
+ }
+
+out:
+ ksocket_rele(so);
+ switch (rc) {
+ case 0:
+ status = 0;
+ break;
+ case EIO:
+ status = RPC_NT_COMM_FAILURE;
+ break;
+ case ENOTCONN:
+ status = RPC_NT_PIPE_CLOSED;
+ break;
+ default:
+ status = RPC_NT_CALL_FAILED;
+ break;
+ }
+
+ return (status);
+}
+
+/*
+ * Hope this is interpreted per-zone...
+ */
+static struct sockaddr_un smbauth_sockname = {
+ AF_UNIX, SMB_AUTHSVC_SOCKNAME };
+
+/*
+ * Limit how long smb_authsock_sendrecv() will wait for a
+ * response from the local authentication service.
+ */
+struct timeval smb_auth_recv_tmo = { 45, 0 };
+
+/*
+ * Also limit the time smb_authsock_sendrecv() will wait
+ * trying to send a request to the authentication service.
+ */
+struct timeval smb_auth_send_tmo = { 15, 0 };
+
+static uint32_t
+smb_authsock_open(smb_user_t *user)
+{
+ smb_server_t *sv = user->u_server;
+ ksocket_t so = NULL;
+ uint32_t status;
+ int rc;
+
+ /*
+ * If the auth. service is busy, wait our turn.
+ * This may be frequent, so don't log.
+ */
+ if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
+ return (NT_STATUS_NO_LOGON_SERVERS);
+
+ rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
+ KSOCKET_SLEEP, CRED());
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
+ status = NT_STATUS_INSUFF_SERVER_RESOURCES;
+ goto errout;
+ }
+
+ /*
+ * Set the send/recv timeouts.
+ */
+ (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
+ &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
+ (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
+ &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
+
+ /*
+ * Connect to the smbd auth. service.
+ *
+ * Would like to set the connect timeout too, but there's
+ * apparently no easy way to do that for AF_UNIX.
+ */
+ rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
+ sizeof (smbauth_sockname), CRED());
+ if (rc != 0) {
+ DTRACE_PROBE1(error, int, rc);
+ status = NT_STATUS_NETLOGON_NOT_STARTED;
+ goto errout;
+ }
+
+ /* Note: u_authsock cleanup in smb_authsock_close() */
+ mutex_enter(&user->u_mutex);
+ if (user->u_authsock != NULL) {
+ mutex_exit(&user->u_mutex);
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto errout;
+ }
+ user->u_authsock = so;
+ mutex_exit(&user->u_mutex);
+ return (0);
+
+errout:
+ if (so != NULL)
+ (void) ksocket_close(so, CRED());
+ smb_threshold_exit(&sv->sv_ssetup_ct);
+
+ return (status);
+}
+
+static int
+smb_authsock_send(ksocket_t so, void *buf, size_t len)
+{
+ int rc;
+ size_t iocnt = 0;
+
+ rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
+ if (rc == 0 && iocnt != len) {
+ DTRACE_PROBE1(short, size_t, iocnt);
+ rc = EIO;
+ }
+ if (rc != 0) {
+ DTRACE_PROBE1(error, int, rc);
+ }
+
+ return (rc);
+}
+
+static int
+smb_authsock_recv(ksocket_t so, void *buf, size_t len)
+{
+ int rc;
+ size_t iocnt = 0;
+
+ rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
+ if (rc == 0) {
+ if (iocnt == 0) {
+ DTRACE_PROBE1(discon, struct sonode *, so);
+ rc = ENOTCONN;
+ } else if (iocnt != len) {
+ /* Should not happen with MSG_WAITALL */
+ DTRACE_PROBE1(short, size_t, iocnt);
+ rc = EIO;
+ }
+ }
+ if (rc != 0) {
+ DTRACE_PROBE1(error, int, rc);
+ }
+
+ return (rc);
+}
+
+void
+smb_authsock_close(smb_user_t *user)
+{
+
+ ASSERT(MUTEX_HELD(&user->u_mutex));
+ if (user->u_authsock == NULL)
+ return;
+ (void) ksocket_close(user->u_authsock, CRED());
+ user->u_authsock = NULL;
+ smb_threshold_exit(&user->u_server->sv_ssetup_ct);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_cred.c b/usr/src/uts/common/fs/smbsrv/smb_cred.c
new file mode 100644
index 0000000000..c6956518fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_cred.c
@@ -0,0 +1,157 @@
+/*
+ * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Authentication helpers for building credentials
+ */
+
+#include <sys/types.h>
+#include <sys/sid.h>
+#include <sys/priv_names.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_idmap.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_token.h>
+
+static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
+static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
+
+/*
+ * Allocate a Solaris cred and initialize it based on the access token.
+ *
+ * If the user can be mapped to a non-ephemeral ID, the cred gid is set
+ * to the Solaris user's primary group.
+ *
+ * If the mapped UID is ephemeral, or the primary group could not be
+ * obtained, the cred gid is set to whatever Solaris group is mapped
+ * to the token's primary group.
+ */
+cred_t *
+smb_cred_create(smb_token_t *token)
+{
+ ksid_t ksid;
+ ksidlist_t *ksidlist = NULL;
+ smb_posix_grps_t *posix_grps;
+ cred_t *cr;
+ gid_t gid;
+
+ ASSERT(token);
+ ASSERT(token->tkn_posix_grps);
+ posix_grps = token->tkn_posix_grps;
+
+ cr = crget();
+ ASSERT(cr != NULL);
+
+ if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
+ (posix_grps->pg_ngrps != 0)) {
+ gid = posix_grps->pg_grps[0];
+ } else {
+ gid = token->tkn_primary_grp.i_id;
+ }
+
+ if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ smb_cred_set_sid(&token->tkn_user, &ksid);
+ crsetsid(cr, &ksid, KSID_USER);
+ smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
+ crsetsid(cr, &ksid, KSID_GROUP);
+ smb_cred_set_sid(&token->tkn_owner, &ksid);
+ crsetsid(cr, &ksid, KSID_OWNER);
+ ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
+ crsetsidlist(cr, ksidlist);
+
+ /*
+ * In the AD world, "take ownership privilege" is very much
+ * like having Unix "root" privileges. It's normally given
+ * to members of the "Administrators" group, which normally
+ * includes the the local Administrator (like root) and when
+ * joined to a domain, "Domain Admins".
+ */
+ if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
+ (void) crsetpriv(cr,
+ PRIV_FILE_CHOWN,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ PRIV_FILE_OWNER,
+ NULL);
+ }
+
+ return (cr);
+}
+
+/*
+ * Initialize the ksid based on the given smb_id_t.
+ */
+static void
+smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
+{
+ char sidstr[SMB_SID_STRSZ];
+ int rc;
+
+ ASSERT(id);
+ ASSERT(id->i_sid);
+
+ ksid->ks_id = id->i_id;
+ smb_sid_tostr(id->i_sid, sidstr);
+ rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
+ ASSERT(rc == 0);
+
+ ksid->ks_attr = id->i_attrs;
+ ksid->ks_domain = ksid_lookupdomain(sidstr);
+}
+
+/*
+ * Allocate and initialize the ksidlist based on the access token group list.
+ */
+static ksidlist_t *
+smb_cred_set_sidlist(smb_ids_t *token_grps)
+{
+ int i;
+ ksidlist_t *lp;
+
+ lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
+ lp->ksl_ref = 1;
+ lp->ksl_nsid = token_grps->i_cnt;
+ lp->ksl_neid = 0;
+
+ for (i = 0; i < lp->ksl_nsid; i++) {
+ smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
+ if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
+ lp->ksl_neid++;
+ }
+
+ return (lp);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
index 90619f8b4d..b2028603dc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -81,7 +81,7 @@ uint_t smb_audit_flags =
* Maximum number of simultaneous authentication, share mapping, pipe open
* requests to be processed.
*/
-int smb_ssetup_threshold = 256;
+int smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD;
int smb_tcon_threshold = 1024;
int smb_opipe_threshold = 1024;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
index a9b787f461..cf59d6eea2 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -21,6 +21,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -157,8 +159,10 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
uint32_t lval;
int unicode = 0;
int repc;
+ boolean_t repc_specified;
while ((c = *fmt++) != 0) {
+ repc_specified = B_FALSE;
repc = 1;
if ('0' <= c && c <= '9') {
@@ -167,9 +171,11 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
repc = repc * 10 + c - '0';
c = *fmt++;
} while ('0' <= c && c <= '9');
+ repc_specified = B_TRUE;
} else if (c == '#') {
repc = va_arg(ap, int);
c = *fmt++;
+ repc_specified = B_TRUE;
}
switch (c) {
@@ -296,7 +302,7 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
ascii_conversion:
ASSERT(sr != NULL);
cvalpp = va_arg(ap, uint8_t **);
- if (repc <= 1)
+ if (!repc_specified)
repc = 0;
if (mbc_marshal_get_ascii_string(sr,
mbc, cvalpp, repc) != 0)
@@ -307,7 +313,7 @@ ascii_conversion:
unicode_translation:
ASSERT(sr != 0);
cvalpp = va_arg(ap, uint8_t **);
- if (repc <= 1)
+ if (!repc_specified)
repc = 0;
if (mbc->chain_offset & 1)
mbc->chain_offset++;
@@ -508,12 +514,14 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
uint32_t lval;
uint_t tag;
int unicode = 0;
- int repc = 1;
+ int repc;
+ boolean_t repc_specified;
uint16_t wval;
uint8_t cval;
uint8_t c;
while ((c = *fmt++) != 0) {
+ repc_specified = B_FALSE;
repc = 1;
if ('0' <= c && c <= '9') {
@@ -522,9 +530,12 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
repc = repc * 10 + c - '0';
c = *fmt++;
} while ('0' <= c && c <= '9');
+ repc_specified = B_TRUE;
} else if (c == '#') {
repc = va_arg(ap, int);
c = *fmt++;
+ repc_specified = B_TRUE;
+
}
switch (c) {
@@ -647,6 +658,8 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
case 's': /* ASCII/multibyte string */
ascii_conversion: cvalp = va_arg(ap, uint8_t *);
+ if (!repc_specified)
+ repc = 0;
if (mbc_marshal_put_ascii_string(mbc,
(char *)cvalp, repc) != 0)
return (DECODE_NO_MORE_DATA);
@@ -696,6 +709,8 @@ unicode_translation:
if (mbc->chain_offset & 1)
mbc->chain_offset++;
cvalp = va_arg(ap, uint8_t *);
+ if (!repc_specified)
+ repc = 0;
if (mbc_marshal_put_unicode_string(mbc,
(char *)cvalp, repc) != 0)
return (DECODE_NO_MORE_DATA);
@@ -1040,7 +1055,7 @@ mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
length += sizeof (char);
- if ((repc > 1) && (repc < length))
+ if ((repc > 0) && (repc < length))
length = repc;
if (mbc_marshal_make_room(mbc, length))
return (DECODE_NO_MORE_DATA);
@@ -1077,7 +1092,7 @@ mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
length += sizeof (smb_wchar_t);
- if ((repc > 1) && (repc < length))
+ if ((repc > 0) && (repc < length))
length = repc;
if (mbc_marshal_make_room(mbc, length))
diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
index d774c07b48..08597f79ce 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
@@ -229,7 +229,31 @@ static uint32_t smb_nt_tcp_rcvbuf = 1048560; /* scale factor of 4 */
static int smb_xlate_dialect(const char *);
-int smb_cap_passthru = 1;
+/*
+ * "Capabilities" offered by SMB1 Negotiate Protocol.
+ * See smb.h for descriptions.
+ *
+ * CAP_RAW_MODE, CAP_MPX_MODE are obsolete.
+ * UNICODE support is required for long share names,
+ * long file names and streams.
+ *
+ * For testing, one can patch this, i.e. remove the high bit to
+ * temporarily disable extended security, etc.
+ */
+uint32_t smb1srv_capabilities =
+ CAP_UNICODE |
+ CAP_LARGE_FILES |
+ CAP_NT_SMBS |
+ CAP_RPC_REMOTE_APIS |
+ CAP_STATUS32 |
+ CAP_LEVEL_II_OPLOCKS |
+ CAP_LOCK_AND_READ |
+ CAP_NT_FIND |
+ CAP_DFS |
+ CAP_INFOLEVEL_PASSTHRU |
+ CAP_LARGE_READX |
+ CAP_LARGE_WRITEX |
+ CAP_EXTENDED_SECURITY;
smb_sdrc_t
smb_pre_negotiate(smb_request_t *sr)
@@ -296,8 +320,8 @@ smb_com_negotiate(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->session->secmode = NEGOTIATE_SECURITY_CHALLENGE_RESPONSE |
- NEGOTIATE_SECURITY_USER_LEVEL;
+ sr->session->secmode = NEGOTIATE_ENCRYPT_PASSWORDS |
+ NEGOTIATE_USER_SECURITY;
secmode = sr->session->secmode;
sesskey = sr->session->sesskey;
@@ -308,30 +332,7 @@ smb_com_negotiate(smb_request_t *sr)
bcopy(&sr->session->challenge_key, negprot->ni_key, SMB_CHALLENGE_SZ);
nbdomain = sr->sr_cfg->skc_nbdomain;
- /*
- * UNICODE support is required for long share names,
- * long file names and streams. Note: CAP_RAW_MODE
- * is not supported because it does nothing to help
- * modern clients and causes nasty complications.
- */
- negprot->ni_capabilities = CAP_LARGE_FILES
- | CAP_UNICODE
- | CAP_NT_SMBS
- | CAP_STATUS32
- | CAP_NT_FIND
- | CAP_LEVEL_II_OPLOCKS
- | CAP_LOCK_AND_READ
- | CAP_RPC_REMOTE_APIS
- | CAP_LARGE_READX
- | CAP_LARGE_WRITEX
- | CAP_DFS;
-
- if (smb_cap_passthru)
- negprot->ni_capabilities |= CAP_INFOLEVEL_PASSTHRU;
- else
- cmn_err(CE_NOTE, "smbsrv: cap passthru is %s",
- (negprot->ni_capabilities & CAP_INFOLEVEL_PASSTHRU) ?
- "enabled" : "disabled");
+ negprot->ni_capabilities = smb1srv_capabilities;
switch (negprot->ni_dialect) {
case PC_NETWORK_PROGRAM_1_0: /* core */
@@ -404,14 +405,9 @@ smb_com_negotiate(smb_request_t *sr)
sizeof (smb_nt_tcp_rcvbuf), CRED());
/*
- * Turn off Extended Security Negotiation
+ * Allow SMB signatures if using encrypted passwords
*/
- sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;
-
- /*
- * Allow SMB signatures if security challenge response enabled
- */
- if ((secmode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
+ if ((secmode & NEGOTIATE_ENCRYPT_PASSWORDS) &&
sr->sr_cfg->skc_signing_enable) {
secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
if (sr->sr_cfg->skc_signing_required)
@@ -422,6 +418,19 @@ smb_com_negotiate(smb_request_t *sr)
}
/*
+ * Does the client want Extended Security?
+ * (and if we have it enabled)
+ * If so, handle as if a different dialect.
+ */
+ if ((sr->smb_flg2 & SMB_FLAGS2_EXT_SEC) != 0 &&
+ (negprot->ni_capabilities & CAP_EXTENDED_SECURITY) != 0)
+ goto NT_LM_0_12_ext_sec;
+
+ /* Else deny knowledge of extended security. */
+ sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;
+ negprot->ni_capabilities &= ~CAP_EXTENDED_SECURITY;
+
+ /*
* nbdomain is not expected to be aligned.
* Use temporary buffer to avoid alignment padding
*/
@@ -457,6 +466,33 @@ smb_com_negotiate(smb_request_t *sr)
smb_msgbuf_term(&mb);
break;
+NT_LM_0_12_ext_sec:
+ /*
+ * This is the "Extended Security" variant of
+ * dialect NT_LM_0_12.
+ */
+ rc = smbsr_encode_result(sr, 17, VAR_BCC,
+ "bwbwwllllTwbw#c#c",
+ 17, /* wct */
+ negprot->ni_index, /* dialect index */
+ secmode, /* security mode */
+ negprot->ni_maxmpxcount, /* max MPX */
+ 1, /* max VCs */
+ (DWORD)smb_maxbufsize, /* max buffer size */
+ 0xFFFF, /* max raw size */
+ sesskey, /* session key */
+ negprot->ni_capabilities,
+ &negprot->ni_servertime, /* system time */
+ negprot->ni_tzcorrection,
+ 0, /* encryption key length (MBZ) */
+ VAR_BCC,
+ UUID_LEN,
+ sr->sr_cfg->skc_machine_uuid,
+ sr->sr_cfg->skc_negtok_len,
+ sr->sr_cfg->skc_negtok);
+ break;
+
+
default:
rc = smbsr_encode_result(sr, 1, 0, "bww", 1, -1, 0);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index 94eeb396dd..e4a305c7fa 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -1889,6 +1889,7 @@ smb_server_fclose(smb_llist_t *ll, uint32_t uniqid)
return (rc);
}
+/* See also: libsmb smb_kmod_setcfg */
static void
smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc)
{
@@ -1909,12 +1910,22 @@ smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc)
sv->sv_cfg.skc_oplock_enable = ioc->oplock_enable;
sv->sv_cfg.skc_sync_enable = ioc->sync_enable;
sv->sv_cfg.skc_secmode = ioc->secmode;
+ sv->sv_cfg.skc_netbios_enable = ioc->netbios_enable;
sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable;
sv->sv_cfg.skc_print_enable = ioc->print_enable;
sv->sv_cfg.skc_traverse_mounts = ioc->traverse_mounts;
- sv->sv_cfg.skc_netbios_enable = ioc->netbios_enable;
sv->sv_cfg.skc_execflags = ioc->exec_flags;
+ sv->sv_cfg.skc_negtok_len = ioc->negtok_len;
sv->sv_cfg.skc_version = ioc->version;
+ (void) memcpy(sv->sv_cfg.skc_machine_uuid, ioc->machine_uuid,
+ sizeof (uuid_t));
+ (void) memcpy(sv->sv_cfg.skc_negtok, ioc->negtok,
+ sizeof (sv->sv_cfg.skc_negtok));
+ (void) memcpy(sv->sv_cfg.skc_native_os, ioc->native_os,
+ sizeof (sv->sv_cfg.skc_native_os));
+ (void) memcpy(sv->sv_cfg.skc_native_lm, ioc->native_lm,
+ sizeof (sv->sv_cfg.skc_native_lm));
+
(void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain,
sizeof (sv->sv_cfg.skc_nbdomain));
(void) strlcpy(sv->sv_cfg.skc_fqdn, ioc->fqdn,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index d084a3f29b..fc130cb973 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -47,7 +47,6 @@ static void smb_session_cancel(smb_session_t *);
static int smb_session_message(smb_session_t *);
static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
uint8_t *, size_t);
-static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
static smb_tree_t *smb_session_get_tree(smb_session_t *, smb_tree_t *);
static void smb_session_logoff(smb_session_t *);
static void smb_request_init_command_mbuf(smb_request_t *sr);
@@ -706,11 +705,16 @@ smb_session_delete(smb_session_t *session)
ASSERT(session->s_magic == SMB_SESSION_MAGIC);
- session->s_magic = 0;
-
if (session->sign_fini != NULL)
session->sign_fini(session);
+ if (session->signing.mackey != NULL) {
+ kmem_free(session->signing.mackey,
+ session->signing.mackey_len);
+ }
+
+ session->s_magic = 0;
+
smb_rwx_destroy(&session->s_lock);
smb_net_txl_destructor(&session->s_txlst);
@@ -828,63 +832,18 @@ smb_session_worker(void *arg)
}
/*
- * smb_session_lookup_user
- */
-static smb_user_t *
-smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
-{
- smb_user_t *user;
- smb_llist_t *ulist;
-
- ulist = &session->s_user_list;
- smb_llist_enter(ulist, RW_READER);
- user = smb_llist_head(ulist);
- while (user) {
- ASSERT(user->u_magic == SMB_USER_MAGIC);
- if (!smb_strcasecmp(user->u_name, name, 0) &&
- !smb_strcasecmp(user->u_domain, domain, 0)) {
- if (smb_user_hold(user))
- break;
- }
- user = smb_llist_next(ulist, user);
- }
- smb_llist_exit(ulist);
-
- return (user);
-}
-
-/*
- * If a user attempts to log in subsequently from the specified session,
- * duplicates the existing SMB user instance such that all SMB user
- * instances that corresponds to the same user on the given session
- * reference the same user's cred.
- *
- * Returns NULL if the given user hasn't yet logged in from this
- * specified session. Otherwise, returns a user instance that corresponds
- * to this subsequent login.
+ * Find a user on the specified session by SMB UID.
*/
smb_user_t *
-smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
+smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
{
- smb_user_t *orig_user = NULL;
- smb_user_t *user = NULL;
-
- orig_user = smb_session_lookup_user(session, domain,
- account_name);
-
- if (orig_user) {
- user = smb_user_dup(orig_user);
- smb_user_release(orig_user);
- }
-
- return (user);
+ return (smb_session_lookup_uid_st(session, uid,
+ SMB_USER_STATE_LOGGED_ON));
}
-/*
- * Find a user on the specified session by SMB UID.
- */
smb_user_t *
-smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
+smb_session_lookup_uid_st(smb_session_t *session, uint16_t uid,
+ smb_user_state_t st)
{
smb_user_t *user;
smb_llist_t *user_list;
@@ -899,19 +858,16 @@ smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
SMB_USER_VALID(user);
ASSERT(user->u_session == session);
- if (user->u_uid == uid) {
- if (!smb_user_hold(user))
- break;
-
- smb_llist_exit(user_list);
- return (user);
+ if (user->u_uid == uid && user->u_state == st) {
+ smb_user_hold_internal(user);
+ break;
}
user = smb_llist_next(user_list, user);
}
smb_llist_exit(user_list);
- return (NULL);
+ return (user);
}
void
@@ -1233,9 +1189,21 @@ smb_session_logoff(smb_session_t *session)
SMB_USER_VALID(user);
ASSERT(user->u_session == session);
- if (smb_user_hold(user)) {
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGING_ON:
+ case SMB_USER_STATE_LOGGED_ON:
+ smb_user_hold_internal(user);
smb_user_logoff(user);
smb_user_release(user);
+ break;
+
+ case SMB_USER_STATE_LOGGED_OFF:
+ case SMB_USER_STATE_LOGGING_OFF:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
}
user = smb_llist_next(&session->s_user_list, user);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
index 7eabad7513..5f98a16293 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -32,95 +32,54 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_token.h>
-static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *);
-static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *);
-static uint32_t smb_priv_xlate(smb_token_t *);
-#ifdef _KERNEL
-static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
-static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
-#endif /* _KERNEL */
-
-/*
- * In NTLM 0.12, the padding between the Native OS and Native LM is a bit
- * strange. On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381)
- * and LM (Windows NT 4.0). On Windows 2000, there is no padding between
- * the OS (Windows 2000 2195) and LM (Windows 2000 5.0).
- * If the padding is removed from the decode string the NT4.0 LM comes out
- * as an empty string. So if the client's native OS is Win NT we consider
- * the padding otherwise we don't.
- *
- * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are
- * not always present in the message. We try to get the account name and
- * the primary domain but we don't care about the the native OS or native
- * LM fields.
- *
- * If the Native LM cannot be determined, default to Windows NT.
- */
smb_sdrc_t
smb_pre_session_setup_andx(smb_request_t *sr)
{
smb_arg_sessionsetup_t *sinfo;
char *native_os;
char *native_lm;
- uint32_t junk_sesskey;
- uint16_t maxbufsize;
- uint16_t vcnumber;
int rc = 0;
sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
sr->sr_ssetup = sinfo;
- if (sr->session->dialect >= NT_LM_0_12) {
- rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
- &sr->andx_off, &maxbufsize,
- &sinfo->ssi_maxmpxcount, &vcnumber,
- &junk_sesskey, &sinfo->ssi_cipwlen,
- &sinfo->ssi_cspwlen, &sinfo->ssi_capabilities);
- if (rc != 0)
- goto pre_session_setup_andx_done;
-
- sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
- sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1);
-
- rc = smbsr_decode_data(sr, "%#c#cuuu",
- sr,
- sinfo->ssi_cipwlen, sinfo->ssi_cipwd,
- sinfo->ssi_cspwlen, sinfo->ssi_cspwd,
- &sinfo->ssi_user,
- &sinfo->ssi_domain,
- &native_os);
- if (rc != 0)
- goto pre_session_setup_andx_done;
-
- sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
- sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0;
+ /*
+ * Enforce the minimum word count seen in the old protocol,
+ * to make sure we have enough to decode the common stuff.
+ * Further wcnt checks below.
+ */
+ if (sr->smb_wct < 10) {
+ rc = -1;
+ goto done;
+ }
- sr->session->native_os = smbnative_os_value(native_os);
+ /*
+ * Parse common part of SMB session setup.
+ * skip: vcnumber(2), sesskey(4)
+ */
+ rc = smbsr_decode_vwv(sr, "b.www6.",
+ &sr->andx_com, &sr->andx_off,
+ &sinfo->ssi_maxbufsize, &sinfo->ssi_maxmpxcount);
+ if (rc != 0)
+ goto done;
- if (sr->session->native_os == NATIVE_OS_WINNT)
- rc = smbsr_decode_data(sr, "%,u", sr, &native_lm);
- else
- rc = smbsr_decode_data(sr, "%u", sr, &native_lm);
+ if (sr->session->dialect < NT_LM_0_12) {
- if (rc != 0 || native_lm == NULL)
- native_lm = "NT LAN Manager 4.0";
+ sinfo->ssi_type = SMB_SSNSETUP_PRE_NTLM012;
+ sinfo->ssi_capabilities = 0;
- sr->session->native_lm = smbnative_lm_value(native_lm);
- } else {
- rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
- &sr->andx_off, &maxbufsize,
- &sinfo->ssi_maxmpxcount, &vcnumber,
- &junk_sesskey, &sinfo->ssi_cipwlen);
+ rc = smbsr_decode_vwv(sr, "w4.",
+ &sinfo->ssi_lmpwlen);
if (rc != 0)
- goto pre_session_setup_andx_done;
+ goto done;
- sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
- rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_cipwlen,
- sinfo->ssi_cipwd);
+ sinfo->ssi_lmpwd = smb_srm_zalloc(sr, sinfo->ssi_lmpwlen + 1);
+ rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_lmpwlen,
+ sinfo->ssi_lmpwd);
if (rc != 0)
- goto pre_session_setup_andx_done;
+ goto done;
- sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
+ sinfo->ssi_lmpwd[sinfo->ssi_lmpwlen] = 0;
if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0)
sinfo->ssi_user = "";
@@ -128,15 +87,108 @@ smb_pre_session_setup_andx(smb_request_t *sr)
if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0)
sinfo->ssi_domain = "";
- native_lm = "NT LAN Manager 4.0";
- sr->session->native_os = NATIVE_OS_WINNT;
- sr->session->native_lm = smbnative_lm_value(native_lm);
+ goto part2;
+ }
+
+ /*
+ * We have dialect >= NT_LM_0_12
+ */
+ if (sr->smb_wct == 13) {
+ /* Old style (non-extended) request. */
+ sinfo->ssi_type = SMB_SSNSETUP_NTLM012_NOEXT;
+
+ rc = smbsr_decode_vwv(sr, "ww4.l",
+ &sinfo->ssi_lmpwlen,
+ &sinfo->ssi_ntpwlen,
+ &sinfo->ssi_capabilities);
+ if (rc != 0)
+ goto done;
+
+ /* paranoid: ignore cap. ext. sec. here */
+ sinfo->ssi_capabilities &= ~CAP_EXTENDED_SECURITY;
+
+ sinfo->ssi_lmpwd = smb_srm_zalloc(sr, sinfo->ssi_lmpwlen + 1);
+ sinfo->ssi_ntpwd = smb_srm_zalloc(sr, sinfo->ssi_ntpwlen + 1);
+
+ rc = smbsr_decode_data(sr, "%#c#cuu", sr,
+ sinfo->ssi_lmpwlen, sinfo->ssi_lmpwd,
+ sinfo->ssi_ntpwlen, sinfo->ssi_ntpwd,
+ &sinfo->ssi_user, &sinfo->ssi_domain);
+ if (rc != 0)
+ goto done;
+
+ sinfo->ssi_lmpwd[sinfo->ssi_lmpwlen] = 0;
+ sinfo->ssi_ntpwd[sinfo->ssi_ntpwlen] = 0;
+
+ goto part2;
+ }
+
+ if (sr->smb_wct == 12) {
+ /* New style (extended) request. */
+ sinfo->ssi_type = SMB_SSNSETUP_NTLM012_EXTSEC;
+
+ rc = smbsr_decode_vwv(sr, "w4.l",
+ &sinfo->ssi_iseclen,
+ &sinfo->ssi_capabilities);
+ if (rc != 0)
+ goto done;
+
+ if ((sinfo->ssi_capabilities & CAP_EXTENDED_SECURITY) == 0) {
+ rc = -1;
+ goto done;
+ }
+
+ sinfo->ssi_isecblob = smb_srm_zalloc(sr, sinfo->ssi_iseclen);
+ rc = smbsr_decode_data(sr, "%#c", sr,
+ sinfo->ssi_iseclen, sinfo->ssi_isecblob);
+ if (rc != 0)
+ goto done;
+
+ goto part2;
}
- sr->session->vcnumber = vcnumber;
- sr->session->smb_msg_size = maxbufsize;
+ /* Invalid message */
+ rc = -1;
+ goto done;
+
+part2:
+ /*
+ * Get the "Native OS" and "Native LanMan" strings.
+ * These are not critical to protocol function, so
+ * if we can't parse them, just guess "NT".
+ * These strings are free'd with the sr.
+ *
+ * In NTLM 0.12, the padding between the Native OS and Native LM
+ * is a bit strange. On NT4.0, there is a 2 byte pad between the
+ * OS (Windows NT 1381) and LM (Windows NT 4.0). On Windows 2000,
+ * there is no padding between the OS (Windows 2000 2195) and LM
+ * (Windows 2000 5.0). If the padding is removed from the decode
+ * string the NT4.0 LM comes out as an empty string. So if the
+ * client's native OS is Win NT, assume extra padding.
+ */
+ rc = smbsr_decode_data(sr, "%u", sr, &native_os);
+ if (rc != 0 || native_os == NULL)
+ sinfo->ssi_native_os = NATIVE_OS_WINNT;
+ else
+ sinfo->ssi_native_os = smbnative_os_value(native_os);
+
+ if (sinfo->ssi_native_os == NATIVE_OS_WINNT)
+ rc = smbsr_decode_data(sr, "%,u", sr, &native_lm);
+ else
+ rc = smbsr_decode_data(sr, "%u", sr, &native_lm);
+ if (rc != 0 || native_lm == NULL)
+ sinfo->ssi_native_lm = NATIVE_LM_NT;
+ else
+ sinfo->ssi_native_lm = smbnative_lm_value(native_lm);
+ rc = 0;
+
+done:
+ if (rc != 0) {
+ cmn_err(CE_NOTE,
+ "SmbSessonSetupX: client %s invalid request",
+ sr->session->ip_addr_str);
+ }
-pre_session_setup_andx_done:
DTRACE_SMB_2(op__SessionSetupX__start, smb_request_t *, sr,
smb_arg_sessionsetup_t, sinfo);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
@@ -150,18 +202,14 @@ smb_post_session_setup_andx(smb_request_t *sr)
DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr,
smb_arg_sessionsetup_t, sinfo);
- if (sinfo->ssi_cipwd != NULL)
- bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1);
+ if (sinfo->ssi_lmpwd != NULL)
+ bzero(sinfo->ssi_lmpwd, sinfo->ssi_lmpwlen);
- if (sinfo->ssi_cspwd != NULL)
- bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1);
+ if (sinfo->ssi_ntpwd != NULL)
+ bzero(sinfo->ssi_ntpwd, sinfo->ssi_ntpwlen);
}
/*
- * If signing has not already been enabled on this session check to see if
- * it should be enabled. The first authenticated logon provides the MAC
- * key and sequence numbers for signing all subsequent sessions on the same
- * connection.
*
* NT systems use different native OS and native LanMan values dependent on
* whether they are acting as a client or a server. NT 4.0 server responds
@@ -174,329 +222,117 @@ smb_sdrc_t
smb_com_session_setup_andx(smb_request_t *sr)
{
smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
+ uint32_t status;
+ uint16_t action;
int rc;
- if (smb_authenticate(sr, sinfo) != 0)
- return (SDRC_ERROR);
-
- if (sr->session->native_lm == NATIVE_LM_WIN2000)
- sinfo->ssi_capabilities |= CAP_LARGE_FILES |
- CAP_LARGE_READX | CAP_LARGE_WRITEX;
-
- if (!smb_oplock_levelII)
- sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
-
- sr->session->capabilities = sinfo->ssi_capabilities;
-
- rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
- 3,
- sr->andx_com,
- -1, /* andx_off */
- sinfo->ssi_guest ? 1 : 0,
- VAR_BCC,
- sr,
- smbnative_os_str(&sr->sr_cfg->skc_version),
- smbnative_lm_str(&sr->sr_cfg->skc_version),
- sr->sr_cfg->skc_nbdomain);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-static int
-smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo)
-{
- int rc;
- smb_server_t *sv = sr->sr_server;
-
- if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) {
- smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
- return (-1);
- }
-
- rc = smb_authenticate_core(sr, sinfo);
- smb_threshold_exit(&sv->sv_ssetup_ct);
- return (rc);
-}
-
-/*
- * Authenticate a user. If the user has already been authenticated on
- * this session, we can simply dup the user and return.
- *
- * Otherwise, the user information is passed to smbd for authentication.
- * If smbd can authenticate the user an access token is returned and we
- * generate a cred and new user based on the token.
- */
-static int
-smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo)
-{
- char *hostname = sr->sr_cfg->skc_hostname;
- int security = sr->sr_cfg->skc_secmode;
- smb_token_t *token = NULL;
- smb_user_t *user = NULL;
- smb_logon_t user_info;
- boolean_t need_lookup = B_FALSE;
- uint32_t privileges;
- cred_t *cr;
- char *buf = NULL;
- char *p;
-
- bzero(&user_info, sizeof (smb_logon_t));
- user_info.lg_e_domain = sinfo->ssi_domain;
-
- if ((*sinfo->ssi_user == '\0') &&
- (sinfo->ssi_cspwlen == 0) &&
- (sinfo->ssi_cipwlen == 0 ||
- (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) {
- user_info.lg_e_username = "anonymous";
- user_info.lg_flags |= SMB_ATF_ANON;
- } else {
- user_info.lg_e_username = sinfo->ssi_user;
- }
-
/*
- * Handle user@domain format. We need to retain the original
- * data as this is important in some forms of authentication.
+ * Some stuff we do only in the first in a (possible)
+ * sequence of session setup requests.
*/
- if (*sinfo->ssi_domain == '\0') {
- buf = smb_srm_strdup(sr, sinfo->ssi_user);
- if ((p = strchr(buf, '@')) != NULL) {
- *p = '\0';
- user_info.lg_e_username = buf;
- user_info.lg_e_domain = p + 1;
- }
- }
+ if (sinfo->ssi_type != SMB_SSNSETUP_NTLM012_EXTSEC ||
+ sr->smb_uid == 0 || sr->smb_uid == 0xFFFF) {
- /*
- * If no domain name has been provided in domain mode we cannot
- * determine if this is a local user or a domain user without
- * obtaining an access token. So we postpone the lookup until
- * after authentication.
- */
- if (security == SMB_SECMODE_WORKGRP) {
- user = smb_session_dup_user(sr->session, hostname,
- user_info.lg_e_username);
- } else if (*user_info.lg_e_domain != '\0') {
- user = smb_session_dup_user(sr->session, user_info.lg_e_domain,
- user_info.lg_e_username);
- } else {
- need_lookup = B_TRUE;
- }
+ /* This is a first (or only) call */
+ sr->session->smb_msg_size = sinfo->ssi_maxbufsize;
+ sr->session->smb_max_mpx = sinfo->ssi_maxmpxcount;
+ sr->session->capabilities = sinfo->ssi_capabilities;
- if (user != NULL) {
- sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
- sr->user_cr = user->u_cred;
- sr->smb_uid = user->u_uid;
- sr->uid_user = user;
- return (0);
- }
-
- user_info.lg_level = NETR_NETWORK_LOGON;
- user_info.lg_domain = sinfo->ssi_domain;
- user_info.lg_username = sinfo->ssi_user;
- user_info.lg_workstation = sr->session->workstation;
- user_info.lg_clnt_ipaddr = sr->session->ipaddr;
- user_info.lg_local_ipaddr = sr->session->local_ipaddr;
- user_info.lg_local_port = sr->session->s_local_port;
- user_info.lg_challenge_key.val = sr->session->challenge_key;
- user_info.lg_challenge_key.len = sr->session->challenge_len;
- user_info.lg_nt_password.val = sinfo->ssi_cspwd;
- user_info.lg_nt_password.len = sinfo->ssi_cspwlen;
- user_info.lg_lm_password.val = sinfo->ssi_cipwd;
- user_info.lg_lm_password.len = sinfo->ssi_cipwlen;
- user_info.lg_native_os = sr->session->native_os;
- user_info.lg_native_lm = sr->session->native_lm;
-
- DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info);
-
- if ((token = smb_get_token(sr->session, &user_info)) == NULL) {
- smbsr_error(sr, 0, ERRSRV, ERRbadpw);
- return (-1);
- }
+ if (!smb_oplock_levelII)
+ sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
- if (need_lookup) {
- user = smb_session_dup_user(sr->session,
- token->tkn_domain_name, token->tkn_account_name);
- if (user != NULL) {
- sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
- sr->user_cr = user->u_cred;
- sr->smb_uid = user->u_uid;
- sr->uid_user = user;
- smb_token_free(token);
- return (0);
- }
+ sr->session->native_os = sinfo->ssi_native_os;
+ sr->session->native_lm = sinfo->ssi_native_lm;
}
- if ((cr = smb_cred_create(token)) == NULL) {
- smb_token_free(token);
- smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
- return (-1);
- }
-
- privileges = smb_priv_xlate(token);
-
- user = smb_user_login(sr->session, cr,
- token->tkn_domain_name, token->tkn_account_name,
- token->tkn_flags, privileges, token->tkn_audit_sid);
- crfree(cr);
-
/*
- * Save the session key, and (maybe) enable signing,
- * but only for real logon (not ANON or GUEST).
+ * The "meat" of authentication happens here.
*/
- if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0)
- (void) smb_sign_begin(sr, token);
-
- smb_token_free(token);
-
- if (user == NULL) {
- smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
- return (-1);
- }
-
- sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
- sr->user_cr = user->u_cred;
- sr->smb_uid = user->u_uid;
- sr->uid_user = user;
- return (0);
-}
-
-#ifdef _KERNEL
-/*
- * Allocate a Solaris cred and initialize it based on the access token.
- *
- * If the user can be mapped to a non-ephemeral ID, the cred gid is set
- * to the Solaris user's primary group.
- *
- * If the mapped UID is ephemeral, or the primary group could not be
- * obtained, the cred gid is set to whatever Solaris group is mapped
- * to the token's primary group.
- */
-cred_t *
-smb_cred_create(smb_token_t *token)
-{
- ksid_t ksid;
- ksidlist_t *ksidlist = NULL;
- smb_posix_grps_t *posix_grps;
- cred_t *cr;
- gid_t gid;
-
- ASSERT(token);
- ASSERT(token->tkn_posix_grps);
- posix_grps = token->tkn_posix_grps;
-
- cr = crget();
- ASSERT(cr != NULL);
-
- if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
- (posix_grps->pg_ngrps != 0)) {
- gid = posix_grps->pg_grps[0];
- } else {
- gid = token->tkn_primary_grp.i_id;
- }
-
- if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
- crfree(cr);
- return (NULL);
- }
+ if (sinfo->ssi_type == SMB_SSNSETUP_NTLM012_EXTSEC)
+ status = smb_authenticate_ext(sr);
+ else
+ status = smb_authenticate_old(sr);
- if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
- crfree(cr);
- return (NULL);
- }
+ switch (status) {
- smb_cred_set_sid(&token->tkn_user, &ksid);
- crsetsid(cr, &ksid, KSID_USER);
- smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
- crsetsid(cr, &ksid, KSID_GROUP);
- smb_cred_set_sid(&token->tkn_owner, &ksid);
- crsetsid(cr, &ksid, KSID_OWNER);
- ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
- crsetsidlist(cr, ksidlist);
+ case NT_STATUS_SUCCESS:
+ break;
/*
- * In the AD world, "take ownership privilege" is very much
- * like having Unix "root" privileges. It's normally given
- * to members of the "Administrators" group, which normally
- * includes the the local Administrator (like root) and when
- * joined to a domain, "Domain Admins".
+ * This is not really an error, but tells the client
+ * it should send another session setup request.
*/
- if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
- (void) crsetpriv(cr,
- PRIV_FILE_CHOWN,
- PRIV_FILE_DAC_READ,
- PRIV_FILE_DAC_SEARCH,
- PRIV_FILE_DAC_WRITE,
- PRIV_FILE_OWNER,
- NULL);
- }
-
- return (cr);
-}
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ smbsr_error(sr, status, 0, 0);
+ break;
-/*
- * Initialize the ksid based on the given smb_id_t.
- */
-static void
-smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
-{
- char sidstr[SMB_SID_STRSZ];
- int rc;
+ case NT_STATUS_ACCESS_DENIED:
+ smbsr_error(sr, status, ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
- ASSERT(id);
- ASSERT(id->i_sid);
+ case NT_STATUS_TOO_MANY_SESSIONS:
+ smbsr_error(sr, status, ERRSRV, ERRtoomanyuids);
+ return (SDRC_ERROR);
- ksid->ks_id = id->i_id;
- smb_sid_tostr(id->i_sid, sidstr);
- rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
- ASSERT(rc == 0);
+ case NT_STATUS_NO_LOGON_SERVERS:
+ smbsr_error(sr, status, ERRDOS, ERROR_NO_LOGON_SERVERS);
+ return (SDRC_ERROR);
- ksid->ks_attr = id->i_attrs;
- ksid->ks_domain = ksid_lookupdomain(sidstr);
-}
+ case NT_STATUS_NETLOGON_NOT_STARTED:
+ smbsr_error(sr, status, ERRDOS, ERROR_NETLOGON_NOT_STARTED);
+ return (SDRC_ERROR);
-/*
- * Allocate and initialize the ksidlist based on the access token group list.
- */
-static ksidlist_t *
-smb_cred_set_sidlist(smb_ids_t *token_grps)
-{
- int i;
- ksidlist_t *lp;
-
- lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
- lp->ksl_ref = 1;
- lp->ksl_nsid = token_grps->i_cnt;
- lp->ksl_neid = 0;
-
- for (i = 0; i < lp->ksl_nsid; i++) {
- smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
- if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
- lp->ksl_neid++;
- }
+ case NT_STATUS_USER_SESSION_DELETED:
+ smbsr_error(sr, status, ERRSRV, ERRbaduid);
+ return (SDRC_ERROR);
- return (lp);
-}
-#endif /* _KERNEL */
+ case NT_STATUS_INSUFF_SERVER_RESOURCES:
+ smbsr_error(sr, status, ERRSRV, ERRnoresource);
+ return (SDRC_ERROR);
-/*
- * Convert access token privileges to local definitions.
- */
-static uint32_t
-smb_priv_xlate(smb_token_t *token)
-{
- uint32_t privileges = 0;
+ case NT_STATUS_INTERNAL_ERROR:
+ default:
+ smbsr_error(sr, status, ERRSRV, ERRsrverror);
+ return (SDRC_ERROR);
+ }
- if (smb_token_query_privilege(token, SE_BACKUP_LUID))
- privileges |= SMB_USER_PRIV_BACKUP;
+ action = SMB_USER_IS_GUEST(sr->uid_user) ? 1 : 0;
- if (smb_token_query_privilege(token, SE_RESTORE_LUID))
- privileges |= SMB_USER_PRIV_RESTORE;
+ switch (sinfo->ssi_type) {
- if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
- privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
+ default:
+ case SMB_SSNSETUP_PRE_NTLM012:
+ case SMB_SSNSETUP_NTLM012_NOEXT:
- if (smb_token_query_privilege(token, SE_SECURITY_LUID))
- privileges |= SMB_USER_PRIV_SECURITY;
+ rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
+ 3,
+ sr->andx_com,
+ -1, /* andx_off */
+ action,
+ VAR_BCC,
+ sr,
+ sr->sr_cfg->skc_native_os,
+ sr->sr_cfg->skc_native_lm,
+ sr->sr_cfg->skc_nbdomain);
+ break;
+
+ case SMB_SSNSETUP_NTLM012_EXTSEC:
+
+ rc = smbsr_encode_result(sr, 4, VAR_BCC, "bb.wwww%#cuuu",
+ 4,
+ sr->andx_com,
+ -1, /* andx_off */
+ action,
+ sinfo->ssi_oseclen,
+ VAR_BCC,
+ sr,
+ sinfo->ssi_oseclen,
+ sinfo->ssi_osecblob,
+ sr->sr_cfg->skc_native_os,
+ sr->sr_cfg->skc_native_lm,
+ sr->sr_cfg->skc_nbdomain);
+ break;
+ }
- return (privileges);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_signing.c b/usr/src/uts/common/fs/smbsrv/smb_signing.c
index c1cd826e32..c6f0212d31 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_signing.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_signing.c
@@ -44,7 +44,6 @@
#include <sys/isa_defs.h>
#include <sys/byteorder.h>
-#define SSN_KEY_LEN 16
#define SMB_SIG_SIZE 8
#define SMB_SIG_OFFS 14
#define SMB_HDRLEN 32
@@ -55,40 +54,47 @@
#define htolel(x) BSWAP_32(x)
#endif
-int
-smb_sign_calc(struct mbuf_chain *mbc,
- struct smb_sign *sign,
- uint32_t seqnum,
- unsigned char *mac_sign);
+static int
+smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
+ uint32_t seqnum, unsigned char *sig);
#ifdef DEBUG
-static void
+uint32_t smb_sign_debug_search = 10;
+
+/*
+ * Debug code to search +/- for the correct sequence number.
+ * If found, correct sign->seqnum and return 0, else return -1
+ */
+static int
smb_sign_find_seqnum(
- uint32_t seqnum,
- struct smb_sign *sign,
- struct mbuf_chain *command,
+ smb_request_t *sr,
+ struct mbuf_chain *mbc,
unsigned char *mac_sig,
- unsigned char *sr_sig,
- boolean_t *found)
+ unsigned char *sr_sig)
{
-int start_seqnum;
-int i;
-
- /* Debug code to hunt for the sequence number */
- *found = B_FALSE;
- start_seqnum = seqnum - 10;
- if (start_seqnum < 0)
- start_seqnum = 0;
- for (i = start_seqnum; i <= start_seqnum + 20; i++) {
- (void) smb_sign_calc(command, sign, i, mac_sig);
+ struct smb_sign *sign = &sr->session->signing;
+ uint32_t i, t;
+
+ for (i = 1; i < smb_sign_debug_search; i++) {
+ t = sr->sr_seqnum + i;
+ (void) smb_sign_calc(sr, mbc, t, mac_sig);
+ if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
+ goto found;
+ }
+ t = sr->sr_seqnum - i;
+ (void) smb_sign_calc(sr, mbc, t, mac_sig);
if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
- sign->seqnum = i;
- *found = B_TRUE;
- break;
+ goto found;
}
- cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum:%d mismatch", i);
}
- cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found);
+ cmn_err(CE_WARN, "smb_sign_find_seqnum: failed after %d", i);
+ return (-1);
+
+found:
+ cmn_err(CE_WARN, "smb_sign_find_seqnum: found! %d <- %d",
+ sign->seqnum, t);
+ sign->seqnum = t;
+ return (0);
}
#endif
@@ -100,9 +106,9 @@ smb_sign_fini(smb_session_t *s)
{
smb_sign_mech_t *mech;
- if ((mech = s->signing.mech) != NULL) {
+ if ((mech = s->sign_mech) != NULL) {
kmem_free(mech, sizeof (*mech));
- s->signing.mech = NULL;
+ s->sign_mech = NULL;
}
}
@@ -123,6 +129,15 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token)
int rc;
/*
+ * We should normally have a session key here because
+ * our caller filters out Anonymous and Guest logons.
+ * However, buggy clients could get us here without a
+ * session key, in which case: just don't sign.
+ */
+ if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
+ return (0);
+
+ /*
* Session-level initialization (once per session)
*/
smb_rwx_rwenter(&session->s_lock, RW_WRITER);
@@ -139,7 +154,7 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token)
/*
* Get the mech handle
*/
- if (sign->mech == NULL) {
+ if (session->sign_mech == NULL) {
mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
rc = smb_md5_getmech(mech);
if (rc != 0) {
@@ -147,7 +162,7 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token)
smb_rwx_rwexit(&session->s_lock);
return (rc);
}
- sign->mech = mech;
+ session->sign_mech = mech;
session->sign_fini = smb_sign_fini;
}
@@ -155,17 +170,16 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token)
* Compute and store the signing (MAC) key.
*
* With extended security, the MAC key is the same as the
- * session key (and we'll have sinfo->ssi_cspwlen == 0).
+ * session key (and we'll have sinfo->ssi_ntpwlen == 0).
* With non-extended security, it's the concatenation of
* the session key and the "NT response" we received.
- * (NB: no extended security yet)
*/
- sign->mackey_len = SSN_KEY_LEN + sinfo->ssi_cspwlen;
+ sign->mackey_len = token->tkn_ssnkey.len + sinfo->ssi_ntpwlen;
sign->mackey = kmem_alloc(sign->mackey_len, KM_SLEEP);
- bcopy(token->tkn_session_key, sign->mackey, SSN_KEY_LEN);
- if (sinfo->ssi_cspwlen > 0) {
- bcopy(sinfo->ssi_cspwd, sign->mackey + SSN_KEY_LEN,
- sinfo->ssi_cspwlen);
+ bcopy(token->tkn_ssnkey.val, sign->mackey, token->tkn_ssnkey.len);
+ if (sinfo->ssi_ntpwlen > 0) {
+ bcopy(sinfo->ssi_ntpwd, sign->mackey + token->tkn_ssnkey.len,
+ sinfo->ssi_ntpwlen);
}
session->signing.seqnum = 0;
@@ -207,12 +221,12 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token)
* Return 0 if success
*
*/
-int
-smb_sign_calc(struct mbuf_chain *mbc,
- struct smb_sign *sign,
- uint32_t seqnum,
- unsigned char *mac_sign)
+static int
+smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
+ uint32_t seqnum, unsigned char *mac_sign)
{
+ smb_session_t *s = sr->session;
+ struct smb_sign *sign = &s->signing;
smb_sign_ctx_t ctx = 0;
uchar_t digest[MD5_DIGEST_LENGTH];
uchar_t *hdrp;
@@ -241,10 +255,10 @@ smb_sign_calc(struct mbuf_chain *mbc,
} s;
} smbhdr;
- if (sign->mech == NULL || sign->mackey == NULL)
+ if (s->sign_mech == NULL || sign->mackey == NULL)
return (-1);
- if ((rc = smb_md5_init(&ctx, sign->mech)) != 0)
+ if ((rc = smb_md5_init(&ctx, s->sign_mech)) != 0)
return (rc);
/* Digest the MAC Key */
@@ -313,11 +327,8 @@ smb_sign_calc(struct mbuf_chain *mbc,
int
smb_sign_check_request(smb_request_t *sr)
{
- struct mbuf_chain command = sr->command;
+ struct mbuf_chain mbc = sr->command;
unsigned char mac_sig[SMB_SIG_SIZE];
- struct smb_sign *sign = &sr->session->signing;
- int rtn = 0;
- boolean_t found = B_TRUE;
/*
* Don't check secondary transactions - we dont know the sequence
@@ -329,32 +340,31 @@ smb_sign_check_request(smb_request_t *sr)
return (0);
/* Reset the offset to begining of header */
- command.chain_offset = sr->orig_request_hdr;
+ mbc.chain_offset = sr->orig_request_hdr;
/* calculate mac signature */
- if (smb_sign_calc(&command, sign, sr->sr_seqnum, mac_sig) != 0)
+ if (smb_sign_calc(sr, &mbc, sr->sr_seqnum, mac_sig) != 0)
return (-1);
/* compare the signatures */
- if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
- DTRACE_PROBE2(smb__signing__req, smb_request_t, sr,
- smb_sign_t *, sr->smb_sig);
- cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
- /*
- * check nearby sequence numbers in debug mode
- */
-#ifdef DEBUG
- if (smb_sign_debug)
- smb_sign_find_seqnum(sr->sr_seqnum, sign,
- &command, mac_sig, sr->smb_sig, &found);
- else
-#endif
- found = B_FALSE;
+ if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) == 0) {
+ /* They match! OK, we're done. */
+ return (0);
+ }
+
+ DTRACE_PROBE2(smb__signature__mismatch, smb_request_t, sr,
+ unsigned char *, mac_sig);
+ cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
- if (found == B_FALSE)
- rtn = -1;
+ /*
+ * check nearby sequence numbers in debug mode
+ */
+#ifdef DEBUG
+ if (smb_sign_debug) {
+ return (smb_sign_find_seqnum(sr, &mbc, mac_sig, sr->smb_sig));
}
- return (rtn);
+#endif
+ return (-1);
}
/*
@@ -368,17 +378,15 @@ smb_sign_check_request(smb_request_t *sr)
int
smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
{
- struct mbuf_chain command = sr->command;
+ struct mbuf_chain mbc = sr->command;
unsigned char mac_sig[SMB_SIG_SIZE];
- struct smb_sign *sign = &sr->session->signing;
int rtn = 0;
/* Reset the offset to begining of header */
- command.chain_offset = sr->orig_request_hdr;
+ mbc.chain_offset = sr->orig_request_hdr;
/* calculate mac signature */
- if (smb_sign_calc(&command, sign, reply_seqnum - 1,
- mac_sig) != 0)
+ if (smb_sign_calc(sr, &mbc, reply_seqnum - 1, mac_sig) != 0)
return (-1);
@@ -403,22 +411,21 @@ smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
void
smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
{
- struct mbuf_chain resp;
- struct smb_sign *sign = &sr->session->signing;
- unsigned char signature[SMB_SIG_SIZE];
+ struct mbuf_chain mbc;
+ unsigned char mac[SMB_SIG_SIZE];
if (reply)
- resp = *reply;
+ mbc = *reply;
else
- resp = sr->reply;
+ mbc = sr->reply;
/* Reset offset to start of reply */
- resp.chain_offset = 0;
+ mbc.chain_offset = 0;
/*
* Calculate MAC signature
*/
- if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) {
+ if (smb_sign_calc(sr, &mbc, sr->reply_seqnum, mac) != 0) {
cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc");
return;
}
@@ -426,6 +433,6 @@ smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
/*
* Put signature in the response
*/
- (void) smb_mbc_poke(&resp, SMB_SIG_OFFS, "#c",
- SMB_SIG_SIZE, signature);
+ (void) smb_mbc_poke(&mbc, SMB_SIG_OFFS, "#c",
+ SMB_SIG_SIZE, mac);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
index 017e3771ed..7f43d188c9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -68,40 +68,59 @@
* User State Machine
* ------------------
*
- * +-----------------------------+ T0
- * | SMB_USER_STATE_LOGGED_IN |<----------- Creation/Allocation
+ *
+ * | T0: Creation/Allocation
+ * | (1st session setup)
+ * v
+ * +-----------------------------+
+ * | SMB_USER_STATE_LOGGING_ON |<----------+
+ * +-----------------------------+ addl. session setup
+ * | | (more proc. required)
+ * | T2 | ^
+ * | | | T1: (cont.)
+ * | +------->-------?
+ * v | T3: (fail)
+ * +-----------------------------+ v
+ * | SMB_USER_STATE_LOGGED_ON | (logged off)
* +-----------------------------+
* |
- * | T1
+ * | T4
* |
* v
* +-----------------------------+
* | SMB_USER_STATE_LOGGING_OFF |
* +-----------------------------+
* |
- * | T2
+ * | T5
* |
* v
- * +-----------------------------+ T3
+ * +-----------------------------+ T6
* | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free
* +-----------------------------+
*
- * SMB_USER_STATE_LOGGED_IN
+ * SMB_USER_STATE_LOGGING_ON
*
* While in this state:
- * - The user is queued in the list of users of his session.
+ * - The user is in the list of users for his session.
+ * - References will be given out ONLY for session setup.
+ * - This user can not access anything yet.
+ *
+ * SMB_USER_STATE_LOGGED_ON
+ *
+ * While in this state:
+ * - The user is in the list of users for his session.
* - References will be given out if the user is looked up.
* - The user can access files and pipes.
*
* SMB_USER_STATE_LOGGING_OFF
*
* While in this state:
- * - The user is queued in the list of users of his session.
+ * - The user is in the list of users for his session.
* - References will not be given out if the user is looked up.
* - The trees the user connected are being disconnected.
* - The resources associated with the user remain.
*
- * SMB_USER_STATE_LOGGING_OFF
+ * SMB_USER_STATE_LOGGED_OFF
*
* While in this state:
* - The user is queued in the list of users of his session.
@@ -111,15 +130,34 @@
*
* Transition T0
*
- * This transition occurs in smb_user_login(). A new user is created and
- * added to the list of users of a session.
+ * First request in an SMB Session Setup sequence creates a
+ * new user object and adds it to the list of users for
+ * this session. User UID is assigned and returned.
*
* Transition T1
*
- * This transition occurs in smb_user_logoff().
+ * Subsequent SMB Session Setup requests (on the same UID
+ * assigned in T0) update the state of this user object,
+ * communicating with smbd for the crypto work.
*
* Transition T2
*
+ * If the SMB Session Setup sequence is successful, T2
+ * makes the new user object available for requests.
+ *
+ * Transition T3
+ *
+ * If an Session Setup request gets an error other than
+ * the expected "more processing required", then T3
+ * leads to state "LOGGED_OFF" and then tear-down of the
+ * partially constructed user.
+ *
+ * Transition T4
+ *
+ * Normal SMB User Logoff request, or session tear-down.
+ *
+ * Transition T5
+ *
* This transition occurs in smb_user_release(). The resources associated
* with the user are deleted as well as the user. For the transition to
* occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
@@ -169,9 +207,7 @@
#define ADMINISTRATORS_SID "S-1-5-32-544"
-static boolean_t smb_user_is_logged_in(smb_user_t *);
static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
-static void smb_user_nonauth_logon(smb_user_t *);
static void smb_user_auth_logoff(smb_user_t *);
@@ -179,77 +215,84 @@ static void smb_user_auth_logoff(smb_user_t *);
* Create a new user.
*/
smb_user_t *
-smb_user_login(
- smb_session_t *session,
- cred_t *cr,
- char *domain_name,
- char *account_name,
- uint32_t flags,
- uint32_t privileges,
- uint32_t audit_sid)
+smb_user_new(smb_session_t *session)
{
smb_user_t *user;
ASSERT(session);
ASSERT(session->s_magic == SMB_SESSION_MAGIC);
- ASSERT(cr);
- ASSERT(account_name);
- ASSERT(domain_name);
user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
bzero(user, sizeof (smb_user_t));
+
user->u_refcnt = 1;
user->u_session = session;
user->u_server = session->s_server;
user->u_logon_time = gethrestime_sec();
- user->u_flags = flags;
- user->u_name_len = strlen(account_name) + 1;
- user->u_domain_len = strlen(domain_name) + 1;
- user->u_name = smb_mem_strdup(account_name);
- user->u_domain = smb_mem_strdup(domain_name);
- user->u_audit_sid = audit_sid;
- if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
- mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
- smb_user_setcred(user, cr, privileges);
- user->u_state = SMB_USER_STATE_LOGGED_IN;
- user->u_magic = SMB_USER_MAGIC;
- smb_llist_enter(&session->s_user_list, RW_WRITER);
- smb_llist_insert_tail(&session->s_user_list, user);
- smb_llist_exit(&session->s_user_list);
- smb_server_inc_users(session->s_server);
- return (user);
- }
- smb_mem_free(user->u_name);
- smb_mem_free(user->u_domain);
+ if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
+ goto errout;
+
+ mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
+ user->u_state = SMB_USER_STATE_LOGGING_ON;
+ user->u_magic = SMB_USER_MAGIC;
+
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_insert_tail(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+ smb_server_inc_users(session->s_server);
+
+ return (user);
+
+errout:
+ if (user->u_uid != 0)
+ smb_idpool_free(&session->s_uid_pool, user->u_uid);
kmem_cache_free(smb_cache_user, user);
return (NULL);
}
/*
- * Create a new user based on an existing user, used to support
- * additional SessionSetupX requests for a user on a session.
- *
- * Assumes the caller has a reference on the original user from
- * a user_lookup_by_x call.
+ * Fill in the details of a user, meaning a transition
+ * from state LOGGING_ON to state LOGGED_ON.
*/
-smb_user_t *
-smb_user_dup(
- smb_user_t *orig_user)
+int
+smb_user_logon(
+ smb_user_t *user,
+ cred_t *cr,
+ char *domain_name,
+ char *account_name,
+ uint32_t flags,
+ uint32_t privileges,
+ uint32_t audit_sid)
{
- smb_user_t *user;
- ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
- ASSERT(orig_user->u_refcnt);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(cr);
+ ASSERT(account_name);
+ ASSERT(domain_name);
- user = smb_user_login(orig_user->u_session, orig_user->u_cred,
- orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
- orig_user->u_privileges, orig_user->u_audit_sid);
+ mutex_enter(&user->u_mutex);
- if (user)
- smb_user_nonauth_logon(orig_user);
+ if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
+ mutex_exit(&user->u_mutex);
+ return (-1);
+ }
- return (user);
+ smb_authsock_close(user);
+
+ user->u_state = SMB_USER_STATE_LOGGED_ON;
+ user->u_flags = flags;
+ user->u_name_len = strlen(account_name) + 1;
+ user->u_domain_len = strlen(domain_name) + 1;
+ user->u_name = smb_mem_strdup(account_name);
+ user->u_domain = smb_mem_strdup(domain_name);
+ user->u_audit_sid = audit_sid;
+
+ smb_user_setcred(user, cr, privileges);
+
+ mutex_exit(&user->u_mutex);
+
+ return (0);
}
/*
@@ -267,7 +310,14 @@ smb_user_logoff(
mutex_enter(&user->u_mutex);
ASSERT(user->u_refcnt);
switch (user->u_state) {
- case SMB_USER_STATE_LOGGED_IN: {
+ case SMB_USER_STATE_LOGGING_ON: {
+ smb_authsock_close(user);
+ user->u_state = SMB_USER_STATE_LOGGED_OFF;
+ smb_server_dec_users(user->u_server);
+ break;
+ }
+
+ case SMB_USER_STATE_LOGGED_ON: {
/*
* The user is moved into a state indicating that the log off
* process has started.
@@ -303,7 +353,7 @@ smb_user_hold(smb_user_t *user)
mutex_enter(&user->u_mutex);
- if (smb_user_is_logged_in(user)) {
+ if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
user->u_refcnt++;
mutex_exit(&user->u_mutex);
return (B_TRUE);
@@ -348,7 +398,8 @@ smb_user_release(
smb_session_post_user(user->u_session, user);
break;
- case SMB_USER_STATE_LOGGED_IN:
+ case SMB_USER_STATE_LOGGING_ON:
+ case SMB_USER_STATE_LOGGED_ON:
case SMB_USER_STATE_LOGGING_OFF:
break;
@@ -466,30 +517,6 @@ smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
/* *************************** Static Functions ***************************** */
/*
- * Determine whether or not a user is logged in.
- * Typically, a reference can only be taken on a logged-in user.
- *
- * This is a private function and must be called with the user
- * mutex held.
- */
-static boolean_t
-smb_user_is_logged_in(smb_user_t *user)
-{
- switch (user->u_state) {
- case SMB_USER_STATE_LOGGED_IN:
- return (B_TRUE);
-
- case SMB_USER_STATE_LOGGING_OFF:
- case SMB_USER_STATE_LOGGED_OFF:
- return (B_FALSE);
-
- default:
- ASSERT(0);
- return (B_FALSE);
- }
-}
-
-/*
* Delete a user. The tree list should be empty.
*
* Remove the user from the session's user list before freeing resources
@@ -504,6 +531,7 @@ smb_user_delete(void *arg)
SMB_USER_VALID(user);
ASSERT(user->u_refcnt == 0);
ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
+ ASSERT(user->u_authsock == NULL);
session = user->u_session;
smb_llist_enter(&session->s_user_list, RW_WRITER);
@@ -679,15 +707,6 @@ smb_user_netinfo_fini(smb_netuserinfo_t *info)
}
static void
-smb_user_nonauth_logon(smb_user_t *user)
-{
- uint32_t audit_sid = user->u_audit_sid;
-
- (void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_NONAUTH_LOGON,
- &audit_sid, xdr_uint32_t, NULL, NULL);
-}
-
-static void
smb_user_auth_logoff(smb_user_t *user)
{
uint32_t audit_sid = user->u_audit_sid;
@@ -695,27 +714,3 @@ smb_user_auth_logoff(smb_user_t *user)
(void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF,
&audit_sid, xdr_uint32_t, NULL, NULL);
}
-
-smb_token_t *
-smb_get_token(smb_session_t *session, smb_logon_t *user_info)
-{
- smb_token_t *token;
- int rc;
-
- token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
-
- rc = smb_kdoor_upcall(session->s_server, SMB_DR_USER_AUTH_LOGON,
- user_info, smb_logon_xdr, token, smb_token_xdr);
-
- if (rc != 0) {
- kmem_free(token, sizeof (smb_token_t));
- return (NULL);
- }
-
- if (!smb_token_valid(token)) {
- smb_token_free(token);
- return (NULL);
- }
-
- return (token);
-}
diff --git a/usr/src/uts/common/gssapi/Makefile b/usr/src/uts/common/gssapi/Makefile
index 82ec96631d..60396302fd 100644
--- a/usr/src/uts/common/gssapi/Makefile
+++ b/usr/src/uts/common/gssapi/Makefile
@@ -24,6 +24,7 @@
# All rights reserved.
#
# Copyright 2012 Milan Jurik. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
# uts/common/gssd/Makefile
#
@@ -31,7 +32,7 @@
include ../../../Makefile.master
-INSTALLED_HDRS= gssapi.h gssapi_ext.h
+INSTALLED_HDRS= gssapi.h gssapi_ext.h gssapi_krb5.h
PRIVATE_HDRS= gssd.x gssd_prot.h
HDRS= $(INSTALLED_HDRS) $(PRIVATE_HDRS)
@@ -47,10 +48,16 @@ CHECKHDRS= $(INSTALLED_HDRS:%.h=%.check)
# cstyle so it is unchecked
UNCHECKED_HDRS= gss_prot.h
-# install rule
+# install rules
$(GSSDDIRS)/%: %
$(INS.file)
+$(GSSDDIRS)/%: mechs/krb5/include/%
+ $(INS.file)
+
+# This is 3rd party code, so just skip hdrchk.
+gssapi_krb5.check:
+
.KEEP_STATE:
.PARALLEL: $(CHECKHDRS)
diff --git a/usr/src/uts/common/gssapi/gen_oids.c b/usr/src/uts/common/gssapi/gen_oids.c
index 3e2c0e9552..8c3866d7d9 100644
--- a/usr/src/uts/common/gssapi/gen_oids.c
+++ b/usr/src/uts/common/gssapi/gen_oids.c
@@ -57,15 +57,24 @@
*/
static const gss_OID_desc oids[] = {
+ /* GSS_C_NT_USER_NAME */
{10, "\052\206\110\206\367\022\001\002\001\001"},
+ /* GSS_C_NT_MACHINE_UID_NAME */
{10, "\052\206\110\206\367\022\001\002\001\002"},
+ /* GSS_C_NT_STRING_UID_NAME */
{10, "\052\206\110\206\367\022\001\002\001\003"},
+ /* gss_nt_service_name */
{10, "\052\206\110\206\367\022\001\002\001\004"},
+
+ /* GSS_C_NT_HOSTBASED_SERVICE */
{6, "\053\006\001\005\006\002"},
+ /* GSS_C_NT_ANONYMOUS */
{6, "\053\006\001\005\006\003"},
+ /* GSS_C_NT_EXPORT_NAME */
{6, "\053\006\001\005\006\004"},
- {11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"},
+ /* GSS_C_INQ_SSPI_SESSION_KEY */
+ {11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"},
};
const gss_OID_desc * const gss_nt_user_name = oids+0;
@@ -93,4 +102,4 @@ const gss_OID GSS_C_NT_STRING_UID_NAME = (gss_OID)oids+2;
const gss_OID GSS_C_NT_HOSTBASED_SERVICE = (gss_OID)oids+4;
const gss_OID GSS_C_NT_ANONYMOUS = (gss_OID)oids+5;
const gss_OID GSS_C_NT_EXPORT_NAME = (gss_OID)oids+6;
-const gss_OID GSS_C_INQ_SSPI_SESSION_KEY = (gss_OID)oids+7;
+const gss_OID GSS_C_INQ_SSPI_SESSION_KEY = (gss_OID)oids+7;
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
index 9bb092095b..aaaee2bd93 100644
--- a/usr/src/uts/common/smbsrv/Makefile
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
#
include ../../../Makefile.master
@@ -52,6 +53,7 @@ HDRS= alloc.h \
smb_ktypes.h \
smb_privilege.h \
smb_share.h \
+ smb_signing.h \
smb_token.h \
smb_vops.h \
smb_xdr.h \
diff --git a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
index de6c19049b..26df6a902a 100644
--- a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
+++ b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
@@ -21,7 +21,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _MLSVC_NETR_NDL_
@@ -70,6 +71,12 @@
#define NETR_OPNUM_LogonGetDomainInfo 0x1D
#define NETR_OPNUM_ServerPasswordSet2 0x1E
+/*
+ * This is not a real NETR OPNUM. It's used to unpack the
+ * struct krb5_validation_info found in the Kerberos PAC.
+ */
+#define NETR_OPNUM_decode_krb5_pac 1000
+
struct netr_sid {
BYTE Revision;
@@ -349,6 +356,15 @@ struct netr_validation_info3 {
struct netr_sid_and_attributes *ExtraSids;
};
+/* NETR_OPNUM_decode_krb5_pac */
+struct krb5_validation_info {
+ struct netr_validation_info3 info3;
+ /* Kerberos PAC "resource group" stuff. */
+ struct netr_sid *rg_dom_sid;
+ DWORD rg_rid_cnt;
+ SIZE_IS(rg_rid_cnt)
+ struct netr_group_membership *rg_rids;
+};
union netr_validation_u {
CASE(3) struct netr_validation_info3 *info3;
@@ -431,6 +447,10 @@ union netr_interface {
struct netr_PasswordSet PasswordSet;
CASE(NETR_OPNUM_ServerPasswordSet2)
struct netr_PasswordSet2 PasswordSet2;
+
+ /* Special, for smb_decode_krb5_pac() */
+ CASE(NETR_OPNUM_decode_krb5_pac)
+ struct krb5_validation_info krb5pac;
};
typedef union netr_interface netr_interface_t;
EXTERNTYPEINFO(netr_interface)
diff --git a/usr/src/uts/common/smbsrv/netrauth.h b/usr/src/uts/common/smbsrv/netrauth.h
index 7beb52ad51..54ea798a0d 100644
--- a/usr/src/uts/common/smbsrv/netrauth.h
+++ b/usr/src/uts/common/smbsrv/netrauth.h
@@ -21,6 +21,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_NETRAUTH_H
@@ -69,6 +71,32 @@ extern "C" {
#define NETR_VALIDATION_LEVEL3 0x03
/*
+ * Most of these are from: "MSV1_0_LM20_LOGON structure"
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa378762
+ * and a few are from the ntddk (ntmsv1_0.h) found many places.
+ */
+#define MSV1_0_CLEARTEXT_PASSWORD_ALLOWED 0x00000002
+#define MSV1_0_UPDATE_LOGON_STATISTICS 0x00000004
+#define MSV1_0_RETURN_USER_PARAMETERS 0x00000008
+#define MSV1_0_DONT_TRY_GUEST_ACCOUNT 0x00000010
+#define MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT 0x00000020
+#define MSV1_0_RETURN_PASSWORD_EXPIRY 0x00000040
+/*
+ * MSV1_0_USE_CLIENT_CHALLENGE means the LM response field contains the
+ * "client challenge" in the first 8 bytes instead of the LM response.
+ */
+#define MSV1_0_USE_CLIENT_CHALLENGE 0x00000080
+#define MSV1_0_TRY_GUEST_ACCOUNT_ONLY 0x00000100
+#define MSV1_0_RETURN_PROFILE_PATH 0x00000200
+#define MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY 0x00000400
+#define MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT 0x00000800
+#define MSV1_0_DISABLE_PERSONAL_FALLBACK 0x00001000
+#define MSV1_0_ALLOW_FORCE_GUEST 0x00002000
+#define MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED 0x00004000
+#define MSV1_0_USE_DOMAIN_FOR_ROUTING_ONLY 0x00008000
+#define MSV1_0_SUBAUTHENTICATION_DLL_EX 0x00100000
+
+/*
* This is a duplicate of the netr_credential
* from netlogon.ndl.
*/
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
index 100691582b..9c421bc454 100644
--- a/usr/src/uts/common/smbsrv/smb.h
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
@@ -777,20 +778,12 @@ typedef uint32_t smb_utime_t;
* The following bits may be set in the SecurityMode field of the
* SMB_COM_NEGOTIATE response.
*
- * Notes:
- * NEGOTIATE_SECURITY_SHARE_LEVEL is a montana2 invention.
- *
- * The NTDDK definitions are:
- * #define NEGOTIATE_USER_SECURITY 0x01
- * #define NEGOTIATE_ENCRYPT_PASSWORDS 0x02
- * #define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
- * #define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+ * Note: Same as the NTDDK definitions.
*/
-#define NEGOTIATE_SECURITY_SHARE_LEVEL 0x00
-#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
-#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
-#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
-#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+#define NEGOTIATE_USER_SECURITY 0x01
+#define NEGOTIATE_ENCRYPT_PASSWORDS 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
/*
diff --git a/usr/src/uts/common/smbsrv/smb_ioctl.h b/usr/src/uts/common/smbsrv/smb_ioctl.h
index e620a2b762..8ccecd7415 100644
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h
@@ -150,6 +150,7 @@ typedef struct smb_ioc_fileid {
uint32_t uniqid;
} smb_ioc_fileid_t;
+/* See also: smb_kmod_cfg_t */
typedef struct smb_ioc_cfg {
smb_ioc_header_t hdr;
uint32_t maxworkers;
@@ -161,12 +162,18 @@ typedef struct smb_ioc_cfg {
int32_t oplock_enable;
int32_t sync_enable;
int32_t secmode;
+ int32_t netbios_enable;
int32_t ipv6_enable;
int32_t print_enable;
int32_t traverse_mounts;
- int32_t netbios_enable;
uint32_t exec_flags;
+ uint32_t negtok_len;
smb_version_t version;
+ /* SMB negotiate protocol response. */
+ uuid_t machine_uuid;
+ uchar_t negtok[SMB_PI_MAX_NEGTOK];
+ char native_os[SMB_PI_MAX_NATIVE_OS];
+ char native_lm[SMB_PI_MAX_LANMAN];
char nbdomain[NETBIOS_NAME_SZ];
char fqdn[SMB_PI_MAX_DOMAIN];
char hostname[SMB_PI_MAX_HOST];
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index f19dd9926a..9f8e445481 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -553,6 +553,13 @@ void smb_request_cancel(smb_request_t *);
void smb_request_wait(smb_request_t *);
/*
+ * authentication support (smb_authenticate.c)
+ */
+int smb_authenticate_ext(smb_request_t *);
+int smb_authenticate_old(smb_request_t *);
+void smb_authsock_close(smb_user_t *);
+
+/*
* session functions (file smb_session.c)
*/
smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *, int);
@@ -566,6 +573,8 @@ void smb_session_config(smb_session_t *session);
void smb_session_disconnect_from_share(smb_llist_t *, char *);
smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
smb_user_t *smb_session_lookup_uid(smb_session_t *, uint16_t);
+smb_user_t *smb_session_lookup_uid_st(smb_session_t *session,
+ uint16_t uid, smb_user_state_t st);
void smb_session_post_user(smb_session_t *, smb_user_t *);
void smb_session_post_tree(smb_session_t *, smb_tree_t *);
smb_tree_t *smb_session_lookup_tree(smb_session_t *, uint16_t);
@@ -653,7 +662,8 @@ void smb_odir_resume_at(smb_odir_t *, smb_odir_resume_t *);
/*
* SMB user functions (file smb_user.c)
*/
-smb_user_t *smb_user_login(smb_session_t *, cred_t *,
+smb_user_t *smb_user_new(smb_session_t *);
+int smb_user_logon(smb_user_t *, cred_t *,
char *, char *, uint32_t, uint32_t, uint32_t);
smb_user_t *smb_user_dup(smb_user_t *);
void smb_user_logoff(smb_user_t *);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 79ee5e1ece..42428b2b13 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -300,6 +300,7 @@ typedef struct smb_idpool {
kmutex_t id_mutex;
uint8_t *id_pool;
uint32_t id_size;
+ uint32_t id_maxsize;
uint8_t id_bit;
uint8_t id_bit_idx;
uint32_t id_idx;
@@ -700,15 +701,34 @@ typedef struct smb_arg_negotiate {
timestruc_t ni_servertime;
} smb_arg_negotiate_t;
+typedef enum {
+ SMB_SSNSETUP_PRE_NTLM012 = 1,
+ SMB_SSNSETUP_NTLM012_NOEXT,
+ SMB_SSNSETUP_NTLM012_EXTSEC
+} smb_ssnsetup_type_t;
+
typedef struct smb_arg_sessionsetup {
+ smb_ssnsetup_type_t ssi_type;
char *ssi_user;
char *ssi_domain;
- uint16_t ssi_cipwlen;
- uint8_t *ssi_cipwd;
- uint16_t ssi_cspwlen;
- uint8_t *ssi_cspwd;
+ /* LM password hash, f.k.a. case-insensitive p/w */
+ uint16_t ssi_lmpwlen;
+ uint8_t *ssi_lmpwd;
+ /* NT password hash, f.k.a. case-sensitive p/w */
+ uint16_t ssi_ntpwlen;
+ uint8_t *ssi_ntpwd;
+ /* Incoming security blob */
+ uint16_t ssi_iseclen;
+ uint8_t *ssi_isecblob;
+ /* Incoming security blob */
+ uint16_t ssi_oseclen;
+ uint8_t *ssi_osecblob;
+ /* parameters */
+ uint16_t ssi_maxbufsize;
uint16_t ssi_maxmpxcount;
uint32_t ssi_capabilities;
+ int ssi_native_os;
+ int ssi_native_lm;
boolean_t ssi_guest;
} smb_arg_sessionsetup_t;
@@ -765,7 +785,6 @@ struct smb_sign {
uint32_t seqnum;
uint_t mackey_len;
uint8_t *mackey;
- void *mech; /* mechanism info */
};
#define SMB_SIGNING_ENABLED 1
@@ -902,7 +921,6 @@ typedef struct smb_session {
int32_t s_gmtoff;
uint32_t keep_alive;
uint64_t opentime;
- uint16_t vcnumber;
uint16_t s_local_port;
smb_inaddr_t ipaddr;
smb_inaddr_t local_ipaddr;
@@ -911,7 +929,9 @@ typedef struct smb_session {
int native_lm;
uint32_t capabilities;
- struct smb_sign signing;
+
+ struct smb_sign signing; /* SMB1 */
+ void *sign_mech; /* mechanism info */
void (*sign_fini)(struct smb_session *);
ksocket_t sock;
@@ -939,6 +959,7 @@ typedef struct smb_session {
* in SMB_SESSION_SETUP_ANDX
*/
uint16_t smb_msg_size;
+ uint16_t smb_max_mpx;
uchar_t *outpipe_data;
int outpipe_datalen;
int outpipe_cookie;
@@ -967,7 +988,8 @@ typedef struct smb_session {
typedef enum {
- SMB_USER_STATE_LOGGED_IN = 0,
+ SMB_USER_STATE_LOGGING_ON = 0,
+ SMB_USER_STATE_LOGGED_ON,
SMB_USER_STATE_LOGGING_OFF,
SMB_USER_STATE_LOGGED_OFF,
SMB_USER_STATE_SENTINEL
@@ -981,6 +1003,7 @@ typedef struct smb_user {
struct smb_server *u_server;
smb_session_t *u_session;
+ ksocket_t u_authsock;
uint16_t u_name_len;
char *u_name;
uint16_t u_domain_len;
diff --git a/usr/src/uts/common/smbsrv/smb_signing.h b/usr/src/uts/common/smbsrv/smb_signing.h
index 1b1694a99d..780ceb5c1d 100644
--- a/usr/src/uts/common/smbsrv/smb_signing.h
+++ b/usr/src/uts/common/smbsrv/smb_signing.h
@@ -23,6 +23,10 @@
#include <security/pkcs11.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */
#ifdef _KERNEL
@@ -47,4 +51,8 @@ int smb_md5_init(smb_sign_ctx_t *, smb_sign_mech_t *);
int smb_md5_update(smb_sign_ctx_t, void *, size_t);
int smb_md5_final(smb_sign_ctx_t, uint8_t *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _SMB_SIGNING_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_token.h b/usr/src/uts/common/smbsrv/smb_token.h
index 99541ad670..5b7a4eba37 100644
--- a/usr/src/uts/common/smbsrv/smb_token.h
+++ b/usr/src/uts/common/smbsrv/smb_token.h
@@ -19,10 +19,11 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_TOKEN_H
@@ -37,15 +38,9 @@ extern "C" {
#endif
/*
- * User Session Key
- *
- * This is part of the MAC key which is required for signing SMB messages.
+ * 32-bit opaque buffer (non-null terminated strings)
+ * See also: smb_buf32_xdr()
*/
-typedef struct smb_session_key {
- uint8_t data[16];
-} smb_session_key_t;
-
-/* 32-bit opaque buffer (non-null terminated strings) */
typedef struct smb_buf32 {
uint32_t len;
uint8_t *val;
@@ -96,7 +91,7 @@ typedef struct smb_token {
char *tkn_domain_name;
uint32_t tkn_flags;
uint32_t tkn_audit_sid;
- smb_session_key_t *tkn_session_key;
+ smb_buf32_t tkn_ssnkey;
smb_posix_grps_t *tkn_posix_grps;
} smb_token_t;
@@ -116,6 +111,7 @@ typedef struct smb_logon {
smb_buf32_t lg_challenge_key;
smb_buf32_t lg_nt_password;
smb_buf32_t lg_lm_password;
+ uint32_t lg_ntlm_flags;
int lg_native_os;
int lg_native_lm;
uint32_t lg_flags;
@@ -125,8 +121,70 @@ typedef struct smb_logon {
uint32_t lg_status; /* filled in user space */
} smb_logon_t;
-int smb_logon_xdr();
-int smb_token_xdr();
+/*
+ * This is the name of the local (AF_UNIX) socket
+ * where the SMB auth. service listens.
+ */
+#define SMB_AUTHSVC_SOCKNAME "/var/smb/lipc/smbauth"
+
+/*
+ * Maximum number of authentcation conversations at one time.
+ * Note this is _NOT_ the max. number of logged on users,
+ * which can be much larger.
+ */
+#define SMB_AUTHSVC_MAXTHREAD 256
+
+/*
+ * Messages to and from the local security authority
+ * Type codes:
+ */
+typedef enum smb_lsa_mtype {
+ /* reply types */
+ LSA_MTYPE_OK = 0,
+ LSA_MTYPE_ERROR,
+ LSA_MTYPE_ES_DONE, /* ext. sec: authenticated */
+ LSA_MTYPE_ES_CONT, /* more processing required */
+ LSA_MTYPE_TOKEN, /* smb_token_t */
+
+ /* request types */
+ LSA_MTYPE_OLDREQ, /* non-ext. sec. session setup */
+ LSA_MTYPE_CLINFO, /* client info sent at start of ES */
+ LSA_MTYPE_ESFIRST, /* spnego initial message */
+ LSA_MTYPE_ESNEXT, /* spnego continuation */
+ LSA_MTYPE_GETTOK /* after ES auth, get token */
+} smb_lsa_mtype_t;
+
+/*
+ * msg: header common to all message types
+ */
+typedef struct smb_lsa_msg_hdr {
+ uint32_t lmh_msgtype; /* smb_lsa_mtype_t */
+ uint32_t lmh_msglen; /* size of what follows */
+} smb_lsa_msg_hdr_t;
+
+/*
+ * eresp: error response
+ * msgtype: LSA_MTYPE_ERESP
+ */
+typedef struct smb_lsa_eresp {
+ uint32_t ler_ntstatus;
+ uint16_t ler_errclass;
+ uint16_t ler_errcode;
+} smb_lsa_eresp_t;
+
+/*
+ * Message for LSA_MTYPE_CLINFO
+ */
+typedef struct smb_lsa_clinfo {
+ smb_inaddr_t lci_clnt_ipaddr;
+ unsigned char lci_challenge_key[8];
+ int lci_native_os;
+ int lci_native_lm;
+} smb_lsa_clinfo_t;
+
+struct XDR;
+int smb_logon_xdr(struct XDR *, smb_logon_t *);
+int smb_token_xdr(struct XDR *, smb_token_t *);
#if defined(_KERNEL) || defined(_FAKE_KERNEL)
void smb_token_free(smb_token_t *);
diff --git a/usr/src/uts/common/smbsrv/smbinfo.h b/usr/src/uts/common/smbsrv/smbinfo.h
index 8e7724bdaa..fdb7ae8d5e 100644
--- a/usr/src/uts/common/smbsrv/smbinfo.h
+++ b/usr/src/uts/common/smbsrv/smbinfo.h
@@ -27,6 +27,7 @@
#define _SMBSRV_SMBINFO_H
#include <sys/types.h>
+#include <sys/uuid.h>
#include <smbsrv/netbios.h>
#include <netinet/in.h>
#include <smbsrv/smb_inet.h>
@@ -93,6 +94,7 @@ extern "C" {
#define SMB_PI_MAX_COMMENT 58
#define SMB_PI_MAX_NATIVE_OS 32
#define SMB_PI_MAX_LANMAN 32
+#define SMB_PI_MAX_NEGTOK 256 /* GUID and SMB negotiate token */
#define SMB_PI_KEEP_ALIVE_MIN (90 * 60)
/*
@@ -115,6 +117,7 @@ typedef struct smb_version {
uint32_t sv_platform_id;
} smb_version_t;
+/* See also: smb_ioc_cfg_t */
typedef struct smb_kmod_cfg {
uint32_t skc_maxworkers;
uint32_t skc_maxconnections;
@@ -130,7 +133,13 @@ typedef struct smb_kmod_cfg {
int32_t skc_print_enable;
int32_t skc_traverse_mounts;
uint32_t skc_execflags;
+ uint32_t skc_negtok_len;
smb_version_t skc_version;
+ /* SMB negotiate protocol response. */
+ uuid_t skc_machine_uuid;
+ uchar_t skc_negtok[SMB_PI_MAX_NEGTOK];
+ char skc_native_os[SMB_PI_MAX_NATIVE_OS];
+ char skc_native_lm[SMB_PI_MAX_LANMAN];
char skc_nbdomain[NETBIOS_NAME_SZ];
char skc_fqdn[SMB_PI_MAX_DOMAIN];
char skc_hostname[SMB_PI_MAX_HOST];