diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-08-11 18:09:40 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:57:51 -0500 |
commit | 1c9216f36cc451156d6c65f0e971ce48f05da3e5 (patch) | |
tree | e86bb93c78f168110f7e81dac4069213cfc74917 /source4 | |
parent | 86d4ec7212bcebd460cc52a24d3833939e4746bc (diff) | |
download | samba-1c9216f36cc451156d6c65f0e971ce48f05da3e5.tar.gz samba-1c9216f36cc451156d6c65f0e971ce48f05da3e5.tar.bz2 samba-1c9216f36cc451156d6c65f0e971ce48f05da3e5.zip |
r1731: Add server-side SPNEGO support to Samba (disabled, until SMB signing
is reworked).
Andrew Bartlett
(This used to be commit 73ee549b8c54e93556ff0105941996e0d4de8303)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/libcli/auth/spnego.c | 310 | ||||
-rw-r--r-- | source4/smb_server/negprot.c | 100 | ||||
-rw-r--r-- | source4/smb_server/sesssetup.c | 117 |
3 files changed, 356 insertions, 171 deletions
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c index 23f0b1c070..6a8b858f91 100644 --- a/source4/libcli/auth/spnego.c +++ b/source4/libcli/auth/spnego.c @@ -66,6 +66,28 @@ static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_securi return NT_STATUS_OK; } +static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security) +{ + struct spnego_state *spnego_state; + TALLOC_CTX *mem_ctx = talloc_init("gensec_spnego_server_start"); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + spnego_state = talloc_p(mem_ctx, struct spnego_state); + + if (!spnego_state) { + return NT_STATUS_NO_MEMORY; + } + + spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; + spnego_state->state_position = SPNEGO_SERVER_START; + spnego_state->mem_ctx = mem_ctx; + spnego_state->sub_sec_security = NULL; + + gensec_security->private_data = spnego_state; + return NT_STATUS_OK; +} + /* wrappers for the spnego_*() functions */ @@ -146,6 +168,18 @@ static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_securit session_key); } +static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security, + struct auth_session_info **session_info) +{ + struct spnego_state *spnego_state = gensec_security->private_data; + if (!spnego_state->sub_sec_security) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_session_info(spnego_state->sub_sec_security, + session_info); +} + /** Fallback to another GENSEC mechanism, based on magic strings * * This is the 'fallback' case, where we don't get SPNEGO, and have to @@ -191,22 +225,69 @@ static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec } -/** create a client netTokenInit +static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_security, + struct spnego_state *spnego_state, + TALLOC_CTX *out_mem_ctx, + const char **mechType, + const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) +{ + int i; + NTSTATUS nt_status; + DATA_BLOB null_data_blob = data_blob(NULL,0); + + for (i=0; mechType && mechType[i]; i++) { + nt_status = gensec_subcontext_start(gensec_security, + &spnego_state->sub_sec_security); + if (!NT_STATUS_IS_OK(nt_status)) { + break; + } + /* select the sub context */ + nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, + mechType[i]); + if (!NT_STATUS_IS_OK(nt_status)) { + gensec_end(&spnego_state->sub_sec_security); + continue; + } + + if (i == 0) { + nt_status = gensec_update(spnego_state->sub_sec_security, + out_mem_ctx, + unwrapped_in, + unwrapped_out); + } else { + /* only get the helping start blob for the first OID */ + nt_status = gensec_update(spnego_state->sub_sec_security, + out_mem_ctx, + null_data_blob, + unwrapped_out); + } + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", + spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); + gensec_end(&spnego_state->sub_sec_security); + } else { + break; + } + } + if (!mechType || !mechType[i]) { + DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); + } + return nt_status; +} + +/** create a client negTokenInit * * This is the case, where the client is the first one who sends data */ -static NTSTATUS gensec_spnego_client_netTokenInit(struct gensec_security *gensec_security, +static NTSTATUS gensec_spnego_client_negTokenInit(struct gensec_security *gensec_security, struct spnego_state *spnego_state, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) { NTSTATUS nt_status; - int i; int num_ops; - char **mechTypes = NULL; - const struct gensec_security_ops **all_ops = gensec_security_all(&num_ops); - DATA_BLOB null_data_blob = data_blob(NULL,0); + const char **mechTypes = NULL; DATA_BLOB unwrapped_out = data_blob(NULL,0); if (num_ops < 1) { @@ -214,31 +295,13 @@ static NTSTATUS gensec_spnego_client_netTokenInit(struct gensec_security *gensec return NT_STATUS_INVALID_PARAMETER; } - /* build a mechTypes list we want to offer */ - for (i=0; i < num_ops; i++) { - if (!all_ops[i]->oid) { - continue; - } - - /* skip SPNEGO itself */ - if (strcmp(OID_SPNEGO,all_ops[i]->oid)==0) { - continue; - } - - mechTypes = talloc_realloc_p(out_mem_ctx, mechTypes, char *, i+2); - if (!mechTypes) { - DEBUG(1, ("talloc_realloc_p(out_mem_ctx, mechTypes, char *, i+1) failed\n")); - return NT_STATUS_NO_MEMORY; - } - - mechTypes[i] = all_ops[i]->oid; - mechTypes[i+1] = NULL; - } + mechTypes = gensec_security_oids(out_mem_ctx, OID_SPNEGO); if (!mechTypes) { DEBUG(1, ("no GENSEC OID backends available\n")); return NT_STATUS_INVALID_PARAMETER; } + DATA_BLOB null_data_blob = data_blob(NULL,0); nt_status = gensec_subcontext_start(gensec_security, &spnego_state->sub_sec_security); @@ -278,6 +341,53 @@ static NTSTATUS gensec_spnego_client_netTokenInit(struct gensec_security *gensec return NT_STATUS_INVALID_PARAMETER; } + +/** create a client negTokenTarg + * + * This is the case, where the client is the first one who sends data +*/ + +static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, + struct spnego_state *spnego_state, + TALLOC_CTX *out_mem_ctx, + NTSTATUS nt_status, + const DATA_BLOB unwrapped_out, DATA_BLOB *out) +{ + struct spnego_data spnego_out; + DATA_BLOB null_data_blob = data_blob(NULL, 0); + + /* compose reply */ + spnego_out.type = SPNEGO_NEG_TOKEN_TARG; + spnego_out.negTokenTarg.supportedMech + = spnego_state->sub_sec_security->ops->oid; + spnego_out.negTokenTarg.responseToken = unwrapped_out; + spnego_out.negTokenTarg.mechListMIC = null_data_blob; + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; + spnego_state->state_position = SPNEGO_SERVER_TARG; + } else if (NT_STATUS_IS_OK(nt_status)) { + spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; + spnego_state->state_position = SPNEGO_DONE; + } else { + spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; + DEBUG(1, ("SPNEGO(%s) login failed: %s\n", + spnego_state->sub_sec_security->ops->name, + nt_errstr(nt_status))); + spnego_state->state_position = SPNEGO_DONE; + } + + if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { + DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; + + return nt_status; +} + + static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) { @@ -289,6 +399,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA ssize_t len; + *out = data_blob(NULL, 0); + if (!out_mem_ctx) { out_mem_ctx = spnego_state->mem_ctx; } @@ -302,30 +414,72 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA case SPNEGO_SERVER_START: { if (in.length) { + NTSTATUS nt_status; + len = spnego_read_data(in, &spnego); if (len == -1) { return gensec_spnego_server_try_fallback(gensec_security, spnego_state, out_mem_ctx, in, out); - } else { - /* client sent NegTargetInit */ } + /* client sent NegTargetInit, we send NegTokenTarg */ + + /* OK, so it's real SPNEGO, check the packet's the one we expect */ + if (spnego.type != spnego_state->expected_packet) { + DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, + spnego_state->expected_packet)); + dump_data(1, (const char *)in.data, in.length); + spnego_free_data(&spnego); + return NT_STATUS_INVALID_PARAMETER; + } + + nt_status = gensec_spnego_parse_negTokenInit(gensec_security, + spnego_state, + out_mem_ctx, + spnego.negTokenInit.mechTypes, + spnego.negTokenInit.mechToken, + &unwrapped_out); + + nt_status = gensec_spnego_server_negTokenTarg(gensec_security, + spnego_state, + out_mem_ctx, + nt_status, + unwrapped_out, + out); + + spnego_free_data(&spnego); + + return nt_status; } else { - /* server needs to send NegTargetInit */ + const char **mechlist = gensec_security_oids(out_mem_ctx, OID_SPNEGO); + + spnego_out.type = SPNEGO_NEG_TOKEN_INIT; + spnego_out.negTokenInit.mechTypes = mechlist; + spnego_out.negTokenInit.reqFlags = 0; + spnego_out.negTokenInit.mechListMIC = null_data_blob; + spnego_out.negTokenInit.mechToken = unwrapped_out; + + if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { + DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + /* set next state */ + spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; + spnego_state->state_position = SPNEGO_SERVER_TARG; + + return NT_STATUS_MORE_PROCESSING_REQUIRED; } - return NT_STATUS_INVALID_PARAMETER; } case SPNEGO_CLIENT_START: { /* The server offers a list of mechanisms */ - char **mechType; char *my_mechs[] = {NULL, NULL}; - int i; NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; if (!in.length) { /* client to produce negTokenInit */ - return gensec_spnego_client_netTokenInit(gensec_security, spnego_state, out_mem_ctx, in, out); + return gensec_spnego_client_negTokenInit(gensec_security, spnego_state, out_mem_ctx, in, out); } len = spnego_read_data(in, &spnego); @@ -354,50 +508,17 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA } } - mechType = spnego.negTokenInit.mechTypes; - for (i=0; mechType && mechType[i]; i++) { - nt_status = gensec_subcontext_start(gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - break; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechType[i]); - if (!NT_STATUS_IS_OK(nt_status)) { - gensec_end(&spnego_state->sub_sec_security); - continue; - } - - if (i == 0) { - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - spnego.negTokenInit.mechToken, - &unwrapped_out); - } else { - /* only get the helping start blob for the first OID */ - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - null_data_blob, - &unwrapped_out); - } - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", - spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); - gensec_end(&spnego_state->sub_sec_security); - } else { - break; - } - } - if (!mechType || !mechType[i]) { - DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); - } - - spnego_free_data(&spnego); + nt_status = gensec_spnego_parse_negTokenInit(gensec_security, + spnego_state, + out_mem_ctx, + spnego.negTokenInit.mechTypes, + spnego.negTokenInit.mechToken, + &unwrapped_out); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { return nt_status; } - + /* compose reply */ my_mechs[0] = spnego_state->sub_sec_security->ops->oid; @@ -441,40 +562,21 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA spnego_free_data(&spnego); return NT_STATUS_INVALID_PARAMETER; } - + nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, - spnego.negTokenTarg.responseToken, + spnego.negTokenTarg.responseToken, &unwrapped_out); - + + nt_status = gensec_spnego_server_negTokenTarg(gensec_security, + spnego_state, + out_mem_ctx, + nt_status, + unwrapped_out, + out); + spnego_free_data(&spnego); - /* compose reply */ - spnego_out.type = SPNEGO_NEG_TOKEN_TARG; - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego_state->state_position = SPNEGO_SERVER_TARG; - } else if (NT_STATUS_IS_OK(nt_status)) { - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; - spnego_state->state_position = SPNEGO_DONE; - } else { - spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; - DEBUG(1, ("SPNEGO(%s) login failed: %s\n", - spnego_state->sub_sec_security->ops->name, - nt_errstr(nt_status))); - spnego_state->state_position = SPNEGO_DONE; - } - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); - return NT_STATUS_INVALID_PARAMETER; - } - return nt_status; } case SPNEGO_CLIENT_TARG: @@ -584,12 +686,14 @@ static const struct gensec_security_ops gensec_spnego_security_ops = { .auth_type = DCERPC_AUTH_TYPE_SPNEGO, .oid = OID_SPNEGO, .client_start = gensec_spnego_client_start, + .server_start = gensec_spnego_server_start, .update = gensec_spnego_update, .seal_packet = gensec_spnego_seal_packet, .sign_packet = gensec_spnego_sign_packet, .check_packet = gensec_spnego_check_packet, .unseal_packet = gensec_spnego_unseal_packet, .session_key = gensec_spnego_session_key, + .session_info = gensec_spnego_session_info, .end = gensec_spnego_end }; diff --git a/source4/smb_server/negprot.c b/source4/smb_server/negprot.c index c9c775e62f..9e8a8f1f2c 100644 --- a/source4/smb_server/negprot.c +++ b/source4/smb_server/negprot.c @@ -171,54 +171,9 @@ static void reply_lanman2(struct smbsrv_request *req, uint16_t choice) req_push_str(req, NULL, lp_workgroup(), -1, STR_TERMINATE); - req_send_reply(req); -} - -#if 0 -/**************************************************************************** - Generate the spnego negprot reply blob. Return the number of bytes used. -****************************************************************************/ -static DATA_BLOB negprot_spnego(struct smbsrv_connection *smb_conn) -{ - DATA_BLOB blob; - uint8_t guid[16]; - const char *OIDs_krb5[] = {OID_KERBEROS5, - OID_KERBEROS5_OLD, - OID_NTLMSSP, - NULL}; - const char *OIDs_plain[] = {OID_NTLMSSP, NULL}; - char *principal; - - smb_conn->negotiate.spnego_negotiated = True; - - memset(guid, 0, 16); - safe_strcpy((char *)guid, lp_netbios_name(), 16); - strlower((char *)guid); - -#if 0 - /* strangely enough, NT does not send the single OID NTLMSSP when - not a ADS member, it sends no OIDs at all - - we can't do this until we teach our sesssion setup parser to know - about raw NTLMSSP (clients send no ASN.1 wrapping if we do this) - */ - if (lp_security() != SEC_ADS) { - memcpy(p, guid, 16); - return 16; - } -#endif - if (lp_security() != SEC_ADS) { - blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); - } else { - asprintf(&principal, "%s$@%s", guid, lp_realm()); - blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal); - free(principal); - } - - return blob; + req_send_reply(req); } -#endif /**************************************************************************** Reply for the nt protocol. @@ -243,13 +198,12 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) /* do spnego in user level security if the client supports it and we can do encrypted passwords */ - if (req->smb_conn->negotiate.encrypted_passwords && + if (0 && req->smb_conn->negotiate.encrypted_passwords && (lp_security() != SEC_SHARE) && lp_use_spnego() && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { -/* REWRITE negotiate_spnego = True; + negotiate_spnego = True; capabilities |= CAP_EXTENDED_SECURITY; -*/ } if (lp_unix_extensions()) { @@ -335,15 +289,51 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) req_push_str(req, NULL, lp_netbios_name(), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN); DEBUG(3,("not using SPNEGO\n")); } else { -#if 0 - DATA_BLOB blob = negprot_spnego(req->smb_conn); + struct gensec_security *gensec_security; + DATA_BLOB null_data_blob = data_blob(NULL, 0); + DATA_BLOB blob; + NTSTATUS nt_status = gensec_server_start(&gensec_security); + + if (req->smb_conn->negotiate.auth_context) { + smbsrv_terminate_connection(req->smb_conn, "reply_nt1: is this a secondary negprot? auth_context is non-NULL!\n"); + return; + } + + req->smb_conn->negotiate.auth_context = NULL; + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n"); + return; + } + + nt_status = gensec_start_mech_by_oid(gensec_security, OID_SPNEGO); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n"); + return; + } + + nt_status = gensec_update(gensec_security, req->mem_ctx, null_data_blob, &blob); + + if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n"); + return; + } + + req->smb_conn->negotiate.spnego_negotiated = True; + + req_grow_data(req, blob.length + 16); + /* a NOT very random guid */ + memset(req->out.ptr, '\0', 16); + req->out.ptr += 16; - req_grow_data(req, blob.length); memcpy(req->out.ptr, blob.data, blob.length); + SCVAL(req->out.vwv+1, VWV(16), blob.length + 16); + req->out.ptr += blob.length; DEBUG(3,("using SPNEGO\n")); -#else - smbsrv_terminate_connection(req->smb_conn, "no SPNEGO please"); -#endif } req_send_reply_nosign(req); diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c index cb0b3a6c5c..39aadf8778 100644 --- a/source4/smb_server/sesssetup.c +++ b/source4/smb_server/sesssetup.c @@ -103,19 +103,41 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; } - status = make_user_info_for_reply_enc(&user_info, - sess->nt1.in.user, sess->nt1.in.domain, - sess->nt1.in.password1, - sess->nt1.in.password2); - if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_ACCESS_DENIED; + if (req->smb_conn->negotiate.spnego_negotiated) { + struct auth_context *auth_context; + + status = make_auth_context_subsystem(&auth_context); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sess->nt1.in.user || !*sess->nt1.in.user) { + make_user_info_guest(&user_info); + } + + status = auth_context->check_ntlm_password(auth_context, + user_info, + &server_info); + + free_auth_context(&auth_context); + + } else { + status = make_user_info_for_reply_enc(&user_info, + sess->nt1.in.user, sess->nt1.in.domain, + sess->nt1.in.password1, + sess->nt1.in.password2); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_ACCESS_DENIED; + } + + status = req->smb_conn->negotiate + .auth_context->check_ntlm_password(req->smb_conn->negotiate + .auth_context, + user_info, + &server_info); } - status = req->smb_conn->negotiate - .auth_context->check_ntlm_password(req->smb_conn->negotiate - .auth_context, - user_info, - &server_info); if (!NT_STATUS_IS_OK(status)) { return nt_status_squash(status); } @@ -149,8 +171,74 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s */ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess) { - /* defer this one for now */ - return NT_STATUS_INVALID_LEVEL; + NTSTATUS status = NT_STATUS_ACCESS_DENIED; + struct smbsrv_session *smb_sess; + struct gensec_security *gensec_ctx = NULL; + struct auth_session_info *session_info = NULL; + uint16_t vuid; + + if (!req->smb_conn->negotiate.done_sesssetup) { + req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize; + req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; + } + + vuid = SVAL(req->in.hdr,HDR_UID); + smb_sess = smbsrv_session_find(req->smb_conn, vuid); + if (smb_sess) { + if (!smb_sess->gensec_ctx) { + return NT_STATUS_INVALID_HANDLE; + } + + /* what is when the client is already successful authentificated? */ + if (smb_sess->session_info) { + return NT_STATUS_ACCESS_DENIED; + } + + status = gensec_update(smb_sess->gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob); + } else { + status = gensec_server_start(&gensec_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); + return status; + } + + status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status))); + return status; + } + + status = gensec_update(gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob); + + } + + if (NT_STATUS_IS_OK(status)) { + DATA_BLOB session_key; + DATA_BLOB null_data_blob = data_blob(NULL, 0); + status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info); + if (NT_STATUS_IS_OK(gensec_session_key(smb_sess->gensec_ctx, + &session_key))) { + srv_setup_signing(req->smb_conn, &session_key, &null_data_blob); + req->seq_num = 0; + req->smb_conn->signing.next_seq_num = 2; + } + } + + if (!smb_sess) { + vuid = smbsrv_register_session(req->smb_conn, session_info, gensec_ctx); + if (vuid == UID_FIELD_INVALID) { + return NT_STATUS_ACCESS_DENIED; + } + } + + sess->spnego.out.action = 0; + sess->spnego.out.vuid = vuid; + sesssetup_common_strings(req, + &sess->spnego.out.os, + &sess->spnego.out.lanman, + &sess->spnego.out.domain); + + return status; } /* @@ -162,6 +250,9 @@ NTSTATUS sesssetup_backend(struct smbsrv_request *req, NTSTATUS status = NT_STATUS_INVALID_LEVEL; switch (sess->generic.level) { + case RAW_SESSSETUP_GENERIC: + status = NT_STATUS_INVALID_LEVEL; + break; case RAW_SESSSETUP_OLD: status = sesssetup_old(req, sess); break; |