summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2004-07-05 23:28:49 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:56:51 -0500
commit4f0e5e069064c11a8efc407cd42412d38534d0d2 (patch)
treefcf4d3913183525653af213c6c15abbb8b9c6754
parent8bebc53df8ff46e801ed1258206126f6ebe9a1c3 (diff)
downloadsamba-4f0e5e069064c11a8efc407cd42412d38534d0d2.tar.gz
samba-4f0e5e069064c11a8efc407cd42412d38534d0d2.tar.bz2
samba-4f0e5e069064c11a8efc407cd42412d38534d0d2.zip
r1345: add extended security spnego support to the smb client
code set lp_use_spnego = False, because I can't get it working yet but I commit it so others can help me metze (This used to be commit 2445cceba9ab9bd928c8bc50927a39509e4526b0)
-rw-r--r--source4/include/cli_context.h28
-rw-r--r--source4/libcli/raw/clisession.c111
-rw-r--r--source4/libcli/raw/clitransport.c1
-rw-r--r--source4/libcli/raw/clitree.c4
-rw-r--r--source4/libcli/raw/rawnegotiate.c47
-rw-r--r--source4/libcli/raw/smb_signing.c50
-rw-r--r--source4/param/loadparm.c2
7 files changed, 210 insertions, 33 deletions
diff --git a/source4/include/cli_context.h b/source4/include/cli_context.h
index 24dcfe7235..930017bb26 100644
--- a/source4/include/cli_context.h
+++ b/source4/include/cli_context.h
@@ -29,21 +29,12 @@ struct cli_request; /* forward declare */
struct cli_session; /* forward declare */
struct cli_transport; /* forward declare */
-typedef struct smb_sign_info {
- void (*sign_outgoing_message)(struct cli_request *req);
- BOOL (*check_incoming_message)(struct cli_request *req);
- void (*free_signing_context)(struct cli_transport *transport);
- void *signing_context;
-
- BOOL doing_signing;
-} smb_sign_info;
-
/* context that will be and has been negotiated between the client and server */
struct cli_negotiate {
/*
* negotiated maximum transmit size - this is given to us by the server
*/
- uint_t max_xmit;
+ uint32_t max_xmit;
/* maximum number of requests that can be multiplexed */
uint16_t max_mux;
@@ -51,16 +42,24 @@ struct cli_negotiate {
/* the negotiatiated protocol */
enum protocol_types protocol;
- int sec_mode; /* security mode returned by negprot */
+ uint8_t sec_mode; /* security mode returned by negprot */
+ uint8_t key_len;
+ DATA_BLOB server_guid; /* server_guid */
DATA_BLOB secblob; /* cryptkey or negTokenInit blob */
uint32_t sesskey;
- smb_sign_info sign_info;
+ struct {
+ void (*sign_outgoing_message)(struct cli_request *req);
+ BOOL (*check_incoming_message)(struct cli_request *req);
+ void (*free_signing_context)(struct cli_transport *transport);
+ void *signing_context;
+ BOOL doing_signing;
+ } sign_info;
/* capabilities that the server reported */
uint32_t capabilities;
- int server_zone;
+ int16_t server_zone;
time_t server_time;
uint_t readbraw_supported:1;
uint_t writebraw_supported:1;
@@ -187,6 +186,9 @@ struct cli_session {
uint32_t pid;
DATA_BLOB user_session_key;
+
+ /* the spnego context if we use extented security */
+ struct gensec_security *gensec;
};
/*
diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c
index 780ff5837b..7ff5db59c3 100644
--- a/source4/libcli/raw/clisession.c
+++ b/source4/libcli/raw/clisession.c
@@ -121,10 +121,12 @@ struct cli_request *smb_raw_session_setup_send(struct cli_session *session, unio
SSVAL(req->out.vwv, VWV(4), parms->spnego.in.vc_num);
SIVAL(req->out.vwv, VWV(5), parms->spnego.in.sesskey);
SSVAL(req->out.vwv, VWV(7), parms->spnego.in.secblob.length);
+ SIVAL(req->out.vwv, VWV(8), 0); /* reserved */
SIVAL(req->out.vwv, VWV(10), parms->spnego.in.capabilities);
cli_req_append_blob(req, &parms->spnego.in.secblob);
cli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE);
cli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE);
+ cli_req_append_string(req, parms->spnego.in.domain, STR_TERMINATE);
break;
}
@@ -369,6 +371,109 @@ static NTSTATUS smb_raw_session_setup_generic_nt1(struct cli_session *session,
return NT_STATUS_OK;
}
+/****************************************************************************
+ Perform a session setup (sync interface) using generic interface and the SPNEGO
+ style sesssetup call
+****************************************************************************/
+static NTSTATUS smb_raw_session_setup_generic_spnego(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ NTSTATUS status;
+ union smb_sesssetup s2;
+
+ s2.generic.level = RAW_SESSSETUP_SPNEGO;
+ s2.spnego.in.bufsize = ~0;
+ s2.spnego.in.mpx_max = 50;
+ s2.spnego.in.vc_num = 1;
+ s2.spnego.in.sesskey = parms->generic.in.sesskey;
+ s2.spnego.in.capabilities = parms->generic.in.capabilities;
+ s2.spnego.in.domain = parms->generic.in.domain;
+ s2.spnego.in.os = "Unix";
+ s2.spnego.in.lanman = "Samba";
+
+ cli_temp_set_signing(session->transport);
+
+ status = gensec_client_start(&session->gensec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_domain(session->gensec, parms->generic.in.domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
+ parms->generic.in.domain, nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_username(session->gensec, parms->generic.in.user);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
+ parms->generic.in.user, nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_password(session->gensec, parms->generic.in.password);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_start_mech_by_name(session->gensec, "spnego");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_update(session->gensec, mem_ctx,
+ session->transport->negotiate.secblob,
+ &s2.spnego.in.secblob);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto done;
+ }
+
+ while(1) {
+ status = smb_raw_session_setup(session, mem_ctx, &s2);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto done;
+ }
+
+ status = gensec_update(session->gensec, mem_ctx,
+ s2.spnego.out.secblob,
+ &s2.spnego.in.secblob);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto done;
+ }
+ }
+
+done:
+ if (NT_STATUS_IS_OK(status)) {
+ DATA_BLOB null_data_blob = data_blob(NULL, 0);
+ DATA_BLOB session_key = data_blob(NULL, 0);
+
+ status = gensec_session_key(session->gensec, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ cli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
+
+ cli_session_set_user_session_key(session, &session_key);
+
+ parms->generic.out.vuid = s2.spnego.out.vuid;
+ parms->generic.out.os = s2.spnego.out.os;
+ parms->generic.out.lanman = s2.spnego.out.lanman;
+ parms->generic.out.domain = s2.spnego.out.domain;
+ }
+
+ return status;
+}
/****************************************************************************
Perform a session setup (sync interface) using generic interface
@@ -389,14 +494,12 @@ static NTSTATUS smb_raw_session_setup_generic(struct cli_session *session,
}
/* see if we should use the NT1 interface */
- if (!(session->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) ||
- !session->transport->options.use_spnego) {
+ if (!(session->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY)) {
return smb_raw_session_setup_generic_nt1(session, mem_ctx, parms);
}
/* default to using SPNEGO/NTLMSSP */
- DEBUG(0,("Need to add client SPNEGO code back in\n"));
- return NT_STATUS_UNSUCCESSFUL;
+ return smb_raw_session_setup_generic_spnego(session, mem_ctx, parms);
}
diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c
index 1e9032459f..a378ac8aad 100644
--- a/source4/libcli/raw/clitransport.c
+++ b/source4/libcli/raw/clitransport.c
@@ -38,6 +38,7 @@ struct cli_transport *cli_transport_init(struct cli_socket *sock)
transport->mem_ctx = mem_ctx;
transport->socket = sock;
transport->negotiate.protocol = PROTOCOL_NT1;
+ transport->options.use_spnego = lp_use_spnego();
transport->negotiate.max_xmit = ~0;
cli_null_set_signing(transport);
transport->socket->reference_count++;
diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c
index b35bf67c94..3b16c4c336 100644
--- a/source4/libcli/raw/clitree.c
+++ b/source4/libcli/raw/clitree.c
@@ -235,9 +235,7 @@ NTSTATUS cli_tree_full_connection(struct cli_tree **ret_tree,
/* prepare a session setup to establish a security context */
setup.generic.level = RAW_SESSSETUP_GENERIC;
setup.generic.in.sesskey = transport->negotiate.sesskey;
- setup.generic.in.capabilities = CAP_UNICODE | CAP_STATUS32 |
- CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
- CAP_W2K_SMBS | CAP_LARGE_READX | CAP_LARGE_WRITEX;
+ setup.generic.in.capabilities = transport->negotiate.capabilities;
if (!user || !user[0]) {
setup.generic.in.password = NULL;
setup.generic.in.user = "";
diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c
index 5b94ef63d8..6bf35fb26d 100644
--- a/source4/libcli/raw/rawnegotiate.c
+++ b/source4/libcli/raw/rawnegotiate.c
@@ -32,6 +32,7 @@ static const struct {
{PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
{PROTOCOL_LANMAN2,"LM1.2X002"},
{PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2,"LANMAN2.1"},
{PROTOCOL_LANMAN2,"Samba"},
{PROTOCOL_NT1,"NT LANMAN 1.0"},
{PROTOCOL_NT1,"NT LM 0.12"},
@@ -44,12 +45,25 @@ struct cli_request *smb_negprot_send(struct cli_transport *transport, int maxpro
{
struct cli_request *req;
int i;
+ uint16_t flags2 = 0;
req = cli_request_setup_transport(transport, SMBnegprot, 0, 0);
if (!req) {
return NULL;
}
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
+ flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
+ flags2 |= FLAGS2_IS_LONG_NAME;
+
+ if (transport->options.use_spnego) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+
+ SSVAL(req->out.hdr,HDR_FLG2, flags2);
+
/* setup the protocol strings */
for (i=0; i < ARRAY_SIZE(prots) && prots[i].prot <= maxprotocol; i++) {
cli_req_append_bytes(req, "\2", 1);
@@ -102,26 +116,35 @@ NTSTATUS smb_raw_negotiate(struct cli_transport *transport)
transport->negotiate.max_mux = SVAL(req->in.vwv,VWV(1)+1);
transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1);
transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(7)+1);
- transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
+ transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
/* this time arrives in real GMT */
ntt = cli_pull_nttime(req->in.vwv, VWV(11)+1);
- transport->negotiate.server_time = nt_time_to_unix(ntt);
- transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
+ transport->negotiate.server_time = nt_time_to_unix(ntt);
+ transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
+ transport->negotiate.key_len = CVAL(req->in.vwv,VWV(16)+1);
+
+ if (transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
+ if (req->in.data_size < 16) {
+ goto failed;
+ }
+ transport->negotiate.server_guid = cli_req_pull_blob(req, transport->mem_ctx, req->in.data, 16);
+ transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, req->in.data + 16, req->in.data_size - 16);
+ } else {
+ if (req->in.data_size < (transport->negotiate.key_len)) {
+ goto failed;
+ }
+ transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, req->in.data, transport->negotiate.key_len);
+ cli_req_pull_string(req, transport->mem_ctx, &transport->negotiate.server_domain,
+ req->in.data+transport->negotiate.key_len,
+ req->in.data_size-transport->negotiate.key_len, STR_UNICODE|STR_NOALIGN);
+ /* here comes the server name */
+ }
- transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, req->in.data, req->in.data_size);
if (transport->negotiate.capabilities & CAP_RAW_MODE) {
transport->negotiate.readbraw_supported = True;
transport->negotiate.writebraw_supported = True;
}
-
- /* work out if they sent us a workgroup */
- if ((transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) &&
- req->in.data_size > 16) {
- cli_req_pull_string(req, transport->mem_ctx, &transport->negotiate.server_domain,
- req->in.data+16,
- req->in.data_size-16, STR_UNICODE|STR_NOALIGN);
- }
} else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) {
CLI_CHECK_WCT(req, 13);
transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1));
diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c
index a39f33c290..20b44a5348 100644
--- a/source4/libcli/raw/smb_signing.c
+++ b/source4/libcli/raw/smb_signing.c
@@ -299,6 +299,56 @@ BOOL cli_null_set_signing(struct cli_transport *transport)
return True;
}
+/***********************************************************
+ SMB signing - TEMP implementation - calculate a MAC to send.
+************************************************************/
+static void cli_request_temp_sign_outgoing_message(struct cli_request *req)
+{
+ /* mark the packet as signed - BEFORE we sign it...*/
+ mark_packet_signed(req);
+
+ /* I wonder what BSRSPYL stands for - but this is what MS
+ actually sends! */
+ memcpy((req->out.hdr + HDR_SS_FIELD), "BSRSPYL ", 8);
+ return;
+}
+
+/***********************************************************
+ SMB signing - TEMP implementation - check a MAC sent by server.
+************************************************************/
+static BOOL cli_request_temp_check_incoming_message(struct cli_request *req)
+{
+ return True;
+}
+
+/***********************************************************
+ SMB signing - NULL implementation - free signing context
+************************************************************/
+static void cli_temp_free_signing_context(struct cli_transport *transport)
+{
+ return;
+}
+
+/**
+ SMB signing - TEMP implementation - setup the MAC key.
+
+ @note Used as an initialisation only - it will not correctly
+ shut down a real signing mechanism
+*/
+BOOL cli_temp_set_signing(struct cli_transport *transport)
+{
+ if (!set_smb_signing_common(transport)) {
+ return False;
+ }
+
+ transport->negotiate.sign_info.signing_context = NULL;
+
+ transport->negotiate.sign_info.sign_outgoing_message = cli_request_temp_sign_outgoing_message;
+ transport->negotiate.sign_info.check_incoming_message = cli_request_temp_check_incoming_message;
+ transport->negotiate.sign_info.free_signing_context = cli_temp_free_signing_context;
+
+ return True;
+}
/**
* Free the signing context
diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c
index 68a16501d2..33019c1bf1 100644
--- a/source4/param/loadparm.c
+++ b/source4/param/loadparm.c
@@ -1101,7 +1101,7 @@ static void init_globals(void)
Globals.name_cache_timeout = 660; /* In seconds */
- Globals.bUseSpnego = True;
+ Globals.bUseSpnego = False;
Globals.server_signing = False;