summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/replace/libreplace_network.m44
-rw-r--r--lib/socket_wrapper/socket_wrapper.c56
-rw-r--r--selftest/target/Samba3.pm1
-rw-r--r--source3/Makefile.in21
-rw-r--r--source3/configure.in48
-rw-r--r--source3/include/async_smb.h2
-rw-r--r--source3/include/client.h10
-rw-r--r--source3/include/includes.h1
-rw-r--r--source3/include/proto.h59
-rw-r--r--source3/include/smb.h17
-rw-r--r--source3/include/smb_signing.h46
-rw-r--r--source3/lib/avahi.c268
-rw-r--r--source3/libsmb/async_smb.c43
-rw-r--r--source3/libsmb/cliconnect.c46
-rw-r--r--source3/libsmb/clientgen.c104
-rw-r--r--source3/libsmb/clisigning.c87
-rw-r--r--source3/libsmb/clitrans.c54
-rw-r--r--source3/libsmb/smb_signing.c1020
-rw-r--r--source3/param/loadparm.c11
-rwxr-xr-xsource3/selftest/tests.sh4
-rw-r--r--source3/smbd/aio.c13
-rw-r--r--source3/smbd/avahi_register.c170
-rw-r--r--source3/smbd/blocking.c5
-rw-r--r--source3/smbd/globals.h1
-rw-r--r--source3/smbd/ipc.c4
-rw-r--r--source3/smbd/negprot.c2
-rw-r--r--source3/smbd/notify.c7
-rw-r--r--source3/smbd/nttrans.c3
-rw-r--r--source3/smbd/open.c9
-rw-r--r--source3/smbd/oplock.c27
-rw-r--r--source3/smbd/password.c8
-rw-r--r--source3/smbd/pipes.c1
-rw-r--r--source3/smbd/process.c52
-rw-r--r--source3/smbd/reply.c24
-rw-r--r--source3/smbd/server.c11
-rw-r--r--source3/smbd/service.c2
-rw-r--r--source3/smbd/sesssetup.c25
-rw-r--r--source3/smbd/signing.c158
-rw-r--r--source3/smbd/trans2.c5
-rw-r--r--source3/winbindd/winbindd_pam.c2
40 files changed, 1366 insertions, 1065 deletions
diff --git a/lib/replace/libreplace_network.m4 b/lib/replace/libreplace_network.m4
index 3bac72d136..2af02312ab 100644
--- a/lib/replace/libreplace_network.m4
+++ b/lib/replace/libreplace_network.m4
@@ -170,7 +170,7 @@ fi
# The following tests need LIBS="${LIBREPLACE_NETWORK_LIBS}"
old_LIBS=$LIBS
LIBS="${LIBREPLACE_NETWORK_LIBS}"
-SAVE_CPPFLAGS="$CPPFLAGS"
+libreplace_SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -I$libreplacedir"
AC_CHECK_FUNCS(socketpair,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} socketpair.o"])
@@ -381,7 +381,7 @@ if test x"$libreplace_cv_HAVE_IPV6" = x"yes"; then
fi
LIBS=$old_LIBS
-CPPFLAGS="$SAVE_CPPFLAGS"
+CPPFLAGS="$libreplace_SAVE_CPPFLAGS"
LIBREPLACEOBJ="${LIBREPLACEOBJ} ${LIBREPLACE_NETWORK_OBJS}"
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index 44082e78a1..553827b192 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -218,6 +218,7 @@ struct socket_info
int bcast;
int is_server;
int connected;
+ int defer_connect;
char *path;
char *tmp_path;
@@ -1686,10 +1687,15 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
if (ret == -1) return -1;
- swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+ if (si->type == SOCK_DGRAM) {
+ si->defer_connect = 1;
+ ret = 0;
+ } else {
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
- ret = real_connect(s, (struct sockaddr *)&un_addr,
- sizeof(struct sockaddr_un));
+ ret = real_connect(s, (struct sockaddr *)&un_addr,
+ sizeof(struct sockaddr_un));
+ }
/* to give better errors */
if (ret == -1 && errno == ENOENT) {
@@ -1917,7 +1923,22 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
return len;
}
-
+
+ if (si->defer_connect) {
+ ret = real_connect(s, (struct sockaddr *)&un_addr,
+ sizeof(un_addr));
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == -1) {
+ return ret;
+ }
+ si->defer_connect = 0;
+ }
+
ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
break;
default:
@@ -2002,6 +2023,33 @@ _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
len = MIN(len, 1500);
+ if (si->defer_connect) {
+ struct sockaddr_un un_addr;
+ int bcast = 0;
+
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si, si->family);
+ if (ret == -1) return -1;
+ }
+
+ ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
+ &un_addr, 0, &bcast);
+ if (ret == -1) return -1;
+
+ ret = real_connect(s, (struct sockaddr *)&un_addr,
+ sizeof(un_addr));
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == -1) {
+ return ret;
+ }
+ si->defer_connect = 0;
+ }
+
ret = real_send(s, buf, len, flags);
if (ret == -1) {
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 78aafa7533..0b176d601c 100644
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -144,6 +144,7 @@ sub setup_member($$$)
my $member_options = "
security = domain
+ server signing = on
";
my $ret = $self->provision($prefix,
"LOCALMEMBER3",
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 49cf8408d3..b28109ec60 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -73,6 +73,7 @@ WINBIND_NSS_EXTRA_LIBS=@WINBIND_NSS_EXTRA_LIBS@
WINBIND_NSS_PTHREAD=@WINBIND_NSS_PTHREAD@
PAM_WINBIND_EXTRA_LIBS=@PAM_WINBIND_EXTRA_LIBS@
DNSSD_LIBS=@DNSSD_LIBS@
+AVAHI_LIBS=@AVAHI_LIBS@
POPT_LIBS=@POPTLIBS@
LIBTALLOC_LIBS=@LIBTALLOC_LIBS@
LIBTDB_LIBS=@LIBTDB_LIBS@
@@ -158,7 +159,7 @@ CODEPAGEDIR = @codepagedir@
# the directory where pid files go
PIDDIR = @piddir@
-FLAGS = -I. -I$(srcdir) @FLAGS1@ @SAMBA_CPPFLAGS@ $(CPPFLAGS) -I$(CTDBDIR)/include $(ISA) -I$(srcdir)/lib -I.. -D_SAMBA_BUILD_=3 -I../source4
+FLAGS = -I. -I$(srcdir) @FLAGS1@ @SAMBA_CPPFLAGS@ $(CPPFLAGS) $(ISA) -I$(srcdir)/lib -I.. -D_SAMBA_BUILD_=3 -I../source4
PATH_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\" \
-DPRIVATE_DIR=\"$(PRIVATE_DIR)\" \
@@ -173,7 +174,6 @@ PATH_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\" \
-DMODULESDIR=\"$(MODULESDIR)\" \
-DLOGFILEBASE=\"$(LOGFILEBASE)\" \
-DSHLIBEXT=\"@SHLIBEXT@\" \
- -DCTDBDIR=\"$(CTDBDIR)\" \
-DNCALRPCDIR=\"$(NCALRPCDIR)\" \
-DCONFIGDIR=\"$(CONFIGDIR)\" \
-DCODEPAGEDIR=\"$(CODEPAGEDIR)\" \
@@ -255,6 +255,8 @@ AFS_OBJ = lib/afs.o
AFS_SETTOKEN_OBJ = lib/afs_settoken.o
+AVAHI_OBJ = @AVAHI_OBJ@
+
SERVER_MUTEX_OBJ = lib/server_mutex.o
PASSCHANGE_OBJ = libsmb/passchange.o
@@ -364,7 +366,8 @@ LIB_OBJ = $(LIBSAMBAUTIL_OBJ) $(UTIL_OBJ) $(CRYPTO_OBJ) \
lib/util.o lib/util_sock.o lib/sock_exec.o lib/util_sec.o \
lib/substitute.o lib/dbwrap_util.o \
lib/ms_fnmatch.o lib/select.o lib/errmap_unix.o \
- lib/tallocmsg.o lib/dmallocmsg.o libsmb/smb_signing.o \
+ lib/tallocmsg.o lib/dmallocmsg.o \
+ libsmb/clisigning.o libsmb/smb_signing.o \
lib/iconv.o lib/pam_errors.o intl/lang_tdb.o \
lib/conn_tdb.o lib/adt_tree.o lib/gencache.o \
lib/module.o lib/events.o @LIBTEVENT_OBJ0@ \
@@ -732,7 +735,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/change_trust_pw.o smbd/fake_file.o \
smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
$(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
- smbd/dmapi.o \
+ smbd/dmapi.o smbd/signing.o \
smbd/file_access.o \
smbd/dnsregister.o smbd/globals.o \
$(MANGLE_OBJ) @VFS_STATIC@
@@ -742,7 +745,7 @@ SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
$(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) \
$(LIB_OBJ) $(PRINTBACKEND_OBJ) $(OPLOCK_OBJ) \
$(NOTIFY_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) \
- $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(AVAHI_OBJ) \
$(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \
$(REG_FULL_OBJ) $(POPT_LIB_OBJ) $(BUILDOPT_OBJ) \
$(SMBLDAP_OBJ) $(LDB_OBJ) $(LIBNET_OBJ) @LIBWBCLIENT_STATIC@ \
@@ -1278,6 +1281,10 @@ everything:: all libtalloc libsmbclient libnetapi debug2html smbfilter talloctor
.SUFFIXES:
.SUFFIXES: .c .o .lo
+.PHONY: showflags SHOWFLAGS
+
+showflags: SHOWFLAGS
+
SHOWFLAGS::
@echo "Using CFLAGS = $(CFLAGS)"
@echo " PICFLAG = $(PICFLAG)"
@@ -1386,7 +1393,7 @@ bin/smbd@EXEEXT@: $(BINARY_PREREQS) $(SMBD_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARE
@echo Linking $@
@$(CC) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LDAP_LIBS) \
$(KRB5LIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) \
- $(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) $(DNSSD_LIBS) \
+ $(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) $(DNSSD_LIBS) $(AVAHI_LIBS) \
$(POPT_LIBS) @SMBD_LIBS@ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
$(WINBIND_LIBS) $(ZLIB_LIBS)
@@ -1572,7 +1579,7 @@ bin/pdbtest@EXEEXT@: $(BINARY_PREREQS) $(PDBTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SH
bin/vfstest@EXEEXT@: $(BINARY_PREREQS) $(VFSTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
@echo Linking $@
- @$(CC) -o $@ $(VFSTEST_OBJ) $(LDFLAGS) $(TERMLDFLAGS) \
+ @$(CC) -o $@ $(VFSTEST_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(AVAHI_LIBS) \
$(TERMLIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) $(DNSSD_LIBS) \
$(ACL_LIBS) $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) \
@SMBD_LIBS@ $(NSCD_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
diff --git a/source3/configure.in b/source3/configure.in
index cfc2473a82..1cf8d9ca4a 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -152,13 +152,11 @@ AC_SUBST(NSCD_LIBS)
# do this here since AC_CACHE_CHECK apparently sets the CFLAGS to "-g -O2"
# if it has no value. This prevent *very* large debug binaries from occurring
# by default.
-if test "x$CFLAGS" = x; then
- CFLAGS="-O"
-fi
if test "x$debug" = "xyes" ; then
CFLAGS="${CFLAGS} -g"
-else
- CFLAGS="${CFLAGS} -O"
+fi
+if test "x$CFLAGS" = x; then
+ CFLAGS="-O"
fi
m4_include(../lib/socket_wrapper/config.m4)
@@ -5975,10 +5973,10 @@ AC_SUBST(FLAGS1)
# Check if user wants DNS service discovery support
AC_ARG_ENABLE(dnssd,
-[AS_HELP_STRING([--enable-dnssd], [Enable DNS service discovery support (default=auto)])])
+[AS_HELP_STRING([--enable-dnssd], [Enable DNS service discovery support (default=no)])])
AC_SUBST(DNSSD_LIBS)
-if test x"$enable_dnssd" != x"no"; then
+if test x"$enable_dnssd" == x"yes"; then
have_dnssd_support=yes
AC_CHECK_HEADERS(dns_sd.h)
@@ -6007,6 +6005,42 @@ if test x"$enable_dnssd" != x"no"; then
fi
#################################################
+# Check if user wants avahi support
+
+AC_ARG_ENABLE(avahi,
+[AS_HELP_STRING([--enable-avahi], [Enable Avahi support (default=auto)])])
+
+AC_SUBST(AVAHI_LIBS)
+if test x"$enable_avahi" != x"no"; then
+ have_avahi_support=yes
+
+ AC_CHECK_HEADERS(avahi-common/watch.h)
+ if test x"$ac_cv_header_avahi_common_watch_h" != x"yes"; then
+ have_avahi_support=no
+ fi
+
+ AC_CHECK_HEADERS(avahi-client/client.h)
+ if test x"$ac_cv_header_avahi_common_watch_h" != x"yes"; then
+ have_avahi_support=no
+ fi
+
+ AC_CHECK_LIB_EXT(avahi-client, AVAHI_LIBS, avahi_client_new)
+ if test x"$ac_cv_lib_ext_avahi_client_avahi_client_new" != x"yes"; then
+ have_avahi_support=no
+ fi
+
+ if test x"$have_avahi_support" = x"yes"; then
+ AC_DEFINE(WITH_AVAHI_SUPPORT, 1,
+ [Whether to enable avahi support])
+ AC_SUBST(AVAHI_OBJ, "lib/avahi.o smbd/avahi_register.o")
+ else
+ if test x"$enable_avahi" = x"yes"; then
+ AC_MSG_ERROR(avahi support not available)
+ fi
+ fi
+fi
+
+#################################################
# Check to see if we should use the included iniparser
AC_ARG_WITH(included-iniparser,
diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h
index 7fc4ff7d27..2ac1101a1e 100644
--- a/source3/include/async_smb.h
+++ b/source3/include/async_smb.h
@@ -63,6 +63,8 @@ struct cli_request {
*/
uint16_t mid;
+ uint32_t seqnum;
+
/**
* The bytes we have to ship to the server
*/
diff --git a/source3/include/client.h b/source3/include/client.h
index 320a90e66b..db19f34a9d 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -166,6 +166,13 @@ struct smb_trans_enc_state {
} s;
};
+struct cli_state_seqnum {
+ struct cli_state_seqnum *prev, *next;
+ uint16_t mid;
+ uint32_t seqnum;
+ bool persistent;
+};
+
struct cli_state {
/**
* A list of subsidiary connections for DFS.
@@ -217,6 +224,7 @@ struct cli_state {
size_t max_xmit;
size_t max_mux;
char *outbuf;
+ struct cli_state_seqnum *seqnum;
char *inbuf;
unsigned int bufsize;
int initialised;
@@ -231,7 +239,7 @@ struct cli_state {
TALLOC_CTX *call_mem_ctx;
#endif
- smb_sign_info sign_info;
+ struct smb_signing_state *signing_state;
struct smb_trans_enc_state *trans_enc_state; /* Setup if we're encrypting SMB's. */
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 4bf4b5c735..c883e17713 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -598,6 +598,7 @@ struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx);
#include "messages.h"
#include "locking.h"
#include "smb_perfcount.h"
+#include "smb_signing.h"
#include "smb.h"
#include "nameserv.h"
#include "secrets.h"
diff --git a/source3/include/proto.h b/source3/include/proto.h
index c84b1cb9ac..c8dce13916 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2410,6 +2410,10 @@ bool receive_getdc_response(TALLOC_CTX *mem_ctx,
int cli_set_message(char *buf,int num_words,int num_bytes,bool zero);
unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout);
void cli_set_port(struct cli_state *cli, int port);
+bool cli_state_seqnum_persistent(struct cli_state *cli,
+ uint16_t mid);
+bool cli_state_seqnum_remove(struct cli_state *cli,
+ uint16_t mid);
bool cli_receive_smb(struct cli_state *cli);
ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len);
bool cli_receive_smb_readX_header(struct cli_state *cli);
@@ -3181,29 +3185,34 @@ void cli_free_enc_buffer(struct cli_state *cli, char *buf);
NTSTATUS cli_decrypt_message(struct cli_state *cli);
NTSTATUS cli_encrypt_message(struct cli_state *cli, char *buf, char **buf_out);
-/* The following definitions come from libsmb/smb_signing.c */
+/* The following definitions come from libsmb/clisigning.c */
bool cli_simple_set_signing(struct cli_state *cli,
const DATA_BLOB user_session_key,
const DATA_BLOB response);
-bool cli_null_set_signing(struct cli_state *cli);
bool cli_temp_set_signing(struct cli_state *cli);
-void cli_free_signing_context(struct cli_state *cli);
-void cli_calculate_sign_mac(struct cli_state *cli, char *buf);
-bool cli_check_sign_mac(struct cli_state *cli, char *buf);
-bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid);
-bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid);
+void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum);
+bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum);
bool client_is_signing_on(struct cli_state *cli);
-bool srv_oplock_set_signing(bool onoff);
-bool srv_check_sign_mac(const char *inbuf, bool must_be_ok);
-void srv_calculate_sign_mac(char *outbuf);
-void srv_defer_sign_response(uint16 mid);
-void srv_cancel_sign_response(uint16 mid, bool cancel);
-void srv_set_signing_negotiated(void);
-bool srv_is_signing_active(void);
-bool srv_is_signing_negotiated(void);
-bool srv_signing_started(void);
-void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response);
+bool client_is_signing_allowed(struct cli_state *cli);
+bool client_is_signing_mandatory(struct cli_state *cli);
+void cli_set_signing_negotiated(struct cli_state *cli);
+
+/* The following definitions come from smbd/signing.c */
+
+struct smbd_server_connection;
+bool srv_check_sign_mac(struct smbd_server_connection *conn,
+ const char *inbuf, uint32_t *seqnum);
+void srv_calculate_sign_mac(struct smbd_server_connection *conn,
+ char *outbuf, uint32_t seqnum);
+void srv_cancel_sign_response(struct smbd_server_connection *conn);
+bool srv_init_signing(struct smbd_server_connection *conn);
+void srv_set_signing_negotiated(struct smbd_server_connection *conn);
+bool srv_is_signing_active(struct smbd_server_connection *conn);
+bool srv_is_signing_negotiated(struct smbd_server_connection *conn);
+void srv_set_signing(struct smbd_server_connection *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
/* The following definitions come from libsmb/smbdes.c */
@@ -4347,7 +4356,7 @@ const char *lp_printcapname(void);
bool lp_disable_spoolss( void );
void lp_set_spoolss_state( uint32 state );
uint32 lp_get_spoolss_state( void );
-bool lp_use_sendfile(int snum);
+bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state);
void set_use_sendfile(int snum, bool val);
void set_store_dos_attributes(int snum, bool val);
void lp_set_mangling_method(const char *new_method);
@@ -6722,7 +6731,9 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname);
void smbd_setup_sig_term_handler(void);
void smbd_setup_sig_hup_handler(void);
-bool srv_send_smb(int fd, char *buffer, bool do_encrypt,
+bool srv_send_smb(int fd, char *buffer,
+ bool no_signing, uint32_t seqnum,
+ bool do_encrypt,
struct smb_perfcount_data *pcd);
int srv_set_message(char *buf,
int num_words,
@@ -7219,6 +7230,16 @@ NTSTATUS idmap_sid_to_gid(const char *domname, DOM_SID *sid, gid_t *gid);
NTSTATUS nss_info_template_init( void );
+/* The following definitions come from lib/avahi.c */
+
+struct AvahiPoll *tevent_avahi_poll(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev);
+
+/* The following definitions come from smbd/avahi_register.c */
+
+void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ uint16_t port);
+
/* Misc protos */
#endif /* _PROTO_H_ */
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 281a218256..84aa36a364 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -621,6 +621,7 @@ struct smb_request {
uint16 flags2;
uint16 smbpid;
uint16 mid;
+ uint32_t seqnum;
uint16 vuid;
uint16 tid;
uint8 wct;
@@ -722,6 +723,7 @@ struct pending_message_list {
struct timeval request_time; /* When was this first issued? */
struct timed_event *te;
struct smb_perfcount_data pcd;
+ uint32_t seqnum;
bool encrypted;
DATA_BLOB buf;
DATA_BLOB private_data;
@@ -1847,21 +1849,6 @@ struct ip_service {
/* Special name type used to cause a _kerberos DNS lookup. */
#define KDC_NAME_TYPE 0xDCDC
-/* Used by the SMB signing functions. */
-
-typedef struct smb_sign_info {
- void (*sign_outgoing_message)(char *outbuf, struct smb_sign_info *si);
- bool (*check_incoming_message)(const char *inbuf, struct smb_sign_info *si, bool must_be_ok);
- void (*free_signing_context)(struct smb_sign_info *si);
- void *signing_context;
-
- bool negotiated_smb_signing;
- bool allow_smb_signing;
- bool doing_signing;
- bool mandatory_signing;
- bool seen_valid; /* Have I ever seen a validly signed packet? */
-} smb_sign_info;
-
struct ea_struct {
uint8 flags;
char *name;
diff --git a/source3/include/smb_signing.h b/source3/include/smb_signing.h
new file mode 100644
index 0000000000..770c40cb35
--- /dev/null
+++ b/source3/include/smb_signing.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+struct smb_signing_state;
+
+struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool mandatory);
+uint32_t smb_signing_next_seqnum(struct smb_signing_state *si, bool oneway);
+void smb_signing_cancel_reply(struct smb_signing_state *si, bool oneway);
+void smb_signing_sign_pdu(struct smb_signing_state *si,
+ uint8_t *outbuf, uint32_t seqnum);
+bool smb_signing_check_pdu(struct smb_signing_state *si,
+ const uint8_t *inbuf, uint32_t seqnum);
+bool smb_signing_set_bsrspyl(struct smb_signing_state *si);
+bool smb_signing_activate(struct smb_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool smb_signing_is_active(struct smb_signing_state *si);
+bool smb_signing_is_allowed(struct smb_signing_state *si);
+bool smb_signing_is_mandatory(struct smb_signing_state *si);
+bool smb_signing_set_negotiated(struct smb_signing_state *si);
+bool smb_signing_is_negotiated(struct smb_signing_state *si);
+
+#endif /* _SMB_SIGNING_H_ */
diff --git a/source3/lib/avahi.c b/source3/lib/avahi.c
new file mode 100644
index 0000000000..ac9867a1fc
--- /dev/null
+++ b/source3/lib/avahi.c
@@ -0,0 +1,268 @@
+/*
+ Unix SMB/CIFS implementation.
+ Connect avahi to lib/tevents
+ Copyright (C) Volker Lendecke 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include <avahi-common/watch.h>
+
+struct avahi_poll_context {
+ struct tevent_context *ev;
+ AvahiWatch **watches;
+ AvahiTimeout **timeouts;
+};
+
+struct AvahiWatch {
+ struct avahi_poll_context *ctx;
+ struct tevent_fd *fde;
+ int fd;
+ AvahiWatchEvent latest_event;
+ AvahiWatchCallback callback;
+ void *userdata;
+};
+
+struct AvahiTimeout {
+ struct avahi_poll_context *ctx;
+ struct tevent_timer *te;
+ AvahiTimeoutCallback callback;
+ void *userdata;
+};
+
+static uint16_t avahi_flags_map_to_tevent(AvahiWatchEvent event)
+{
+ return ((event & AVAHI_WATCH_IN) ? TEVENT_FD_READ : 0)
+ | ((event & AVAHI_WATCH_OUT) ? TEVENT_FD_WRITE : 0);
+}
+
+static void avahi_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde, uint16_t flags,
+ void *private_data);
+
+static AvahiWatch *avahi_watch_new(const AvahiPoll *api, int fd,
+ AvahiWatchEvent event,
+ AvahiWatchCallback callback,
+ void *userdata)
+{
+ struct avahi_poll_context *ctx = talloc_get_type_abort(
+ api->userdata, struct avahi_poll_context);
+ int num_watches = talloc_array_length(ctx->watches);
+ AvahiWatch **tmp, *watch_ctx;
+
+ tmp = talloc_realloc(ctx, ctx->watches, AvahiWatch *, num_watches + 1);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ ctx->watches = tmp;
+
+ watch_ctx = talloc(tmp, AvahiWatch);
+ if (watch_ctx == NULL) {
+ goto fail;
+ }
+ ctx->watches[num_watches] = watch_ctx;
+
+ watch_ctx->ctx = ctx;
+ watch_ctx->fde = tevent_add_fd(ctx->ev, watch_ctx, fd,
+ avahi_flags_map_to_tevent(event),
+ avahi_fd_handler, watch_ctx);
+ if (watch_ctx->fde == NULL) {
+ goto fail;
+ }
+ watch_ctx->callback = callback;
+ watch_ctx->userdata = userdata;
+ return watch_ctx;
+
+ fail:
+ TALLOC_FREE(watch_ctx);
+ ctx->watches = talloc_realloc(ctx, ctx->watches, AvahiWatch *,
+ num_watches);
+ return NULL;
+}
+
+static void avahi_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde, uint16_t flags,
+ void *private_data)
+{
+ AvahiWatch *watch_ctx = talloc_get_type_abort(private_data, AvahiWatch);
+
+ watch_ctx->latest_event =
+ ((flags & TEVENT_FD_READ) ? AVAHI_WATCH_IN : 0)
+ | ((flags & TEVENT_FD_WRITE) ? AVAHI_WATCH_OUT : 0);
+
+ watch_ctx->callback(watch_ctx, watch_ctx->fd, watch_ctx->latest_event,
+ watch_ctx->userdata);
+}
+
+static void avahi_watch_update(AvahiWatch *w, AvahiWatchEvent event)
+{
+ tevent_fd_set_flags(w->fde, avahi_flags_map_to_tevent(event));
+}
+
+static AvahiWatchEvent avahi_watch_get_events(AvahiWatch *w)
+{
+ return w->latest_event;
+}
+
+static void avahi_watch_free(AvahiWatch *w)
+{
+ int i, num_watches;
+ AvahiWatch **watches = w->ctx->watches;
+ struct avahi_poll_context *ctx;
+
+ num_watches = talloc_array_length(watches);
+
+ for (i=0; i<num_watches; i++) {
+ if (w == watches[i]) {
+ break;
+ }
+ }
+ if (i == num_watches) {
+ return;
+ }
+ ctx = w->ctx;
+ TALLOC_FREE(w);
+ memmove(&watches[i], &watches[i+1],
+ sizeof(*watches) * (num_watches - i - 1));
+ ctx->watches = talloc_realloc(ctx, watches, AvahiWatch *,
+ num_watches - 1);
+}
+
+static void avahi_timeout_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+
+static AvahiTimeout *avahi_timeout_new(const AvahiPoll *api,
+ const struct timeval *tv,
+ AvahiTimeoutCallback callback,
+ void *userdata)
+{
+ struct avahi_poll_context *ctx = talloc_get_type_abort(
+ api->userdata, struct avahi_poll_context);
+ int num_timeouts = talloc_array_length(ctx->timeouts);
+ AvahiTimeout **tmp, *timeout_ctx;
+
+ tmp = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
+ num_timeouts + 1);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ ctx->timeouts = tmp;
+
+ timeout_ctx = talloc(tmp, AvahiTimeout);
+ if (timeout_ctx == NULL) {
+ goto fail;
+ }
+ ctx->timeouts[num_timeouts] = timeout_ctx;
+
+ timeout_ctx->ctx = ctx;
+ if (tv == NULL) {
+ timeout_ctx->te = NULL;
+ } else {
+ timeout_ctx->te = tevent_add_timer(ctx->ev, timeout_ctx,
+ *tv, avahi_timeout_handler,
+ timeout_ctx);
+ if (timeout_ctx->te == NULL) {
+ goto fail;
+ }
+ }
+ timeout_ctx->callback = callback;
+ timeout_ctx->userdata = userdata;
+ return timeout_ctx;
+
+ fail:
+ TALLOC_FREE(timeout_ctx);
+ ctx->timeouts = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
+ num_timeouts);
+ return NULL;
+}
+
+static void avahi_timeout_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ AvahiTimeout *timeout_ctx = talloc_get_type_abort(
+ private_data, AvahiTimeout);
+
+ TALLOC_FREE(timeout_ctx->te);
+ timeout_ctx->callback(timeout_ctx, timeout_ctx->userdata);
+}
+
+static void avahi_timeout_update(AvahiTimeout *t, const struct timeval *tv)
+{
+ TALLOC_FREE(t->te);
+
+ t->te = tevent_add_timer(t->ctx->ev, t, *tv, avahi_timeout_handler, t);
+ /*
+ * No failure mode defined here
+ */
+ SMB_ASSERT(t->te != NULL);
+}
+
+static void avahi_timeout_free(AvahiTimeout *t)
+{
+ int i, num_timeouts;
+ AvahiTimeout **timeouts = t->ctx->timeouts;
+ struct avahi_poll_context *ctx;
+
+ num_timeouts = talloc_array_length(timeouts);
+
+ for (i=0; i<num_timeouts; i++) {
+ if (t == timeouts[i]) {
+ break;
+ }
+ }
+ if (i == num_timeouts) {
+ return;
+ }
+ ctx = t->ctx;
+ TALLOC_FREE(t);
+ memmove(&timeouts[i], &timeouts[i+1],
+ sizeof(*timeouts) * (num_timeouts - i - 1));
+ ctx->timeouts = talloc_realloc(ctx, timeouts, AvahiTimeout *,
+ num_timeouts - 1);
+}
+
+struct AvahiPoll *tevent_avahi_poll(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
+{
+ struct AvahiPoll *result;
+ struct avahi_poll_context *ctx;
+
+ result = talloc(mem_ctx, struct AvahiPoll);
+ if (result == NULL) {
+ return result;
+ }
+ ctx = talloc_zero(result, struct avahi_poll_context);
+ if (ctx == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ ctx->ev = ev;
+
+ result->watch_new = avahi_watch_new;
+ result->watch_update = avahi_watch_update;
+ result->watch_get_events = avahi_watch_get_events;
+ result->watch_free = avahi_watch_free;
+ result->timeout_new = avahi_timeout_new;
+ result->timeout_update = avahi_timeout_update;
+ result->timeout_free = avahi_timeout_free;
+ result->userdata = ctx;
+
+ return result;
+}
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
index 066ac7bdb8..86fd5c8bef 100644
--- a/source3/libsmb/async_smb.c
+++ b/source3/libsmb/async_smb.c
@@ -550,7 +550,7 @@ void cli_chain_uncork(struct cli_state *cli)
_smb_setlen_large(((char *)req->outbuf), smblen);
}
- cli_calculate_sign_mac(cli, (char *)req->outbuf);
+ cli_calculate_sign_mac(cli, (char *)req->outbuf, &req->seqnum);
if (cli_encryption_on(cli)) {
NTSTATUS status;
@@ -811,9 +811,16 @@ NTSTATUS cli_pull_reply(struct async_req *req,
*/
-static NTSTATUS validate_smb_crypto(struct cli_state *cli, char *pdu)
+static NTSTATUS validate_smb_crypto(struct cli_state *cli, char *pdu,
+ struct cli_request **_req,
+ uint16_t *_mid)
{
NTSTATUS status;
+ struct cli_request *req = NULL;
+ uint16_t mid;
+
+ *_req = NULL;
+ *_mid = 0;
if ((IVAL(pdu, 4) != 0x424d53ff) /* 0xFF"SMB" */
&& (SVAL(pdu, 4) != 0x45ff)) /* 0xFF"E" */ {
@@ -846,11 +853,27 @@ static NTSTATUS validate_smb_crypto(struct cli_state *cli, char *pdu)
}
}
- if (!cli_check_sign_mac(cli, pdu)) {
+ mid = SVAL(pdu, smb_mid);
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ if (req->mid == mid) {
+ break;
+ }
+ }
+
+ if (!req) {
+ /* oplock breaks are not signed */
+ goto done;
+ }
+
+ if (!cli_check_sign_mac(cli, pdu, req->seqnum+1)) {
DEBUG(10, ("cli_check_sign_mac failed\n"));
return NT_STATUS_ACCESS_DENIED;
}
+done:
+ *_req = req;
+ *_mid = mid;
return NT_STATUS_OK;
}
@@ -863,7 +886,7 @@ static void handle_incoming_pdu(struct cli_state *cli)
{
struct cli_request *req, *next;
uint16_t mid;
- size_t raw_pdu_len, buf_len, pdu_len, rest_len;
+ size_t raw_pdu_len, buf_len, rest_len;
char *pdu;
int i;
NTSTATUS status;
@@ -923,23 +946,13 @@ static void handle_incoming_pdu(struct cli_state *cli)
}
}
- status = validate_smb_crypto(cli, pdu);
+ status = validate_smb_crypto(cli, pdu, &req, &mid);
if (!NT_STATUS_IS_OK(status)) {
goto invalidate_requests;
}
- mid = SVAL(pdu, smb_mid);
-
DEBUG(10, ("handle_incoming_pdu: got mid %d\n", mid));
- for (req = cli->outstanding_requests; req; req = req->next) {
- if (req->mid == mid) {
- break;
- }
- }
-
- pdu_len = smb_len(pdu) + 4;
-
if (req == NULL) {
DEBUG(3, ("Request for mid %d not found, dumping PDU\n", mid));
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index ebb01c44a6..aa1ca595a7 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -505,11 +505,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
ok = cli_simple_set_signing(cli, session_key, nt_response);
#endif
if (ok) {
- /* 'resign' the last message, so we get the right sequence numbers
- for checking the first reply from the server */
- cli_calculate_sign_mac(cli, cli->outbuf);
-
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
result = NT_STATUS_ACCESS_DENIED;
goto end;
}
@@ -747,11 +743,7 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
if (cli_simple_set_signing(
cli, session_key_krb5, data_blob_null)) {
- /* 'resign' the last message, so we get the right sequence numbers
- for checking the first reply from the server */
- cli_calculate_sign_mac(cli, cli->outbuf);
-
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
nt_status = NT_STATUS_ACCESS_DENIED;
goto nt_error;
}
@@ -873,11 +865,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
if (cli_simple_set_signing(
cli, ntlmssp_state->session_key, data_blob_null)) {
- /* 'resign' the last message, so we get the right sequence numbers
- for checking the first reply from the server */
- cli_calculate_sign_mac(cli, cli->outbuf);
-
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
nt_status = NT_STATUS_ACCESS_DENIED;
}
}
@@ -1540,13 +1528,16 @@ NTSTATUS cli_negprot_recv(struct async_req *req)
cli->protocol = prots[protnum].prot;
- if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
+ if ((cli->protocol < PROTOCOL_NT1) &&
+ client_is_signing_mandatory(cli)) {
DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
return NT_STATUS_ACCESS_DENIED;
}
if (cli->protocol >= PROTOCOL_NT1) {
struct timespec ts;
+ bool negotiated_smb_signing = false;
+
/* NT protocol */
cli->sec_mode = CVAL(vwv + 1, 0);
cli->max_mux = SVAL(vwv + 1, 1);
@@ -1579,22 +1570,24 @@ NTSTATUS cli_negprot_recv(struct async_req *req)
if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
/* Fail if server says signing is mandatory and we don't want to support it. */
- if (!cli->sign_info.allow_smb_signing) {
+ if (!client_is_signing_allowed(cli)) {
DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
return NT_STATUS_ACCESS_DENIED;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
- } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
+ negotiated_smb_signing = true;
+ } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
/* Fail if client says signing is mandatory and the server doesn't support it. */
if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
return NT_STATUS_ACCESS_DENIED;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
+ negotiated_smb_signing = true;
} else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
- cli->sign_info.negotiated_smb_signing = True;
+ negotiated_smb_signing = true;
+ }
+
+ if (negotiated_smb_signing) {
+ cli_set_signing_negotiated(cli);
}
if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
@@ -1841,10 +1834,9 @@ static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
tevent_req_set_callback(r445, smb_sock_connected, fd445);
tevent_req_set_callback(r139, smb_sock_connected, fd139);
- while ((fd139->fd == -1)
- && tevent_req_is_in_progress(r139)
- && (fd445->fd == -1)
- && tevent_req_is_in_progress(r445)) {
+ while ((fd445->fd == -1) && (fd139->fd == -1)
+ && (tevent_req_is_in_progress(r139)
+ || tevent_req_is_in_progress(r445))) {
event_loop_once(ev);
}
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index c1ba4e5c4f..6186387076 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -135,6 +135,79 @@ static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen)
return len;
}
+static bool cli_state_set_seqnum(struct cli_state *cli, uint16_t mid, uint32_t seqnum)
+{
+ struct cli_state_seqnum *c;
+
+ for (c = cli->seqnum; c; c = c->next) {
+ if (c->mid == mid) {
+ c->seqnum = seqnum;
+ return true;
+ }
+ }
+
+ c = talloc_zero(cli, struct cli_state_seqnum);
+ if (!c) {
+ return false;
+ }
+
+ c->mid = mid;
+ c->seqnum = seqnum;
+ c->persistent = false;
+ DLIST_ADD_END(cli->seqnum, c, struct cli_state_seqnum *);
+
+ return true;
+}
+
+bool cli_state_seqnum_persistent(struct cli_state *cli,
+ uint16_t mid)
+{
+ struct cli_state_seqnum *c;
+
+ for (c = cli->seqnum; c; c = c->next) {
+ if (c->mid == mid) {
+ c->persistent = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cli_state_seqnum_remove(struct cli_state *cli,
+ uint16_t mid)
+{
+ struct cli_state_seqnum *c;
+
+ for (c = cli->seqnum; c; c = c->next) {
+ if (c->mid == mid) {
+ DLIST_REMOVE(cli->seqnum, c);
+ TALLOC_FREE(c);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static uint32_t cli_state_get_seqnum(struct cli_state *cli, uint16_t mid)
+{
+ struct cli_state_seqnum *c;
+
+ for (c = cli->seqnum; c; c = c->next) {
+ if (c->mid == mid) {
+ uint32_t seqnum = c->seqnum;
+ if (!c->persistent) {
+ DLIST_REMOVE(cli->seqnum, c);
+ TALLOC_FREE(c);
+ }
+ return seqnum;
+ }
+ }
+
+ return 0;
+}
+
/****************************************************************************
Recv an smb.
****************************************************************************/
@@ -142,6 +215,8 @@ static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen)
bool cli_receive_smb(struct cli_state *cli)
{
ssize_t len;
+ uint16_t mid;
+ uint32_t seqnum;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
if (cli->fd == -1)
@@ -177,7 +252,10 @@ bool cli_receive_smb(struct cli_state *cli)
return false;
}
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ mid = SVAL(cli->inbuf,smb_mid);
+ seqnum = cli_state_get_seqnum(cli, mid);
+
+ if (!cli_check_sign_mac(cli, cli->inbuf, seqnum+1)) {
/*
* If we get a signature failure in sessionsetup, then
* the server sometimes just reflects the sent signature
@@ -264,12 +342,20 @@ bool cli_send_smb(struct cli_state *cli)
ssize_t ret;
char *buf_out = cli->outbuf;
bool enc_on = cli_encryption_on(cli);
+ uint32_t seqnum;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
if (cli->fd == -1)
return false;
- cli_calculate_sign_mac(cli, cli->outbuf);
+ cli_calculate_sign_mac(cli, cli->outbuf, &seqnum);
+
+ if (!cli_state_set_seqnum(cli, cli->mid, seqnum)) {
+ DEBUG(0,("Failed to store mid[%u]/seqnum[%u]\n",
+ (unsigned int)cli->mid,
+ (unsigned int)seqnum));
+ return false;
+ }
if (enc_on) {
NTSTATUS status = cli_encrypt_message(cli, cli->outbuf,
@@ -506,6 +592,7 @@ struct cli_state *cli_initialise_ex(int signing_state)
cli->bufsize = CLI_BUFFER_SIZE+4;
cli->max_xmit = cli->bufsize;
cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
+ cli->seqnum = 0;
cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
cli->oplock_handler = cli_oplock_ack;
cli->case_sensitive = false;
@@ -556,9 +643,12 @@ struct cli_state *cli_initialise_ex(int signing_state)
#endif
/* initialise signing */
- cli->sign_info.allow_smb_signing = allow_smb_signing;
- cli->sign_info.mandatory_signing = mandatory_signing;
- cli_null_set_signing(cli);
+ cli->signing_state = smb_signing_init(cli,
+ allow_smb_signing,
+ mandatory_signing);
+ if (!cli->signing_state) {
+ goto error;
+ }
cli->initialised = 1;
@@ -641,7 +731,6 @@ void cli_shutdown(struct cli_state *cli)
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
- cli_free_signing_context(cli);
data_blob_free(&cli->secblob);
data_blob_free(&cli->user_session_key);
@@ -740,7 +829,6 @@ static void cli_echo_recv_helper(struct async_req *req)
cli_req->data.echo.num_echos -= 1;
if (cli_req->data.echo.num_echos == 0) {
- client_set_trans_sign_state_off(cli_req->cli, cli_req->mid);
async_req_done(req);
return;
}
@@ -782,8 +870,6 @@ struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
}
req = talloc_get_type_abort(result->private_data, struct cli_request);
- client_set_trans_sign_state_on(cli, req->mid);
-
req->data.echo.num_echos = num_echos;
req->data.echo.data.data = talloc_move(req, &data_copy);
req->data.echo.data.length = data.length;
diff --git a/source3/libsmb/clisigning.c b/source3/libsmb/clisigning.c
new file mode 100644
index 0000000000..0d0e926e6c
--- /dev/null
+++ b/source3/libsmb/clisigning.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+bool cli_simple_set_signing(struct cli_state *cli,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ bool ok;
+
+ ok = smb_signing_activate(cli->signing_state,
+ user_session_key,
+ response);
+ if (!ok) {
+ return false;
+ }
+
+ cli->readbraw_supported = false;
+ cli->writebraw_supported = false;
+
+ return true;
+}
+
+bool cli_temp_set_signing(struct cli_state *cli)
+{
+ return smb_signing_set_bsrspyl(cli->signing_state);
+}
+
+void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum)
+{
+ *seqnum = smb_signing_next_seqnum(cli->signing_state, false);
+ smb_signing_sign_pdu(cli->signing_state, (uint8_t *)buf, *seqnum);
+}
+
+bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum)
+{
+ bool ok;
+
+ ok = smb_signing_check_pdu(cli->signing_state,
+ (const uint8_t *)buf,
+ seqnum);
+
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+void cli_set_signing_negotiated(struct cli_state *cli)
+{
+ smb_signing_set_negotiated(cli->signing_state);
+}
+
+bool client_is_signing_on(struct cli_state *cli)
+{
+ return smb_signing_is_active(cli->signing_state);
+}
+
+bool client_is_signing_allowed(struct cli_state *cli)
+{
+ return smb_signing_is_allowed(cli->signing_state);
+}
+
+bool client_is_signing_mandatory(struct cli_state *cli)
+{
+ return smb_signing_is_mandatory(cli->signing_state);
+}
diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c
index 0266c0307e..c566972b21 100644
--- a/source3/libsmb/clitrans.c
+++ b/source3/libsmb/clitrans.c
@@ -94,14 +94,12 @@ bool cli_send_trans(struct cli_state *cli, int trans,
return False;
}
- /* Note we're in a trans state. Save the sequence
- * numbers for replies. */
- client_set_trans_sign_state_on(cli, mid);
+ cli_state_seqnum_persistent(cli, mid);
if (this_ldata < ldata || this_lparam < lparam) {
/* receive interim response */
if (!cli_receive_smb(cli) || cli_is_error(cli)) {
- client_set_trans_sign_state_off(cli, mid);
+ cli_state_seqnum_remove(cli, mid);
return(False);
}
@@ -137,12 +135,11 @@ bool cli_send_trans(struct cli_state *cli, int trans,
show_msg(cli->outbuf);
- client_set_trans_sign_state_off(cli, mid);
cli->mid = mid;
if (!cli_send_smb(cli)) {
+ cli_state_seqnum_remove(cli, mid);
return False;
}
- client_set_trans_sign_state_on(cli, mid);
tot_data += this_ldata;
tot_param += this_lparam;
@@ -165,10 +162,14 @@ bool cli_receive_trans(struct cli_state *cli,int trans,
unsigned int this_data,this_param;
NTSTATUS status;
bool ret = False;
+ uint16_t mid;
*data_len = *param_len = 0;
+ mid = SVAL(cli->inbuf,smb_mid);
+
if (!cli_receive_smb(cli)) {
+ cli_state_seqnum_remove(cli, mid);
return False;
}
@@ -179,6 +180,7 @@ bool cli_receive_trans(struct cli_state *cli,int trans,
DEBUG(0,("Expected %s response, got command 0x%02x\n",
trans==SMBtrans?"SMBtrans":"SMBtrans2",
CVAL(cli->inbuf,smb_com)));
+ cli_state_seqnum_remove(cli, mid);
return False;
}
@@ -331,6 +333,8 @@ bool cli_receive_trans(struct cli_state *cli,int trans,
out:
+ cli_state_seqnum_remove(cli, mid);
+
if (ret) {
/* Ensure the last 2 bytes of param and data are 2 null
* bytes. These are malloc'ed, but not included in any
@@ -344,7 +348,6 @@ bool cli_receive_trans(struct cli_state *cli,int trans,
}
}
- client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
return ret;
}
@@ -412,14 +415,12 @@ bool cli_send_nt_trans(struct cli_state *cli,
return False;
}
- /* Note we're in a trans state. Save the sequence
- * numbers for replies. */
- client_set_trans_sign_state_on(cli, mid);
+ cli_state_seqnum_persistent(cli, mid);
if (this_ldata < ldata || this_lparam < lparam) {
/* receive interim response */
if (!cli_receive_smb(cli) || cli_is_error(cli)) {
- client_set_trans_sign_state_off(cli, mid);
+ cli_state_seqnum_remove(cli, mid);
return(False);
}
@@ -454,12 +455,11 @@ bool cli_send_nt_trans(struct cli_state *cli,
show_msg(cli->outbuf);
- client_set_trans_sign_state_off(cli, mid);
cli->mid = mid;
if (!cli_send_smb(cli)) {
+ cli_state_seqnum_remove(cli, mid);
return False;
}
- client_set_trans_sign_state_on(cli, mid);
tot_data += this_ldata;
tot_param += this_lparam;
@@ -483,10 +483,14 @@ bool cli_receive_nt_trans(struct cli_state *cli,
uint8 eclass;
uint32 ecode;
bool ret = False;
+ uint16_t mid;
*data_len = *param_len = 0;
+ mid = SVAL(cli->inbuf,smb_mid);
+
if (!cli_receive_smb(cli)) {
+ cli_state_seqnum_remove(cli, mid);
return False;
}
@@ -496,6 +500,7 @@ bool cli_receive_nt_trans(struct cli_state *cli,
if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
CVAL(cli->inbuf,smb_com)));
+ cli_state_seqnum_remove(cli, mid);
return(False);
}
@@ -669,6 +674,8 @@ bool cli_receive_nt_trans(struct cli_state *cli,
out:
+ cli_state_seqnum_remove(cli, mid);
+
if (ret) {
/* Ensure the last 2 bytes of param and data are 2 null
* bytes. These are malloc'ed, but not included in any
@@ -682,7 +689,6 @@ bool cli_receive_nt_trans(struct cli_state *cli,
}
}
- client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
return ret;
}
@@ -696,6 +702,7 @@ struct cli_trans_state {
struct event_context *ev;
uint8_t cmd;
uint16_t mid;
+ uint32_t seqnum;
const char *pipe_name;
uint16_t fid;
uint16_t function;
@@ -919,6 +926,7 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
cli_req = talloc_get_type_abort(result->private_data,
struct cli_request);
state->mid = cli_req->mid;
+ state->seqnum = cli_req->seqnum;
} else {
uint16_t num_bytes = talloc_get_size(bytes);
/*
@@ -939,12 +947,10 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
cli_req->recv_helper.fn = cli_trans_recv_helper;
cli_req->recv_helper.priv = state;
cli_req->mid = state->mid;
- client_set_trans_sign_state_off(state->cli, state->mid);
cli_chain_uncork(state->cli);
+ state->seqnum = cli_req->seqnum;
}
- client_set_trans_sign_state_on(state->cli, state->mid);
-
fail:
TALLOC_FREE(frame);
return result;
@@ -953,6 +959,8 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
static void cli_trans_ship_rest(struct async_req *req,
struct cli_trans_state *state)
{
+ struct cli_request *cli_req;
+
state->secondary_request_ctx = talloc_new(state);
if (state->secondary_request_ctx == NULL) {
async_req_nterror(req, NT_STATUS_NO_MEMORY);
@@ -961,14 +969,19 @@ static void cli_trans_ship_rest(struct async_req *req,
while ((state->param_sent < state->num_param)
|| (state->data_sent < state->num_data)) {
- struct async_req *cli_req;
+ struct async_req *subreq;
- cli_req = cli_ship_trans(state->secondary_request_ctx, state);
- if (cli_req == NULL) {
+ subreq = cli_ship_trans(state->secondary_request_ctx, state);
+ if (subreq == NULL) {
async_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
}
+
+ cli_req = talloc_get_type_abort(req->private_data,
+ struct cli_request);
+
+ cli_req->seqnum = state->seqnum;
}
static NTSTATUS cli_pull_trans(struct async_req *req,
@@ -1174,7 +1187,6 @@ static void cli_trans_recv_helper(struct async_req *req)
if ((state->rparam.total == state->rparam.received)
&& (state->rdata.total == state->rdata.received)) {
- client_set_trans_sign_state_off(state->cli, state->mid);
async_req_done(req);
}
}
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
index a3ed0e7572..32d2883965 100644
--- a/source3/libsmb/smb_signing.c
+++ b/source3/libsmb/smb_signing.c
@@ -1,8 +1,9 @@
-/*
+/*
Unix SMB/CIFS implementation.
SMB Signing Code
Copyright (C) Jeremy Allison 2003.
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,260 +21,89 @@
#include "includes.h"
-/* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
-struct outstanding_packet_lookup {
- struct outstanding_packet_lookup *prev, *next;
- uint16 mid;
- uint32 reply_seq_num;
- bool can_delete; /* Set to False in trans state. */
-};
+/* Used by the SMB signing functions. */
-struct smb_basic_signing_context {
- DATA_BLOB mac_key;
- uint32 send_seq_num;
- struct outstanding_packet_lookup *outstanding_packet_list;
-};
-
-static bool store_sequence_for_reply(struct outstanding_packet_lookup **list,
- uint16 mid, uint32 reply_seq_num)
-{
- struct outstanding_packet_lookup *t;
+struct smb_signing_state {
+ /* is signing localy allowed */
+ bool allowed;
- /* Ensure we only add a mid once. */
- for (t = *list; t; t = t->next) {
- if (t->mid == mid) {
- return False;
- }
- }
+ /* is signing localy mandatory */
+ bool mandatory;
- t = SMB_XMALLOC_P(struct outstanding_packet_lookup);
- ZERO_STRUCTP(t);
+ /* is signing negotiated by the peer */
+ bool negotiated;
- t->mid = mid;
- t->reply_seq_num = reply_seq_num;
- t->can_delete = True;
+ /* send BSRSPYL signatures */
+ bool bsrspyl;
- /*
- * Add to the *start* of the list not the end of the list.
- * This ensures that the *last* send sequence with this mid
- * is returned by preference.
- * This can happen if the mid wraps and one of the early
- * mid numbers didn't get a reply and is still lurking on
- * the list. JRA. Found by Fran Fabrizio <fran@cis.uab.edu>.
- */
+ bool active; /* Have I ever seen a validly signed packet? */
- DLIST_ADD(*list, t);
- DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n",
- (unsigned int)reply_seq_num, (unsigned int)mid ));
- return True;
-}
+ /* mac_key.length > 0 means signing is started */
+ DATA_BLOB mac_key;
-static bool get_sequence_for_reply(struct outstanding_packet_lookup **list,
- uint16 mid, uint32 *reply_seq_num)
-{
- struct outstanding_packet_lookup *t;
-
- for (t = *list; t; t = t->next) {
- if (t->mid == mid) {
- *reply_seq_num = t->reply_seq_num;
- DEBUG(10,("get_sequence_for_reply: found seq = %u mid = %u\n",
- (unsigned int)t->reply_seq_num, (unsigned int)t->mid ));
- if (t->can_delete) {
- DLIST_REMOVE(*list, t);
- SAFE_FREE(t);
- }
- return True;
- }
- }
- return False;
-}
+ /* the next expected seqnum */
+ uint32_t seqnum;
+};
-static bool set_sequence_can_delete_flag(struct outstanding_packet_lookup **list, uint16 mid, bool can_delete_entry)
+static void smb_signing_reset_info(struct smb_signing_state *si)
{
- struct outstanding_packet_lookup *t;
-
- for (t = *list; t; t = t->next) {
- if (t->mid == mid) {
- t->can_delete = can_delete_entry;
- return True;
- }
- }
- return False;
+ si->active = false;
+ si->bsrspyl = false;
+ data_blob_free(&si->mac_key);
+ si->seqnum = 0;
}
-/***********************************************************
- SMB signing - Common code before we set a new signing implementation
-************************************************************/
-
-static bool cli_set_smb_signing_common(struct cli_state *cli)
+struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool mandatory)
{
- if (!cli->sign_info.allow_smb_signing) {
- return False;
- }
+ struct smb_signing_state *si;
- if (!cli->sign_info.negotiated_smb_signing
- && !cli->sign_info.mandatory_signing) {
- return False;
+ si = talloc_zero(mem_ctx, struct smb_signing_state);
+ if (si == NULL) {
+ return NULL;
}
- if (cli->sign_info.doing_signing) {
- return False;
+ if (mandatory) {
+ allowed = true;
}
- if (cli->sign_info.free_signing_context)
- cli->sign_info.free_signing_context(&cli->sign_info);
-
- /* These calls are INCOMPATIBLE with SMB signing */
- cli->readbraw_supported = False;
- cli->writebraw_supported = False;
-
- return True;
-}
-
-/***********************************************************
- SMB signing - Common code for 'real' implementations
-************************************************************/
-
-static bool set_smb_signing_real_common(struct smb_sign_info *si)
-{
- if (si->mandatory_signing) {
- DEBUG(5, ("Mandatory SMB signing enabled!\n"));
- }
-
- si->doing_signing = True;
- DEBUG(5, ("SMB signing enabled!\n"));
-
- return True;
-}
-
-static void mark_packet_signed(char *outbuf)
-{
- uint16 flags2;
- flags2 = SVAL(outbuf,smb_flg2);
- flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
- SSVAL(outbuf,smb_flg2, flags2);
-}
-
-/***********************************************************
- SMB signing - NULL implementation - calculate a MAC to send.
-************************************************************/
-
-static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
-{
- /* we can't zero out the sig, as we might be trying to send a
- session request - which is NBT-level, not SMB level and doesn't
- have the field */
- return;
-}
-
-/***********************************************************
- SMB signing - NULL implementation - check a MAC sent by server.
-************************************************************/
-
-static bool null_check_incoming_message(const char *inbuf,
- struct smb_sign_info *si,
- bool must_be_ok)
-{
- return True;
-}
-
-/***********************************************************
- SMB signing - NULL implementation - free signing context
-************************************************************/
-
-static void null_free_signing_context(struct smb_sign_info *si)
-{
- return;
-}
-
-/**
- SMB signing - NULL implementation - setup the MAC key.
-
- @note Used as an initialisation only - it will not correctly
- shut down a real signing mechanism
-*/
-
-static bool null_set_signing(struct smb_sign_info *si)
-{
- si->signing_context = NULL;
-
- si->sign_outgoing_message = null_sign_outgoing_message;
- si->check_incoming_message = null_check_incoming_message;
- si->free_signing_context = null_free_signing_context;
-
- return True;
-}
-
-/**
- * Free the signing context
- */
-
-static void free_signing_context(struct smb_sign_info *si)
-{
- if (si->free_signing_context) {
- si->free_signing_context(si);
- si->signing_context = NULL;
- }
+ si->allowed = allowed;
+ si->mandatory = mandatory;
- null_set_signing(si);
+ return si;
}
-
-static bool signing_good(const char *inbuf, struct smb_sign_info *si,
- bool good, uint32 seq, bool must_be_ok)
+static bool smb_signing_good(struct smb_signing_state *si,
+ bool good, uint32_t seq)
{
if (good) {
-
- if (!si->doing_signing) {
- si->doing_signing = True;
+ if (!si->active) {
+ si->active = true;
}
+ return true;
+ }
- if (!si->seen_valid) {
- si->seen_valid = True;
- }
-
- } else {
- if (!si->mandatory_signing && !si->seen_valid) {
-
- if (!must_be_ok) {
- return True;
- }
- /* Non-mandatory signing - just turn off if this is the first bad packet.. */
- DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and peer\n"
- "isn't sending correct signatures. Turning off.\n"));
- si->negotiated_smb_signing = False;
- si->allow_smb_signing = False;
- si->doing_signing = False;
- free_signing_context(si);
- return True;
- } else if (!must_be_ok) {
- /* This packet is known to be unsigned */
- return True;
- } else {
- /* Mandatory signing or bad packet after signing started - fail and disconnect. */
- if (seq)
- DEBUG(0, ("signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
- return False;
- }
+ if (!si->mandatory && !si->active) {
+ /* Non-mandatory signing - just turn off if this is the first bad packet.. */
+ DEBUG(5, ("smb_signing_good: signing negotiated but not required and peer\n"
+ "isn't sending correct signatures. Turning off.\n"));
+ smb_signing_reset_info(si);
+ return true;
}
- return True;
-}
-/***********************************************************
- SMB signing - Simple implementation - calculate a MAC on the packet
-************************************************************/
+ /* Mandatory signing or bad packet after signing started - fail and disconnect. */
+ DEBUG(0, ("smb_signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
+ return false;
+}
-static void simple_packet_signature(struct smb_basic_signing_context *data,
- const uchar *buf, uint32 seq_number,
- unsigned char calc_md5_mac[16])
+static void smb_signing_md5(const DATA_BLOB *mac_key,
+ const uint8_t *buf, uint32_t seq_number,
+ uint8_t calc_md5_mac[16])
{
const size_t offset_end_of_sig = (smb_ss_field + 8);
- unsigned char sequence_buf[8];
+ uint8_t sequence_buf[8];
struct MD5Context md5_ctx;
-#if 0
- /* JRA - apparently this is incorrect. */
- unsigned char key_buf[16];
-#endif
/*
* Firstly put the sequence number into the first 4 bytes.
@@ -282,7 +112,7 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
* We do this here, to avoid modifying the packet.
*/
- DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number ));
+ DEBUG(10,("smb_signing_md5: sequence number %u\n", seq_number ));
SIVAL(sequence_buf, 0, seq_number);
SIVAL(sequence_buf, 4, 0);
@@ -295,17 +125,7 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
MD5Init(&md5_ctx);
/* intialise with the key */
- MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length);
-#if 0
- /* JRA - apparently this is incorrect. */
- /* NB. When making and verifying SMB signatures, Windows apparently
- zero-pads the key to 128 bits if it isn't long enough.
- From Nalin Dahyabhai <nalin@redhat.com> */
- if (data->mac_key.length < sizeof(key_buf)) {
- memset(key_buf, 0, sizeof(key_buf));
- MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length);
- }
-#endif
+ MD5Update(&md5_ctx, mac_key->data, mac_key->length);
/* copy in the first bit of the SMB header */
MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
@@ -317,690 +137,234 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
MD5Update(&md5_ctx, buf + offset_end_of_sig,
smb_len(buf) - (offset_end_of_sig - 4));
- /* calculate the MD5 sig */
+ /* calculate the MD5 sig */
MD5Final(calc_md5_mac, &md5_ctx);
}
-
-/***********************************************************
- SMB signing - Client implementation - send the MAC.
-************************************************************/
-
-static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
-{
- unsigned char calc_md5_mac[16];
- struct smb_basic_signing_context *data =
- (struct smb_basic_signing_context *)si->signing_context;
-
- if (!si->doing_signing)
- return;
-
- /* JRA Paranioa test - we should be able to get rid of this... */
- if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
- DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
- smb_len(outbuf) ));
- abort();
- }
-
- /* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(outbuf);
-
- simple_packet_signature(data, (const unsigned char *)outbuf,
- data->send_seq_num, calc_md5_mac);
-
- DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
- dump_data(10, calc_md5_mac, 8);
-
- memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
-
-/* cli->outbuf[smb_ss_field+2]=0;
- Uncomment this to test if the remote server actually verifies signatures...*/
-
- /* Instead of re-introducing the trans_info_conect we
- used to have here, we use the fact that during a
- SMBtrans/SMBtrans2/SMBnttrans send that the mid stays
- constant. This means that calling store_sequence_for_reply()
- will return False for all trans secondaries, as the mid is already
- on the stored sequence list. As the send_seqence_number must
- remain constant for all primary+secondary trans sends, we
- only increment the send sequence number when we successfully
- add a new entry to the outstanding sequence list. This means
- I can isolate the fix here rather than re-adding the trans
- signing on/off calls in libsmb/clitrans2.c JRA.
- */
-
- if (store_sequence_for_reply(&data->outstanding_packet_list, SVAL(outbuf,smb_mid), data->send_seq_num + 1)) {
- data->send_seq_num += 2;
- }
-}
-
-/***********************************************************
- SMB signing - Client implementation - check a MAC sent by server.
-************************************************************/
-
-static bool client_check_incoming_message(const char *inbuf,
- struct smb_sign_info *si,
- bool must_be_ok)
+uint32_t smb_signing_next_seqnum(struct smb_signing_state *si, bool oneway)
{
- bool good;
- uint32 reply_seq_number;
- unsigned char calc_md5_mac[16];
- unsigned char *server_sent_mac;
-
- struct smb_basic_signing_context *data =
- (struct smb_basic_signing_context *)si->signing_context;
+ uint32_t seqnum;
- if (!si->doing_signing)
- return True;
-
- if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
- DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
- return False;
+ if (si->mac_key.length == 0) {
+ return 0;
}
- if (!get_sequence_for_reply(&data->outstanding_packet_list, SVAL(inbuf, smb_mid), &reply_seq_number)) {
- DEBUG(1, ("client_check_incoming_message: received message "
- "with mid %u with no matching send record.\n", (unsigned int)SVAL(inbuf, smb_mid) ));
- return False;
- }
-
- simple_packet_signature(data, (const unsigned char *)inbuf,
- reply_seq_number, calc_md5_mac);
-
- server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
- good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
-
- if (!good) {
- DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
- dump_data(5, calc_md5_mac, 8);
-
- DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
- dump_data(5, server_sent_mac, 8);
-#if 1 /* JRATEST */
- {
- int i;
- for (i = -5; i < 5; i++) {
- simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac);
- if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
- DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \
-We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
- break;
- }
- }
- }
-#endif /* JRATEST */
-
+ seqnum = si->seqnum;
+ if (oneway) {
+ si->seqnum += 1;
} else {
- DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
- dump_data(10, server_sent_mac, 8);
- }
- return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
-}
-
-/***********************************************************
- SMB signing - Simple implementation - free signing context
-************************************************************/
-
-static void simple_free_signing_context(struct smb_sign_info *si)
-{
- struct smb_basic_signing_context *data =
- (struct smb_basic_signing_context *)si->signing_context;
- struct outstanding_packet_lookup *list;
- struct outstanding_packet_lookup *next;
-
- for (list = data->outstanding_packet_list; list; list = next) {
- next = list->next;
- DLIST_REMOVE(data->outstanding_packet_list, list);
- SAFE_FREE(list);
+ si->seqnum += 2;
}
- data_blob_free(&data->mac_key);
-
- SAFE_FREE(si->signing_context);
-
- return;
+ return seqnum;
}
-/***********************************************************
- SMB signing - Simple implementation - setup the MAC key.
-************************************************************/
-
-bool cli_simple_set_signing(struct cli_state *cli,
- const DATA_BLOB user_session_key,
- const DATA_BLOB response)
+void smb_signing_cancel_reply(struct smb_signing_state *si, bool oneway)
{
- struct smb_basic_signing_context *data;
-
- if (!user_session_key.length)
- return False;
-
- if (!cli_set_smb_signing_common(cli)) {
- return False;
- }
-
- if (!set_smb_signing_real_common(&cli->sign_info)) {
- return False;
+ if (si->mac_key.length == 0) {
+ return;
}
- data = SMB_XMALLOC_P(struct smb_basic_signing_context);
- memset(data, '\0', sizeof(*data));
-
- cli->sign_info.signing_context = data;
-
- data->mac_key = data_blob(NULL, response.length + user_session_key.length);
-
- memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
-
- DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
- dump_data(10, user_session_key.data, user_session_key.length);
-
- if (response.length) {
- memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
- DEBUG(10, ("cli_simple_set_signing: response_data\n"));
- dump_data(10, response.data, response.length);
+ if (oneway) {
+ si->seqnum -= 1;
} else {
- DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
+ si->seqnum -= 2;
}
-
- dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
-
- /* Initialise the sequence number */
- data->send_seq_num = 0;
-
- /* Initialise the list of outstanding packets */
- data->outstanding_packet_list = NULL;
-
- cli->sign_info.sign_outgoing_message = client_sign_outgoing_message;
- cli->sign_info.check_incoming_message = client_check_incoming_message;
- cli->sign_info.free_signing_context = simple_free_signing_context;
-
- return True;
}
-/***********************************************************
- SMB signing - TEMP implementation - calculate a MAC to send.
-************************************************************/
-
-static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
+void smb_signing_sign_pdu(struct smb_signing_state *si,
+ uint8_t *outbuf, uint32_t seqnum)
{
- /* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(outbuf);
-
- /* I wonder what BSRSPYL stands for - but this is what MS
- actually sends! */
- memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
- return;
-}
-
-/***********************************************************
- SMB signing - TEMP implementation - check a MAC sent by server.
-************************************************************/
+ uint8_t calc_md5_mac[16];
+ uint16_t flags2;
-static bool temp_check_incoming_message(const char *inbuf,
- struct smb_sign_info *si, bool foo)
-{
- return True;
-}
-
-/***********************************************************
- SMB signing - TEMP implementation - free signing context
-************************************************************/
-
-static void temp_free_signing_context(struct smb_sign_info *si)
-{
- return;
-}
-
-/***********************************************************
- SMB signing - NULL implementation - setup the MAC key.
-************************************************************/
-
-bool cli_null_set_signing(struct cli_state *cli)
-{
- return null_set_signing(&cli->sign_info);
-}
-
-/***********************************************************
- SMB signing - temp implementation - setup the MAC key.
-************************************************************/
-
-bool cli_temp_set_signing(struct cli_state *cli)
-{
- if (!cli_set_smb_signing_common(cli)) {
- return False;
- }
-
- cli->sign_info.signing_context = NULL;
-
- cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message;
- cli->sign_info.check_incoming_message = temp_check_incoming_message;
- cli->sign_info.free_signing_context = temp_free_signing_context;
-
- return True;
-}
-
-void cli_free_signing_context(struct cli_state *cli)
-{
- free_signing_context(&cli->sign_info);
-}
-
-/**
- * Sign a packet with the current mechanism
- */
-
-void cli_calculate_sign_mac(struct cli_state *cli, char *buf)
-{
- cli->sign_info.sign_outgoing_message(buf, &cli->sign_info);
-}
-
-/**
- * Check a packet with the current mechanism
- * @return False if we had an established signing connection
- * which had a bad checksum, True otherwise.
- */
-
-bool cli_check_sign_mac(struct cli_state *cli, char *buf)
-{
- if (!cli->sign_info.check_incoming_message(buf, &cli->sign_info, True)) {
- free_signing_context(&cli->sign_info);
- return False;
- }
- return True;
-}
-
-/***********************************************************
- Enter trans/trans2/nttrans state.
-************************************************************/
-
-bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid)
-{
- struct smb_sign_info *si = &cli->sign_info;
- struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
-
- if (!si->doing_signing) {
- return True;
- }
-
- if (!data) {
- return False;
- }
-
- if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, False)) {
- return False;
- }
-
- return True;
-}
-
-/***********************************************************
- Leave trans/trans2/nttrans state.
-************************************************************/
-
-bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
-{
- uint32 reply_seq_num;
- struct smb_sign_info *si = &cli->sign_info;
- struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
-
- if (!si->doing_signing) {
- return True;
- }
-
- if (!data) {
- return False;
- }
-
- if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, True)) {
- return False;
- }
-
- /* Now delete the stored mid entry. */
- if (!get_sequence_for_reply(&data->outstanding_packet_list, mid, &reply_seq_num)) {
- return False;
- }
-
- return True;
-}
-
-/***********************************************************
- Is client signing on ?
-************************************************************/
-
-bool client_is_signing_on(struct cli_state *cli)
-{
- struct smb_sign_info *si = &cli->sign_info;
- return si->doing_signing;
-}
-
-/***********************************************************
- SMB signing - Server implementation - send the MAC.
-************************************************************/
-
-static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
-{
- unsigned char calc_md5_mac[16];
- struct smb_basic_signing_context *data =
- (struct smb_basic_signing_context *)si->signing_context;
- uint32 send_seq_number = data->send_seq_num-1;
- uint16 mid;
-
- if (!si->doing_signing) {
- return;
+ if (si->mac_key.length == 0) {
+ if (!si->bsrspyl) {
+ return;
+ }
}
/* JRA Paranioa test - we should be able to get rid of this... */
if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
- DEBUG(1, ("srv_sign_outgoing_message: Logic error. Can't send signature on short packet! smb_len = %u\n",
- smb_len(outbuf) ));
+ DEBUG(1,("smb_signing_sign_pdu: Logic error. "
+ "Can't check signature on short packet! smb_len = %u\n",
+ smb_len(outbuf)));
abort();
}
/* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(outbuf);
-
- mid = SVAL(outbuf, smb_mid);
-
- /* See if this is a reply for a deferred packet. */
- get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
+ flags2 = SVAL(outbuf,smb_flg2);
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ SSVAL(outbuf, smb_flg2, flags2);
- simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_number, calc_md5_mac);
+ if (si->bsrspyl) {
+ /* I wonder what BSRSPYL stands for - but this is what MS
+ actually sends! */
+ memcpy(calc_md5_mac, "BSRSPYL ", 8);
+ } else {
+ smb_signing_md5(&si->mac_key, outbuf,
+ seqnum, calc_md5_mac);
+ }
- DEBUG(10, ("srv_sign_outgoing_message: seq %u: sent SMB signature of\n", (unsigned int)send_seq_number));
+ DEBUG(10, ("smb_signing_sign_pdu: sent SMB signature of\n"));
dump_data(10, calc_md5_mac, 8);
memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
-/* cli->outbuf[smb_ss_field+2]=0;
- Uncomment this to test if the remote client actually verifies signatures...*/
+/* outbuf[smb_ss_field+2]=0;
+ Uncomment this to test if the remote server actually verifies signatures...*/
}
-/***********************************************************
- SMB signing - Server implementation - check a MAC sent by server.
-************************************************************/
-
-static bool srv_check_incoming_message(const char *inbuf,
- struct smb_sign_info *si,
- bool must_be_ok)
+bool smb_signing_check_pdu(struct smb_signing_state *si,
+ const uint8_t *inbuf, uint32_t seqnum)
{
bool good;
- struct smb_basic_signing_context *data =
- (struct smb_basic_signing_context *)si->signing_context;
- uint32 reply_seq_number = data->send_seq_num;
- uint32 saved_seq;
- unsigned char calc_md5_mac[16];
- unsigned char *server_sent_mac;
+ uint8_t calc_md5_mac[16];
+ const uint8_t *reply_sent_mac;
- if (!si->doing_signing)
- return True;
+ if (si->mac_key.length == 0) {
+ return true;
+ }
if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
- DEBUG(1, ("srv_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
+ DEBUG(1,("smb_signing_check_pdu: Can't check signature "
+ "on short packet! smb_len = %u\n",
+ smb_len(inbuf)));
return False;
}
- /* We always increment the sequence number. */
- data->send_seq_num += 2;
-
- saved_seq = reply_seq_number;
- simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+ smb_signing_md5(&si->mac_key, inbuf,
+ seqnum, calc_md5_mac);
- server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
- good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
+ reply_sent_mac = &inbuf[smb_ss_field];
+ good = (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0);
if (!good) {
+ int i;
+ const int sign_range = 5;
- if (saved_seq) {
- DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
- (unsigned int)saved_seq));
- dump_data(5, calc_md5_mac, 8);
-
- DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
- (unsigned int)reply_seq_number));
- dump_data(5, server_sent_mac, 8);
- }
+ DEBUG(5, ("smb_signing_check_pdu: BAD SIG: wanted SMB signature of\n"));
+ dump_data(5, calc_md5_mac, 8);
-#if 1 /* JRATEST */
- {
- int i;
- reply_seq_number -= 5;
- for (i = 0; i < 10; i++, reply_seq_number++) {
- simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
- if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
- DEBUG(0,("srv_check_incoming_message: out of seq. seq num %u matches. \
-We were expecting seq %u\n", reply_seq_number, saved_seq ));
- break;
- }
+ DEBUG(5, ("smb_signing_check_pdu: BAD SIG: got SMB signature of\n"));
+ dump_data(5, reply_sent_mac, 8);
+
+ for (i = -sign_range; i < sign_range; i++) {
+ smb_signing_md5(&si->mac_key, inbuf,
+ seqnum+i, calc_md5_mac);
+ if (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0) {
+ DEBUG(0,("smb_signing_check_pdu: "
+ "out of seq. seq num %u matches. "
+ "We were expecting seq %u\n",
+ (unsigned int)seqnum+i,
+ (unsigned int)seqnum));
+ break;
}
}
-#endif /* JRATEST */
-
} else {
- DEBUG(10, ("srv_check_incoming_message: seq %u: (current is %u) got good SMB signature of\n", (unsigned int)reply_seq_number, (unsigned int)data->send_seq_num));
- dump_data(10, server_sent_mac, 8);
+ DEBUG(10, ("smb_signing_check_pdu: seq %u: "
+ "got good SMB signature of\n",
+ (unsigned int)seqnum));
+ dump_data(10, reply_sent_mac, 8);
}
- return (signing_good(inbuf, si, good, saved_seq, must_be_ok));
+ return smb_signing_good(si, good, seqnum);
}
-/***********************************************************
- SMB signing - server API's.
-************************************************************/
-
-static struct smb_sign_info srv_sign_info = {
- null_sign_outgoing_message,
- null_check_incoming_message,
- null_free_signing_context,
- NULL,
- False,
- False,
- False,
- False
-};
-
-/***********************************************************
- Turn signing off or on for oplock break code.
-************************************************************/
-
-bool srv_oplock_set_signing(bool onoff)
+bool smb_signing_set_bsrspyl(struct smb_signing_state *si)
{
- bool ret = srv_sign_info.doing_signing;
- srv_sign_info.doing_signing = onoff;
- return ret;
-}
-
-/***********************************************************
- Called to validate an incoming packet from the client.
-************************************************************/
-
-bool srv_check_sign_mac(const char *inbuf, bool must_be_ok)
-{
- /* Check if it's a non-session message. */
- if(CVAL(inbuf,0)) {
- return True;
+ if (!si->negotiated) {
+ return false;
}
- return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info, must_be_ok);
-}
-
-/***********************************************************
- Called to sign an outgoing packet to the client.
-************************************************************/
-
-void srv_calculate_sign_mac(char *outbuf)
-{
- /* Check if it's a non-session message. */
- if(CVAL(outbuf,0)) {
- return;
+ if (si->active) {
+ return false;
}
- srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info);
-}
+ si->bsrspyl = true;
-/***********************************************************
- Called by server to defer an outgoing packet.
-************************************************************/
+ return true;
+}
-void srv_defer_sign_response(uint16 mid)
+bool smb_signing_activate(struct smb_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
{
- struct smb_basic_signing_context *data;
-
- if (!srv_sign_info.doing_signing)
- return;
+ size_t len;
+ off_t ofs;
- data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
+ if (!user_session_key.length) {
+ return false;
+ }
- if (!data)
- return;
+ if (!si->negotiated) {
+ return false;
+ }
- /*
- * Ensure we only store this mid reply once...
- */
+ if (si->active) {
+ return false;
+ }
- store_sequence_for_reply(&data->outstanding_packet_list, mid,
- data->send_seq_num-1);
-}
+ if (si->mac_key.length > 0) {
+ return false;
+ }
-/***********************************************************
- Called to remove sequence records when a deferred packet is
- cancelled by mid. This should never find one....
-************************************************************/
+ smb_signing_reset_info(si);
-void srv_cancel_sign_response(uint16 mid, bool cancel)
-{
- struct smb_basic_signing_context *data;
- uint32 dummy_seq;
+ len = response.length + user_session_key.length;
+ si->mac_key = data_blob_talloc(si, NULL, len);
- if (!srv_sign_info.doing_signing)
- return;
+ ofs = 0;
+ memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length);
- data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
+ DEBUG(10, ("smb_signing_activate: user_session_key\n"));
+ dump_data(10, user_session_key.data, user_session_key.length);
- if (!data)
- return;
+ if (response.length) {
+ ofs = user_session_key.length;
+ memcpy(&si->mac_key.data[ofs], response.data, response.length);
+ DEBUG(10, ("smb_signing_activate: response_data\n"));
+ dump_data(10, response.data, response.length);
+ } else {
+ DEBUG(10, ("smb_signing_activate: NULL response_data\n"));
+ }
- DEBUG(10,("srv_cancel_sign_response: for mid %u\n", (unsigned int)mid ));
+ dump_data_pw("smb_signing_activate: mac key is:\n",
+ si->mac_key.data, si->mac_key.length);
- while (get_sequence_for_reply(&data->outstanding_packet_list, mid, &dummy_seq))
- ;
+ /* Initialise the sequence number */
+ si->seqnum = 2;
- /* cancel doesn't send a reply so doesn't burn a sequence number. */
- if (cancel) {
- data->send_seq_num -= 1;
- }
+ return true;
}
-/***********************************************************
- Called by server negprot when signing has been negotiated.
-************************************************************/
-
-void srv_set_signing_negotiated(void)
+bool smb_signing_is_active(struct smb_signing_state *si)
{
- srv_sign_info.allow_smb_signing = True;
- srv_sign_info.negotiated_smb_signing = True;
- if (lp_server_signing() == Required)
- srv_sign_info.mandatory_signing = True;
-
- srv_sign_info.sign_outgoing_message = temp_sign_outgoing_message;
- srv_sign_info.check_incoming_message = temp_check_incoming_message;
- srv_sign_info.free_signing_context = temp_free_signing_context;
+ return si->active;
}
-/***********************************************************
- Returns whether signing is active. We can't use sendfile or raw
- reads/writes if it is.
-************************************************************/
-
-bool srv_is_signing_active(void)
+bool smb_signing_is_allowed(struct smb_signing_state *si)
{
- return srv_sign_info.doing_signing;
+ return si->allowed;
}
-
-/***********************************************************
- Returns whether signing is negotiated. We can't use it unless it was
- in the negprot.
-************************************************************/
-
-bool srv_is_signing_negotiated(void)
+bool smb_signing_is_mandatory(struct smb_signing_state *si)
{
- return srv_sign_info.negotiated_smb_signing;
+ return si->mandatory;
}
-/***********************************************************
- Returns whether signing is actually happening
-************************************************************/
-
-bool srv_signing_started(void)
+bool smb_signing_set_negotiated(struct smb_signing_state *si)
{
- struct smb_basic_signing_context *data;
-
- if (!srv_sign_info.doing_signing) {
- return False;
+ if (!si->allowed) {
+ return false;
}
- data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
- if (!data)
- return False;
+ si->negotiated = true;
- if (data->send_seq_num == 0) {
- return False;
- }
-
- return True;
+ return true;
}
-/***********************************************************
- Turn on signing from this packet onwards.
-************************************************************/
-
-void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response)
+bool smb_signing_is_negotiated(struct smb_signing_state *si)
{
- struct smb_basic_signing_context *data;
-
- if (!user_session_key.length)
- return;
-
- if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) {
- DEBUG(5,("srv_set_signing: signing negotiated = %u, mandatory_signing = %u. Not allowing smb signing.\n",
- (unsigned int)srv_sign_info.negotiated_smb_signing,
- (unsigned int)srv_sign_info.mandatory_signing ));
- return;
- }
-
- /* Once we've turned on, ignore any more sessionsetups. */
- if (srv_sign_info.doing_signing) {
- return;
- }
-
- if (srv_sign_info.free_signing_context)
- srv_sign_info.free_signing_context(&srv_sign_info);
-
- srv_sign_info.doing_signing = True;
-
- data = SMB_XMALLOC_P(struct smb_basic_signing_context);
- memset(data, '\0', sizeof(*data));
-
- srv_sign_info.signing_context = data;
-
- data->mac_key = data_blob(NULL, response.length + user_session_key.length);
-
- memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
- if (response.length)
- memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
-
- dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
-
- DEBUG(3,("srv_set_signing: turning on SMB signing: signing negotiated = %s, mandatory_signing = %s.\n",
- BOOLSTR(srv_sign_info.negotiated_smb_signing),
- BOOLSTR(srv_sign_info.mandatory_signing) ));
-
- /* Initialise the sequence number */
- data->send_seq_num = 0;
-
- /* Initialise the list of outstanding packets */
- data->outstanding_packet_list = NULL;
-
- srv_sign_info.sign_outgoing_message = srv_sign_outgoing_message;
- srv_sign_info.check_incoming_message = srv_check_incoming_message;
- srv_sign_info.free_signing_context = simple_free_signing_context;
+ return si->negotiated;
}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index f49a1bc4c9..8460fea567 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -9572,15 +9572,20 @@ uint32 lp_get_spoolss_state( void )
Ensure we don't use sendfile if server smb signing is active.
********************************************************************/
-bool lp_use_sendfile(int snum)
+bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
{
+ bool sign_active = false;
+
/* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
if (Protocol < PROTOCOL_NT1) {
- return False;
+ return false;
+ }
+ if (signing_state) {
+ sign_active = smb_signing_is_active(signing_state);
}
return (_lp_use_sendfile(snum) &&
(get_remote_arch() != RA_WIN95) &&
- !srv_is_signing_active());
+ !sign_active);
}
/*******************************************************************
diff --git a/source3/selftest/tests.sh b/source3/selftest/tests.sh
index f88dab0337..ea59f0ee8e 100755
--- a/source3/selftest/tests.sh
+++ b/source3/selftest/tests.sh
@@ -120,6 +120,10 @@ plantest "blackbox.smbclient_s3.plain" dc BINDIR="$BINDIR" script/tests/test_smb
plantest "blackbox.smbclient_s3.plain member creds" member BINDIR="$BINDIR" script/tests/test_smbclient_s3.sh \$SERVER \$SERVER_IP \$SERVER\\\\\$USERNAME \$PASSWORD
plantest "blackbox.smbclient_s3.plain domain creds" member BINDIR="$BINDIR" script/tests/test_smbclient_s3.sh \$SERVER \$SERVER_IP \$DOMAIN\\\\\$DC_USERNAME \$DC_PASSWORD
+# sign, only the member server allows signing
+plantest "blackbox.smbclient_s3.sign member creds" member BINDIR="$BINDIR" script/tests/test_smbclient_s3.sh \$SERVER \$SERVER_IP \$SERVER\\\\\$USERNAME \$PASSWORD "--signing=required"
+plantest "blackbox.smbclient_s3.sign domain creds" member BINDIR="$BINDIR" script/tests/test_smbclient_s3.sh \$SERVER \$SERVER_IP \$DOMAIN\\\\\$DC_USERNAME \$DC_PASSWORD "--signing=required"
+
# encrypted
plantest "blackbox.smbclient_s3.crypt" dc BINDIR="$BINDIR" script/tests/test_smbclient_s3.sh \$SERVER \$SERVER_IP \$USERNAME \$PASSWORD "-e"
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index cfa4b430eb..77616be48c 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -197,7 +197,6 @@ bool schedule_aio_read_and_X(connection_struct *conn,
fsp->fsp_name, (double)startpos, (unsigned int)smb_maxcnt,
(unsigned int)aio_ex->req->mid ));
- srv_defer_sign_response(aio_ex->req->mid);
outstanding_aio_calls++;
return True;
}
@@ -303,6 +302,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
show_msg(aio_ex->outbuf);
if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
+ true, aio_ex->req->seqnum+1,
IS_CONN_ENCRYPTED(fsp->conn),
&req->pcd)) {
exit_server_cleanly("handle_aio_write: srv_send_smb "
@@ -310,8 +310,6 @@ bool schedule_aio_write_and_X(connection_struct *conn,
}
DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
"behind for file %s\n", fsp->fsp_name ));
- } else {
- srv_defer_sign_response(aio_ex->req->mid);
}
outstanding_aio_calls++;
@@ -347,7 +345,6 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
/* If errno is ECANCELED then don't return anything to the
* client. */
if (errno == ECANCELED) {
- srv_cancel_sign_response(aio_ex->req->mid, false);
return 0;
}
@@ -378,6 +375,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
smb_setlen(outbuf,outsize - 4);
show_msg(outbuf);
if (!srv_send_smb(smbd_server_fd(),outbuf,
+ true, aio_ex->req->seqnum+1,
IS_CONN_ENCRYPTED(aio_ex->fsp->conn), NULL)) {
exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
"failed.");
@@ -441,7 +439,6 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
/* If errno is ECANCELED then don't return anything to the
* client. */
if (errno == ECANCELED) {
- srv_cancel_sign_response(aio_ex->req->mid, false);
return 0;
}
@@ -475,7 +472,9 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
}
show_msg(outbuf);
- if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn),
+ if (!srv_send_smb(smbd_server_fd(),outbuf,
+ true, aio_ex->req->seqnum+1,
+ IS_CONN_ENCRYPTED(fsp->conn),
NULL)) {
exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
}
@@ -534,7 +533,6 @@ void smbd_aio_complete_mid(unsigned int mid)
if (!aio_ex) {
DEBUG(3,("smbd_aio_complete_mid: Can't find record to "
"match mid %u.\n", mid));
- srv_cancel_sign_response(mid, false);
return;
}
@@ -544,7 +542,6 @@ void smbd_aio_complete_mid(unsigned int mid)
* ignore. */
DEBUG( 3,( "smbd_aio_complete_mid: file closed whilst "
"aio outstanding (mid[%u]).\n", mid));
- srv_cancel_sign_response(mid, false);
return;
}
diff --git a/source3/smbd/avahi_register.c b/source3/smbd/avahi_register.c
new file mode 100644
index 0000000000..1903b0ef96
--- /dev/null
+++ b/source3/smbd/avahi_register.c
@@ -0,0 +1,170 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Register _smb._tcp with avahi
+ *
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+#include <avahi-common/error.h>
+
+struct avahi_state_struct {
+ struct AvahiPoll *poll;
+ AvahiClient *client;
+ AvahiEntryGroup *entry_group;
+ uint16_t port;
+};
+
+static void avahi_entry_group_callback(AvahiEntryGroup *g,
+ AvahiEntryGroupState status,
+ void *userdata)
+{
+ struct avahi_state_struct *state = talloc_get_type_abort(
+ userdata, struct avahi_state_struct);
+ int error;
+
+ switch (status) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ DEBUG(10, ("avahi_entry_group_callback: "
+ "AVAHI_ENTRY_GROUP_ESTABLISHED\n"));
+ break;
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ error = avahi_client_errno(state->client);
+
+ DEBUG(10, ("avahi_entry_group_callback: "
+ "AVAHI_ENTRY_GROUP_FAILURE: %s\n",
+ avahi_strerror(error)));
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ DEBUG(10, ("avahi_entry_group_callback: "
+ "AVAHI_ENTRY_GROUP_COLLISION\n"));
+ break;
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ DEBUG(10, ("avahi_entry_group_callback: "
+ "AVAHI_ENTRY_GROUP_UNCOMMITED\n"));
+ break;
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ DEBUG(10, ("avahi_entry_group_callback: "
+ "AVAHI_ENTRY_GROUP_REGISTERING\n"));
+ break;
+ }
+}
+
+static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
+ void *userdata)
+{
+ struct avahi_state_struct *state = talloc_get_type_abort(
+ userdata, struct avahi_state_struct);
+ int error;
+
+ switch (status) {
+ case AVAHI_CLIENT_S_RUNNING:
+ DEBUG(10, ("avahi_client_callback: AVAHI_CLIENT_S_RUNNING\n"));
+
+ state->entry_group = avahi_entry_group_new(
+ c, avahi_entry_group_callback, state);
+ if (state->entry_group == NULL) {
+ error = avahi_client_errno(c);
+ DEBUG(10, ("avahi_entry_group_new failed: %s\n",
+ avahi_strerror(error)));
+ break;
+ }
+ if (avahi_entry_group_add_service(
+ state->entry_group, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, 0, global_myname(),
+ "_smb._tcp", NULL, NULL, state->port, NULL) < 0) {
+ error = avahi_client_errno(c);
+ DEBUG(10, ("avahi_entry_group_add_service failed: "
+ "%s\n", avahi_strerror(error)));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ if (avahi_entry_group_commit(state->entry_group) < 0) {
+ error = avahi_client_errno(c);
+ DEBUG(10, ("avahi_entry_group_commit failed: "
+ "%s\n", avahi_strerror(error)));
+ avahi_entry_group_free(state->entry_group);
+ state->entry_group = NULL;
+ break;
+ }
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ error = avahi_client_errno(c);
+
+ DEBUG(10, ("avahi_client_callback: AVAHI_CLIENT_FAILURE: %s\n",
+ avahi_strerror(error)));
+
+ if (error != AVAHI_ERR_DISCONNECTED) {
+ break;
+ }
+ avahi_client_free(c);
+ state->client = avahi_client_new(state->poll, AVAHI_CLIENT_NO_FAIL,
+ avahi_client_callback, state,
+ &error);
+ if (state->client == NULL) {
+ DEBUG(10, ("avahi_client_new failed: %s\n",
+ avahi_strerror(error)));
+ break;
+ }
+ break;
+ case AVAHI_CLIENT_S_COLLISION:
+ DEBUG(10, ("avahi_client_callback: "
+ "AVAHI_CLIENT_S_COLLISION\n"));
+ break;
+ case AVAHI_CLIENT_S_REGISTERING:
+ DEBUG(10, ("avahi_client_callback: "
+ "AVAHI_CLIENT_S_REGISTERING\n"));
+ break;
+ case AVAHI_CLIENT_CONNECTING:
+ DEBUG(10, ("avahi_client_callback: "
+ "AVAHI_CLIENT_CONNECTING\n"));
+ break;
+ }
+}
+
+void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ uint16_t port)
+{
+ struct avahi_state_struct *state;
+ int error;
+
+ state = talloc(mem_ctx, struct avahi_state_struct);
+ if (state == NULL) {
+ return state;
+ }
+ state->port = port;
+ state->poll = tevent_avahi_poll(state, ev);
+ if (state->poll == NULL) {
+ goto fail;
+ }
+ state->client = avahi_client_new(state->poll, AVAHI_CLIENT_NO_FAIL,
+ avahi_client_callback, state,
+ &error);
+ if (state->client == NULL) {
+ DEBUG(10, ("avahi_client_new failed: %s\n",
+ avahi_strerror(error)));
+ goto fail;
+ }
+ return state;
+
+ fail:
+ TALLOC_FREE(state);
+ return NULL;
+}
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 42849931f3..4c61428692 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -204,9 +204,6 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
(unsigned int)blr->expire_time.tv_usec, lock_timeout,
blr->fsp->fnum, blr->fsp->fsp_name ));
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(blr->req->mid);
-
return True;
}
@@ -260,6 +257,7 @@ static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTAT
reply_nterror(blr->req, status);
if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
+ true, blr->req->seqnum+1,
blr->req->encrypted, NULL)) {
exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
}
@@ -343,6 +341,7 @@ static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS
if (!srv_send_smb(smbd_server_fd(),
(char *)blr->req->outbuf,
+ true, blr->req->seqnum+1,
IS_CONN_ENCRYPTED(blr->fsp->conn),
NULL)) {
exit_server_cleanly("blocking_lock_reply_error: "
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 6ac92ed3dd..b646bc30fd 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -202,6 +202,7 @@ extern int num_children;
struct smbd_server_connection {
struct fd_event *fde;
uint64_t num_requests;
+ struct smb_signing_state *signing_state;
};
extern struct smbd_server_connection *smbd_server_conn;
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index f20c851297..d39aab4f47 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -134,6 +134,7 @@ void send_trans_reply(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn), &req->pcd)) {
exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
}
@@ -190,6 +191,7 @@ void send_trans_reply(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn), &req->pcd))
exit_server_cleanly("send_trans_reply: srv_send_smb "
"failed.");
@@ -296,6 +298,7 @@ static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
send:
if (!srv_send_smb(
smbd_server_fd(), (char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
&req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
@@ -322,6 +325,7 @@ static void api_dcerpc_cmd_read_done(struct tevent_req *subreq)
reply_nterror(req, status);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)
||req->encrypted, &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb "
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index a921954c49..e548c587c1 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -316,7 +316,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
capabilities &= ~CAP_RAW_MODE;
if (lp_server_signing() == Required)
secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
- srv_set_signing_negotiated();
+ srv_set_signing_negotiated(smbd_server_conn);
} else {
DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
if (lp_server_signing() == Required) {
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 8ceeaf5f55..fdab2ca848 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -143,7 +143,9 @@ static void change_notify_reply_packet(connection_struct *conn,
}
show_msg((char *)req->outbuf);
- if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ true, req->seqnum+1,
req->encrypted, &req->pcd)) {
exit_server_cleanly("change_notify_reply_packet: srv_send_smb "
"failed.");
@@ -260,9 +262,6 @@ NTSTATUS change_notify_add_request(struct smb_request *req,
map->mid = request->req->mid;
DLIST_ADD(notify_changes_by_mid, map);
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(request->req->mid);
-
return NT_STATUS_OK;
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 9c7fb1914e..628fc1bd32 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -230,6 +230,7 @@ void send_nt_replies(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn),
&req->pcd)) {
exit_server_cleanly("send_nt_replies: srv_send_smb failed.");
@@ -1129,9 +1130,9 @@ void reply_ntcancel(struct smb_request *req)
*/
START_PROFILE(SMBntcancel);
+ srv_cancel_sign_response(smbd_server_conn);
remove_pending_change_notify_requests_by_mid(req->mid);
remove_pending_lock_requests_by_mid(req->mid);
- srv_cancel_sign_response(req->mid, true);
DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", req->mid));
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index d529b009d5..52df4fa143 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1033,15 +1033,6 @@ static void defer_open(struct share_mode_lock *lck,
exit_server("push_deferred_smb_message failed");
}
add_deferred_open(lck, req->mid, request_time, state->id);
-
- /*
- * Push the MID of this packet on the signing queue.
- * We only do this once, the first time we push the packet
- * onto the deferred open queue, as this has a side effect
- * of incrementing the response sequence number.
- */
-
- srv_defer_sign_response(req->mid);
}
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 22870283fa..ce00397bbd 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -361,7 +361,6 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx
struct share_mode_entry msg;
files_struct *fsp;
char *break_msg;
- bool sign_state;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
@@ -423,20 +422,14 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx
wait_before_sending_break();
}
- /* Save the server smb signing state. */
- sign_state = srv_oplock_set_signing(False);
-
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
- break_msg,
+ break_msg, false, 0,
IS_CONN_ENCRYPTED(fsp->conn),
NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
- /* Restore the sign state to what it was. */
- srv_oplock_set_signing(sign_state);
-
TALLOC_FREE(break_msg);
/* Async level2 request, don't send a reply, just remove the oplock. */
@@ -457,7 +450,6 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
files_struct *fsp;
char *break_msg;
bool break_to_level2 = False;
- bool sign_state;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
@@ -530,20 +522,14 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
wait_before_sending_break();
}
- /* Save the server smb signing state. */
- sign_state = srv_oplock_set_signing(False);
-
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
- break_msg,
+ break_msg, false, 0,
IS_CONN_ENCRYPTED(fsp->conn),
NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
- /* Restore the sign state to what it was. */
- srv_oplock_set_signing(sign_state);
-
TALLOC_FREE(break_msg);
fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
@@ -570,7 +556,6 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
unsigned long file_id;
files_struct *fsp;
char *break_msg;
- bool sign_state;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
@@ -610,20 +595,14 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
exit_server("Could not talloc break_msg\n");
}
- /* Save the server smb signing state. */
- sign_state = srv_oplock_set_signing(False);
-
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
- break_msg,
+ break_msg, false, 0,
IS_CONN_ENCRYPTED(fsp->conn),
NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
- /* Restore the sign state to what it was. */
- srv_oplock_set_signing(sign_state);
-
TALLOC_FREE(break_msg);
fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
diff --git a/source3/smbd/password.c b/source3/smbd/password.c
index 15d120a79c..076965e783 100644
--- a/source3/smbd/password.c
+++ b/source3/smbd/password.c
@@ -298,11 +298,13 @@ int register_existing_vuid(uint16 vuid,
vuser->server_info->unix_name);
}
- if (srv_is_signing_negotiated() && !vuser->server_info->guest &&
- !srv_signing_started()) {
+ if (srv_is_signing_negotiated(smbd_server_conn) &&
+ !vuser->server_info->guest) {
/* Try and turn on server signing on the first non-guest
* sessionsetup. */
- srv_set_signing(vuser->server_info->user_session_key, response_blob);
+ srv_set_signing(smbd_server_conn,
+ vuser->server_info->user_session_key,
+ response_blob);
}
/* fill in the current_user_info struct */
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index 2686cf41d9..7ae7435646 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -216,6 +216,7 @@ static void pipe_write_done(struct tevent_req *subreq)
send:
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
&req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 18fbdd7939..65778ab0fc 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -32,16 +32,20 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf,
Send an smb to a fd.
****************************************************************************/
-bool srv_send_smb(int fd, char *buffer, bool do_encrypt,
- struct smb_perfcount_data *pcd)
+bool srv_send_smb(int fd, char *buffer,
+ bool do_signing, uint32_t seqnum,
+ bool do_encrypt,
+ struct smb_perfcount_data *pcd)
{
size_t len = 0;
size_t nwritten=0;
ssize_t ret;
char *buf_out = buffer;
- /* Sign the outgoing packet if required. */
- srv_calculate_sign_mac(buf_out);
+ if (do_signing) {
+ /* Sign the outgoing packet if required. */
+ srv_calculate_sign_mac(smbd_server_conn, buf_out, seqnum);
+ }
if (do_encrypt) {
NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out);
@@ -275,7 +279,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd,
if (CVAL(lenbuf,0) == 0 && min_recv_size &&
(smb_len_large(lenbuf) > /* Could be a UNIX large writeX. */
(min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE)) &&
- !srv_is_signing_active()) {
+ !srv_is_signing_active(smbd_server_conn)) {
return receive_smb_raw_talloc_partial_read(
mem_ctx, lenbuf, fd, buffer, timeout, p_unread, plen);
@@ -311,7 +315,8 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd,
static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd,
char **buffer, unsigned int timeout,
size_t *p_unread, bool *p_encrypted,
- size_t *p_len)
+ size_t *p_len,
+ uint32_t *seqnum)
{
size_t len = 0;
NTSTATUS status;
@@ -336,7 +341,7 @@ static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd,
}
/* Check the incoming SMB signature. */
- if (!srv_check_sign_mac(*buffer, true)) {
+ if (!srv_check_sign_mac(smbd_server_conn, *buffer, seqnum)) {
DEBUG(0, ("receive_smb: SMB Signature verification failed on "
"incoming packet!\n"));
return NT_STATUS_INVALID_NETWORK_RESPONSE;
@@ -366,6 +371,7 @@ void init_smb_request(struct smb_request *req,
req->flags2 = SVAL(inbuf, smb_flg2);
req->smbpid = SVAL(inbuf, smb_pid);
req->mid = SVAL(inbuf, smb_mid);
+ req->seqnum = 0;
req->vuid = SVAL(inbuf, smb_uid);
req->tid = SVAL(inbuf, smb_tid);
req->wct = CVAL(inbuf, smb_wct);
@@ -401,7 +407,8 @@ void init_smb_request(struct smb_request *req,
static void process_smb(struct smbd_server_connection *conn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
- bool encrypted, struct smb_perfcount_data *deferred_pcd);
+ uint32_t seqnum, bool encrypted,
+ struct smb_perfcount_data *deferred_pcd);
static void smbd_deferred_open_timer(struct event_context *ev,
struct timed_event *te,
@@ -427,7 +434,7 @@ static void smbd_deferred_open_timer(struct event_context *ev,
process_smb(smbd_server_conn, inbuf,
msg->buf.length, 0,
- msg->encrypted, &msg->pcd);
+ msg->seqnum, msg->encrypted, &msg->pcd);
}
/****************************************************************************
@@ -458,6 +465,7 @@ static bool push_queued_message(struct smb_request *req,
}
msg->request_time = request_time;
+ msg->seqnum = req->seqnum;
msg->encrypted = req->encrypted;
SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd);
@@ -913,7 +921,7 @@ static const struct smb_message_struct {
/* 0x30 */ { NULL, NULL, 0 },
/* 0x31 */ { NULL, NULL, 0 },
/* 0x32 */ { "SMBtrans2",reply_trans2, AS_USER | CAN_IPC },
-/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER},
+/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER | CAN_IPC },
/* 0x34 */ { "SMBfindclose",reply_findclose,AS_USER},
/* 0x35 */ { "SMBfindnclose",reply_findnclose,AS_USER},
/* 0x36 */ { NULL, NULL, 0 },
@@ -1362,7 +1370,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
****************************************************************************/
static void construct_reply(char *inbuf, int size, size_t unread_bytes,
- bool encrypted,
+ uint32_t seqnum, bool encrypted,
struct smb_perfcount_data *deferred_pcd)
{
connection_struct *conn;
@@ -1374,6 +1382,7 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes,
init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted);
req->inbuf = (uint8_t *)talloc_move(req, &inbuf);
+ req->seqnum = seqnum;
/* we popped this message off the queue - keep original perf data */
if (deferred_pcd)
@@ -1405,6 +1414,7 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes,
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn)||req->encrypted,
&req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
@@ -1420,7 +1430,8 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes,
****************************************************************************/
static void process_smb(struct smbd_server_connection *conn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
- bool encrypted, struct smb_perfcount_data *deferred_pcd)
+ uint32_t seqnum, bool encrypted,
+ struct smb_perfcount_data *deferred_pcd)
{
int msg_type = CVAL(inbuf,0);
@@ -1442,7 +1453,7 @@ static void process_smb(struct smbd_server_connection *conn,
show_msg((char *)inbuf);
- construct_reply((char *)inbuf,nread,unread_bytes,encrypted,deferred_pcd);
+ construct_reply((char *)inbuf,nread,unread_bytes,seqnum,encrypted,deferred_pcd);
trans_num++;
done:
@@ -1637,6 +1648,7 @@ void chain_reply(struct smb_request *req)
talloc_get_size(req->chain_outbuf) - 4);
if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)
||req->encrypted,
&req->pcd)) {
@@ -1761,6 +1773,7 @@ void chain_reply(struct smb_request *req)
show_msg((char *)(req->chain_outbuf));
if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
&req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
@@ -1830,6 +1843,7 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c
bool encrypted = false;
TALLOC_CTX *mem_ctx = talloc_tos();
NTSTATUS status;
+ uint32_t seqnum;
/* TODO: make this completely nonblocking */
@@ -1838,7 +1852,7 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c
0, /* timeout */
&unread_bytes,
&encrypted,
- &inbuf_len);
+ &inbuf_len, &seqnum);
if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
goto process;
}
@@ -1850,7 +1864,8 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c
}
process:
- process_smb(conn, inbuf, inbuf_len, unread_bytes, encrypted, NULL);
+ process_smb(conn, inbuf, inbuf_len, unread_bytes,
+ seqnum, encrypted, NULL);
}
static void smbd_server_connection_handler(struct event_context *ev,
@@ -2015,7 +2030,8 @@ void smbd_process(void)
unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
DEBUG( 1, ("Connection denied from %s\n",
client_addr(get_client_fd(),addr,sizeof(addr)) ) );
- (void)srv_send_smb(smbd_server_fd(),(char *)buf,false, NULL);
+ (void)srv_send_smb(smbd_server_fd(),(char *)buf, false,
+ 0, false, NULL);
exit_server_cleanly("connection denied");
}
@@ -2041,6 +2057,10 @@ void smbd_process(void)
DEBUG(0,("Changed root to %s\n", lp_rootdir()));
}
+ if (!srv_init_signing(smbd_server_conn)) {
+ exit_server("Failed to init smb_signing");
+ }
+
/* Setup oplocks */
if (!init_oplocks(smbd_messaging_context()))
exit_server("Failed to init oplocks");
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 8b560bd8ca..6f19a58178 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -497,7 +497,7 @@ void reply_special(char *inbuf)
DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
msg_type, msg_flags));
- srv_send_smb(smbd_server_fd(), outbuf, false, NULL);
+ srv_send_smb(smbd_server_fd(), outbuf, false, 0, false, NULL);
return;
}
@@ -2766,7 +2766,8 @@ static void send_file_readbraw(connection_struct *conn,
*/
if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
- (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
+ (fsp->wcp == NULL) &&
+ lp_use_sendfile(SNUM(conn), smbd_server_conn->signing_state) ) {
ssize_t sendfile_read = -1;
char header[4];
DATA_BLOB header_blob;
@@ -2870,7 +2871,8 @@ void reply_readbraw(struct smb_request *req)
START_PROFILE(SMBreadbraw);
- if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
+ if (srv_is_signing_active(smbd_server_conn) ||
+ is_encrypted_packet(req->inbuf)) {
exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
"raw reads/writes are disallowed.");
}
@@ -3274,7 +3276,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
if (!req_is_in_chain(req) &&
!is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
- lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
+ (fsp->wcp == NULL) &&
+ lp_use_sendfile(SNUM(conn), smbd_server_conn->signing_state) ) {
uint8 headerbuf[smb_size + 12 * 2];
DATA_BLOB header;
@@ -3450,7 +3453,8 @@ void reply_read_and_X(struct smb_request *req)
return;
}
/* We currently don't do this on signed or sealed data. */
- if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
+ if (srv_is_signing_active(smbd_server_conn) ||
+ is_encrypted_packet(req->inbuf)) {
reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
END_PROFILE(SMBreadX);
return;
@@ -3558,7 +3562,7 @@ void reply_writebraw(struct smb_request *req)
*/
SCVAL(req->inbuf,smb_com,SMBwritec);
- if (srv_is_signing_active()) {
+ if (srv_is_signing_active(smbd_server_conn)) {
END_PROFILE(SMBwritebraw);
exit_server_cleanly("reply_writebraw: SMB signing is active - "
"raw reads/writes are disallowed.");
@@ -3653,9 +3657,10 @@ void reply_writebraw(struct smb_request *req)
SSVALS(buf,smb_vwv0,0xFFFF);
show_msg(buf);
if (!srv_send_smb(smbd_server_fd(),
- buf,
- IS_CONN_ENCRYPTED(conn),
- &req->pcd)) {
+ buf,
+ false, 0, /* no signing */
+ IS_CONN_ENCRYPTED(conn),
+ &req->pcd)) {
exit_server_cleanly("reply_writebraw: srv_send_smb "
"failed.");
}
@@ -4757,6 +4762,7 @@ void reply_echo(struct smb_request *req)
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn)||req->encrypted,
cur_pcd))
exit_server_cleanly("reply_echo: srv_send_smb failed.");
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index d27f98281b..67836f785b 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -643,8 +643,19 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
#endif
if (dns_port != 0) {
+#ifdef WITH_DNSSD_SUPPORT
smbd_setup_mdns_registration(smbd_event_context(),
parent, dns_port);
+#endif
+#ifdef WITH_AVAHI_SUPPORT
+ void *avahi_conn;
+
+ avahi_conn = avahi_start_register(
+ smbd_event_context(), smbd_event_context(), dns_port);
+ if (avahi_conn == NULL) {
+ DEBUG(10, ("avahi_start_register failed\n"));
+ }
+#endif
}
return true;
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index eb16a2601e..e33f04d971 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -1110,7 +1110,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
dbgtext( "%s (%s) ", get_remote_machine_name(),
conn->client_address );
- dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
+ dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : "");
dbgtext( "connect to service %s ", lp_servicename(snum) );
dbgtext( "initially as user %s ",
conn->server_info->unix_name );
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 2c29192220..e8878a29ab 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -91,25 +91,6 @@ static int push_signature(uint8 **outbuf)
}
/****************************************************************************
- Start the signing engine if needed. Don't fail signing here.
-****************************************************************************/
-
-static void sessionsetup_start_signing_engine(
- const auth_serversupplied_info *server_info,
- const uint8 *inbuf)
-{
- if (!server_info->guest && !srv_signing_started()) {
- /* We need to start the signing engine
- * here but a W2K client sends the old
- * "BSRSPYL " signature instead of the
- * correct one. Subsequent packets will
- * be correct.
- */
- srv_check_sign_mac((char *)inbuf, False);
- }
-}
-
-/****************************************************************************
Send a security blob via a session setup reply.
****************************************************************************/
@@ -579,7 +560,6 @@ static void reply_spnego_kerberos(struct smb_request *req,
SSVAL(req->outbuf, smb_uid, sess_vuid);
- sessionsetup_start_signing_engine(server_info, req->inbuf);
/* Successful logon. Keep this vuid. */
*p_invalidate_vuid = False;
}
@@ -668,9 +648,6 @@ static void reply_spnego_ntlmssp(struct smb_request *req,
if (server_info->guest) {
SSVAL(req->outbuf,smb_vwv2,1);
}
-
- sessionsetup_start_signing_engine(server_info,
- (uint8 *)req->inbuf);
}
out:
@@ -1804,8 +1781,6 @@ void reply_sesssetup_and_X(struct smb_request *req)
/* current_user_info is changed on new vuid */
reload_services( True );
-
- sessionsetup_start_signing_engine(server_info, req->inbuf);
}
data_blob_free(&nt_resp);
diff --git a/source3/smbd/signing.c b/source3/smbd/signing.c
new file mode 100644
index 0000000000..b56eb71f45
--- /dev/null
+++ b/source3/smbd/signing.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/globals.h"
+
+
+/***********************************************************
+ Called to validate an incoming packet from the client.
+************************************************************/
+
+bool srv_check_sign_mac(struct smbd_server_connection *conn,
+ const char *inbuf, uint32_t *seqnum)
+{
+ /* Check if it's a non-session message. */
+ if(CVAL(inbuf,0)) {
+ return true;
+ }
+
+ *seqnum = smb_signing_next_seqnum(conn->signing_state, false);
+ return smb_signing_check_pdu(conn->signing_state,
+ (const uint8_t *)inbuf,
+ *seqnum);
+}
+
+/***********************************************************
+ Called to sign an outgoing packet to the client.
+************************************************************/
+
+void srv_calculate_sign_mac(struct smbd_server_connection *conn,
+ char *outbuf, uint32_t seqnum)
+{
+ /* Check if it's a non-session message. */
+ if(CVAL(outbuf,0)) {
+ return;
+ }
+
+ smb_signing_sign_pdu(conn->signing_state, (uint8_t *)outbuf, seqnum);
+}
+
+
+/***********************************************************
+ Called to indicate a oneway request
+************************************************************/
+void srv_cancel_sign_response(struct smbd_server_connection *conn)
+{
+ smb_signing_cancel_reply(conn->signing_state, true);
+}
+
+/***********************************************************
+ Called by server negprot when signing has been negotiated.
+************************************************************/
+
+bool srv_init_signing(struct smbd_server_connection *conn)
+{
+ bool allowed = true;
+ bool mandatory = false;
+
+ switch (lp_server_signing()) {
+ case Required:
+ mandatory = true;
+ break;
+ case Auto:
+ break;
+ case True:
+ break;
+ case False:
+ allowed = false;
+ break;
+ }
+
+ conn->signing_state = smb_signing_init(smbd_event_context(),
+ allowed, mandatory);
+ if (!conn->signing_state) {
+ return false;
+ }
+
+ return true;
+}
+
+void srv_set_signing_negotiated(struct smbd_server_connection *conn)
+{
+ smb_signing_set_negotiated(conn->signing_state);
+}
+
+/***********************************************************
+ Returns whether signing is active. We can't use sendfile or raw
+ reads/writes if it is.
+************************************************************/
+
+bool srv_is_signing_active(struct smbd_server_connection *conn)
+{
+ return smb_signing_is_active(conn->signing_state);
+}
+
+
+/***********************************************************
+ Returns whether signing is negotiated. We can't use it unless it was
+ in the negprot.
+************************************************************/
+
+bool srv_is_signing_negotiated(struct smbd_server_connection *conn)
+{
+ return smb_signing_is_negotiated(conn->signing_state);
+}
+
+/***********************************************************
+ Turn on signing from this packet onwards.
+************************************************************/
+
+void srv_set_signing(struct smbd_server_connection *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ bool negotiated;
+ bool mandatory;
+
+ if (!user_session_key.length)
+ return;
+
+ negotiated = smb_signing_is_negotiated(conn->signing_state);
+ mandatory = smb_signing_is_mandatory(conn->signing_state);
+
+ if (!negotiated && !mandatory) {
+ DEBUG(5,("srv_set_signing: signing negotiated = %u, "
+ "mandatory_signing = %u. Not allowing smb signing.\n",
+ negotiated, mandatory));
+ return;
+ }
+
+ if (!smb_signing_activate(conn->signing_state,
+ user_session_key, response)) {
+ return;
+ }
+
+ DEBUG(3,("srv_set_signing: turning on SMB signing: "
+ "signing negotiated = %u, mandatory_signing = %u.\n",
+ negotiated, mandatory));
+}
+
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index ee1dda98b2..df01a39893 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -832,6 +832,7 @@ void send_trans2_replies(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
+ true, req->seqnum+1,
IS_CONN_ENCRYPTED(conn),
&req->pcd))
exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
@@ -2892,8 +2893,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
case SMB_QUERY_CIFS_UNIX_INFO:
{
bool large_write = lp_min_receive_file_size() &&
- !srv_is_signing_active();
- bool large_read = !srv_is_signing_active();
+ !srv_is_signing_active(smbd_server_conn);
+ bool large_read = !srv_is_signing_active(smbd_server_conn);
int encrypt_caps = 0;
if (!lp_unix_extensions()) {
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 15d1b7e2bf..54bcac2b04 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -1854,7 +1854,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
|| state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
- if (!state->request.flags & WBFLAG_BIG_NTLMV2_BLOB ||
+ if (!(state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) ||
state->request.extra_len != state->request.data.auth_crap.nt_resp_len) {
DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
state->request.data.auth_crap.lm_resp_len,