summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2003-01-28 03:37:14 +0000
committerAndrew Bartlett <abartlet@samba.org>2003-01-28 03:37:14 +0000
commitdc4bb3bed82773ab0a07eb72b3d21305cccb6ecf (patch)
treeacda990f09f7037583408e4696458250eb2d0407 /source3
parent99bb7dccb29f44d7edeb0fca3f8cfc01bda03281 (diff)
downloadsamba-dc4bb3bed82773ab0a07eb72b3d21305cccb6ecf.tar.gz
samba-dc4bb3bed82773ab0a07eb72b3d21305cccb6ecf.tar.bz2
samba-dc4bb3bed82773ab0a07eb72b3d21305cccb6ecf.zip
Factor out common code in the NTLMSSP/SPNEGO code.
The idea here is to seperate, as much as possible, the SPNEGO layer from the NTLMSSP layer. This not only helps us with protocol correctness, but also should allow further mechinisms to be added with relitive ease. I indend to make the kerberos code use this shortly. I've never seen the 'zero length blob' form of the anonymous login, so I've removed that case. Andrew Bartlett (This used to be commit a8773c9f825539c5bc17e4200b16d7ebbe0b7620)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/asn_1.h4
-rw-r--r--source3/libsmb/clispnego.c67
-rw-r--r--source3/libsmb/ntlmssp.c4
-rw-r--r--source3/smbd/sesssetup.c178
4 files changed, 80 insertions, 173 deletions
diff --git a/source3/include/asn_1.h b/source3/include/asn_1.h
index 7783ab4c2f..9cd873c18a 100644
--- a/source3/include/asn_1.h
+++ b/source3/include/asn_1.h
@@ -55,4 +55,8 @@ typedef struct {
#define OID_KERBEROS5_OLD "1 2 840 48018 1 2 2"
#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
+#define SPNGEO_NEG_RESULT_ACCEPT 0
+#define SPNGEO_NEG_RESULT_INCOMPLETE 1
+#define SPNGEO_NEG_RESULT_REJECT 2
+
#endif /* _ASN_1_H */
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index f4a414ef52..3e28baa417 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -387,51 +387,6 @@ BOOL spnego_parse_challenge(DATA_BLOB blob,
/*
- generate a spnego NTLMSSP challenge packet given two security blobs
- The second challenge is optional
-*/
-BOOL spnego_gen_challenge(DATA_BLOB *blob,
- DATA_BLOB *chal1, DATA_BLOB *chal2)
-{
- ASN1_DATA data;
-
- ZERO_STRUCT(data);
-
- asn1_push_tag(&data,ASN1_CONTEXT(1));
- asn1_push_tag(&data,ASN1_SEQUENCE(0));
-
- asn1_push_tag(&data,ASN1_CONTEXT(0));
- asn1_write_enumerated(&data,1);
- asn1_pop_tag(&data);
-
- asn1_push_tag(&data,ASN1_CONTEXT(1));
- asn1_write_OID(&data, OID_NTLMSSP);
- asn1_pop_tag(&data);
-
- asn1_push_tag(&data,ASN1_CONTEXT(2));
- asn1_write_OctetString(&data, chal1->data, chal1->length);
- asn1_pop_tag(&data);
-
- /* the second challenge is optional (XP doesn't send it) */
- if (chal2) {
- asn1_push_tag(&data,ASN1_CONTEXT(3));
- asn1_write_OctetString(&data, chal2->data, chal2->length);
- asn1_pop_tag(&data);
- }
-
- asn1_pop_tag(&data);
- asn1_pop_tag(&data);
-
- if (data.has_error) {
- return False;
- }
-
- *blob = data_blob(data.data, data.length);
- asn1_free(&data);
- return True;
-}
-
-/*
generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords
*/
DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
@@ -485,23 +440,37 @@ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
/*
generate a minimal SPNEGO NTLMSSP response packet. Doesn't contain much.
*/
-DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply)
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status)
{
ASN1_DATA data;
DATA_BLOB ret;
+ uint8 negResult;
- memset(&data, 0, sizeof(data));
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNGEO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNGEO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNGEO_NEG_RESULT_REJECT;
+ }
+
+ ZERO_STRUCT(data);
asn1_push_tag(&data, ASN1_CONTEXT(1));
asn1_push_tag(&data, ASN1_SEQUENCE(0));
asn1_push_tag(&data, ASN1_CONTEXT(0));
- asn1_write_enumerated(&data, ntlmssp_reply->length ? 1 : 0);
+ asn1_write_enumerated(&data, negResult);
asn1_pop_tag(&data);
- if (ntlmssp_reply->length) {
+ if (negResult == SPNGEO_NEG_RESULT_INCOMPLETE) {
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_write_OID(&data, OID_NTLMSSP);
+ asn1_pop_tag(&data);
+
asn1_push_tag(&data,ASN1_CONTEXT(2));
asn1_write_OctetString(&data, ntlmssp_reply->data, ntlmssp_reply->length);
asn1_pop_tag(&data);
}
+
asn1_pop_tag(&data);
asn1_pop_tag(&data);
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 6837674736..5b608e0a7a 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -275,10 +275,6 @@ NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state,
nt_status = ntlmssp_state->check_password(ntlmssp_state);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
*reply = data_blob(NULL, 0);
return nt_status;
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index e68695ee52..23a44d8df7 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -213,7 +213,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
send a security blob via a session setup reply
****************************************************************************/
static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
- DATA_BLOB blob, NTSTATUS errcode)
+ DATA_BLOB blob, NTSTATUS nt_status)
{
char *p;
@@ -222,60 +222,65 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
/* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
that we aren't finished yet */
- SIVAL(outbuf, smb_rcls, NT_STATUS_V(errcode));
+ nt_status = nt_status_squash(nt_status);
+ SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
SSVAL(outbuf, smb_vwv3, blob.length);
p = smb_buf(outbuf);
memcpy(p, blob.data, blob.length);
- p += blob.length;
- p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
- p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
- p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
- set_message_end(outbuf,p);
+
+ add_signature(outbuf);
return send_smb(smbd_server_fd(),outbuf);
}
/****************************************************************************
-send an NTLMSSP blob via a session setup reply, wrapped in SPNEGO
-****************************************************************************/
-static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
- DATA_BLOB *ntlmssp_blob, NTSTATUS errcode)
-{
- DATA_BLOB response;
- response = spnego_gen_auth_response(ntlmssp_blob);
- reply_sesssetup_blob(conn, outbuf, response, errcode);
- data_blob_free(&response);
- return True;
-}
-
-/****************************************************************************
- send an OK via a session setup reply, wrapped in SPNEGO.
+ send a session setup reply, wrapped in SPNEGO.
get vuid and check first.
-****************************************************************************/
-static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
- AUTH_NTLMSSP_STATE *auth_ntlmssp_state)
+ end the NTLMSSP exchange context if we are OK/complete fail
+***************************************************************************/
+static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf,
+ AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
+ DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
{
- int sess_vuid;
- DATA_BLOB null_blob = data_blob(NULL, 0);
+ DATA_BLOB response;
+ struct auth_serversupplied_info *server_info;
+ server_info = (*auth_ntlmssp_state)->server_info;
- sess_vuid = register_vuid(auth_ntlmssp_state->server_info, auth_ntlmssp_state->ntlmssp_state->user /* check this for weird */);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ nt_status = do_map_to_guest(nt_status,
+ &server_info,
+ (*auth_ntlmssp_state)->ntlmssp_state->user,
+ (*auth_ntlmssp_state)->ntlmssp_state->domain);
+ }
- if (sess_vuid == -1) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ int sess_vuid;
+ sess_vuid = register_vuid(server_info, (*auth_ntlmssp_state)->ntlmssp_state->user /* check this for weird */);
+
+ if (sess_vuid == -1) {
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ } else {
+
+ set_message(outbuf,4,0,True);
+ SSVAL(outbuf, smb_vwv3, 0);
+
+ if ((*auth_ntlmssp_state)->server_info->guest) {
+ SSVAL(outbuf,smb_vwv2,1);
+ }
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ }
}
- set_message(outbuf,4,0,True);
- SSVAL(outbuf, smb_vwv3, 0);
+ response = spnego_gen_auth_response(ntlmssp_blob, nt_status);
+ reply_sesssetup_blob(conn, outbuf, response, nt_status);
+ data_blob_free(&response);
- if (auth_ntlmssp_state->server_info->guest) {
- SSVAL(outbuf,smb_vwv2,1);
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ auth_ntlmssp_end(&global_ntlmssp_state);
}
- add_signature(outbuf);
-
- SSVAL(outbuf,smb_uid,sess_vuid);
- reply_spnego_ntlmssp_blob(conn, outbuf, &null_blob, NT_STATUS_OK);
return True;
}
@@ -291,7 +296,7 @@ static int reply_spnego_negotiate(connection_struct *conn,
char *OIDs[ASN1_MAX_OIDS];
DATA_BLOB secblob;
int i;
- DATA_BLOB chal, spnego_chal;
+ DATA_BLOB chal;
BOOL got_kerberos = False;
NTSTATUS nt_status;
@@ -333,41 +338,13 @@ static int reply_spnego_negotiate(connection_struct *conn,
data_blob_free(&secblob);
- if (!NT_STATUS_IS_OK(nt_status)) {
- nt_status = do_map_to_guest(nt_status,
- &global_ntlmssp_state->server_info,
- global_ntlmssp_state->ntlmssp_state->user,
- global_ntlmssp_state->ntlmssp_state->domain);
- }
-
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- if (!spnego_gen_challenge(&spnego_chal, &chal, NULL)) {
- DEBUG(3,("Failed to generate challenge\n"));
- data_blob_free(&chal);
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
-
- /* now tell the client to send the auth packet */
- reply_sesssetup_blob(conn, outbuf, spnego_chal, nt_status);
+ reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
+ &chal, nt_status);
- data_blob_free(&chal);
- data_blob_free(&spnego_chal);
+ data_blob_free(&chal);
- /* and tell smbd that we have already replied to this packet */
- return -1;
-
- } else if (NT_STATUS_IS_OK(nt_status)) {
- reply_spnego_ntlmssp_ok(conn, outbuf,
- global_ntlmssp_state);
- auth_ntlmssp_end(&global_ntlmssp_state);
-
- /* and tell smbd that we have already replied to this packet */
- return -1;
- }
-
- auth_ntlmssp_end(&global_ntlmssp_state);
-
- return ERROR_NT(nt_status_squash(nt_status));
+ /* already replied */
+ return -1;
}
@@ -389,20 +366,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
}
nt_status = auth_ntlmssp_update(global_ntlmssp_state,
- auth, &auth_reply);
+ auth, &auth_reply);
data_blob_free(&auth);
- if (NT_STATUS_IS_OK(nt_status)) {
- reply_spnego_ntlmssp_ok(conn, outbuf,
- global_ntlmssp_state);
- auth_ntlmssp_end(&global_ntlmssp_state);
- data_blob_free(&auth_reply);
-
- } else { /* !NT_STATUS_IS_OK(nt_status) */
- auth_ntlmssp_end(&global_ntlmssp_state);
- return ERROR_NT(nt_status_squash(nt_status));
- }
+ reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
+ &auth_reply, nt_status);
+
+ data_blob_free(&auth_reply);
/* and tell smbd that we have already replied to this packet */
return -1;
@@ -410,41 +381,6 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
/****************************************************************************
-reply to a session setup spnego anonymous packet
-****************************************************************************/
-static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
- int length, int bufsize)
-{
- int sess_vuid;
- auth_serversupplied_info *server_info = NULL;
- NTSTATUS nt_status;
-
- nt_status = check_guest_password(&server_info);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(nt_status_squash(nt_status));
- }
-
- sess_vuid = register_vuid(server_info, lp_guestaccount());
-
- free_server_info(&server_info);
-
- if (sess_vuid == -1) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
-
- set_message(outbuf,4,0,True);
- SSVAL(outbuf, smb_vwv3, 0);
- add_signature(outbuf);
-
- SSVAL(outbuf,smb_uid,sess_vuid);
- SSVAL(inbuf,smb_uid,sess_vuid);
-
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
-
-
-/****************************************************************************
reply to a session setup command
****************************************************************************/
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
@@ -454,6 +390,7 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
uint8 *p;
DATA_BLOB blob1;
int ret;
+ size_t bufrem;
DEBUG(3,("Doing spnego session setup\n"));
@@ -464,12 +401,13 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
p = (uint8 *)smb_buf(inbuf);
if (SVAL(inbuf, smb_vwv7) == 0) {
- /* an anonymous request */
- return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
+ /* an invalid request */
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
+ bufrem = smb_bufrem(inbuf, p);
/* pull the spnego blob */
- blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
+ blob1 = data_blob(p, MIN(bufrem, SVAL(inbuf, smb_vwv7)));
#if 0
file_save("negotiate.dat", blob1.data, blob1.length);