From 186f93633b4890c444115ac4eed109aa24f20b44 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 29 Jul 2010 19:55:44 -0400 Subject: s3-dcerpc: use common spengo wrapper code for client SPNEGO/NTLMSSP --- source3/librpc/rpc/dcerpc_helpers.c | 110 +++++++++++++++++++++++++++--------- source3/librpc/rpc/dcerpc_spnego.c | 108 +++++++++++++++++++++++++++++++++-- source3/librpc/rpc/dcerpc_spnego.h | 7 +++ 3 files changed, 194 insertions(+), 31 deletions(-) (limited to 'source3/librpc') diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c index 592832bdd8..26b44de5ea 100644 --- a/source3/librpc/rpc/dcerpc_helpers.c +++ b/source3/librpc/rpc/dcerpc_helpers.c @@ -524,6 +524,7 @@ static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx, { enum dcerpc_AuthType auth_type; struct gse_context *gse_ctx; + struct auth_ntlmssp_state *ntlmssp_ctx; void *auth_ctx; NTSTATUS status; @@ -548,8 +549,15 @@ static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx, auth_level, rpc_out); break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - status = NT_STATUS_NOT_IMPLEMENTED; + case DCERPC_AUTH_TYPE_NTLMSSP: + ntlmssp_ctx = talloc_get_type(auth_ctx, + struct auth_ntlmssp_state); + if (!ntlmssp_ctx) { + status = NT_STATUS_INTERNAL_ERROR; + break; + } + status = add_ntlmssp_auth_footer(ntlmssp_ctx, + auth_level, rpc_out); break; default: @@ -560,6 +568,55 @@ static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx, return status; } +static NTSTATUS get_spnego_auth_footer(TALLOC_CTX *mem_ctx, + struct spnego_context *sp_ctx, + enum dcerpc_AuthLevel auth_level, + DATA_BLOB *data, DATA_BLOB *full_pkt, + DATA_BLOB *auth_token) +{ + enum dcerpc_AuthType auth_type; + struct auth_ntlmssp_state *ntlmssp_ctx; + struct gse_context *gse_ctx; + void *auth_ctx; + NTSTATUS status; + + status = spnego_get_negotiated_mech(sp_ctx, &auth_type, &auth_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (auth_type) { + case DCERPC_AUTH_TYPE_KRB5: + gse_ctx = talloc_get_type(auth_ctx, + struct gse_context); + if (!gse_ctx) { + return NT_STATUS_INVALID_PARAMETER; + } + + DEBUG(10, ("KRB5 auth\n")); + + return get_gssapi_auth_footer(mem_ctx, gse_ctx, + auth_level, + data, full_pkt, + auth_token); + case DCERPC_AUTH_TYPE_NTLMSSP: + ntlmssp_ctx = talloc_get_type(auth_ctx, + struct auth_ntlmssp_state); + if (!ntlmssp_ctx) { + return NT_STATUS_INVALID_PARAMETER; + } + + DEBUG(10, ("NTLMSSP auth\n")); + + return get_ntlmssp_auth_footer(ntlmssp_ctx, + auth_level, + data, full_pkt, + auth_token); + default: + return NT_STATUS_INVALID_PARAMETER; + } +} + /** * @brief Append an auth footer according to what is the current mechanism * @@ -618,12 +675,16 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, status = NT_STATUS_OK; break; case DCERPC_AUTH_TYPE_SPNEGO: - if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { - return add_spnego_auth_footer(auth->a_u.spnego_state, - auth->auth_level, - rpc_out); + if (auth->spnego_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { + /* compat for server code */ + return add_ntlmssp_auth_footer( + auth->a_u.auth_ntlmssp_state, + auth->auth_level, + rpc_out); } - /* fall thorugh */ + status = add_spnego_auth_footer(auth->a_u.spnego_state, + auth->auth_level, rpc_out); + break; case DCERPC_AUTH_TYPE_NTLMSSP: status = add_ntlmssp_auth_footer(auth->a_u.auth_ntlmssp_state, auth->auth_level, @@ -731,26 +792,12 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, return NT_STATUS_OK; case DCERPC_AUTH_TYPE_SPNEGO: - if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { - enum dcerpc_AuthType auth_type; - struct gse_context *gse_ctx; - void *auth_ctx; - - status = spnego_get_negotiated_mech( - auth->a_u.spnego_state, - &auth_type, &auth_ctx); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - gse_ctx = talloc_get_type(auth_ctx, - struct gse_context); - if (!gse_ctx) { - return NT_STATUS_INVALID_PARAMETER; - } + if (auth->spnego_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { + /* compat for server code */ + DEBUG(10, ("NTLMSSP auth\n")); - DEBUG(10, ("KRB5 auth\n")); - - status = get_gssapi_auth_footer(pkt, gse_ctx, + status = get_ntlmssp_auth_footer( + auth->a_u.auth_ntlmssp_state, auth->auth_level, &data, &full_pkt, &auth_info.credentials); @@ -759,7 +806,16 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, } break; } - /* fall through */ + + status = get_spnego_auth_footer(pkt, auth->a_u.spnego_state, + auth->auth_level, + &data, &full_pkt, + &auth_info.credentials); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + case DCERPC_AUTH_TYPE_NTLMSSP: DEBUG(10, ("NTLMSSP auth\n")); diff --git a/source3/librpc/rpc/dcerpc_spnego.c b/source3/librpc/rpc/dcerpc_spnego.c index e733469ac3..a0832ce09f 100644 --- a/source3/librpc/rpc/dcerpc_spnego.c +++ b/source3/librpc/rpc/dcerpc_spnego.c @@ -19,6 +19,8 @@ #include "includes.h" #include "../libcli/auth/spnego.h" +#include "include/ntlmssp_wrap.h" +#include "librpc/gen_ndr/ntlmssp.h" #include "dcerpc_spnego.h" #include "dcerpc_gssapi.h" @@ -26,7 +28,7 @@ struct spnego_context { enum dcerpc_AuthType auth_type; union { - struct auth_ntlmssp_state *auth_ntlmssp_state; + struct auth_ntlmssp_state *ntlmssp_state; struct gse_context *gssapi_state; } mech_ctx; @@ -88,12 +90,80 @@ NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthLevel auth_level, + const char *domain, + const char *username, + const char *password, + struct spnego_context **spnego_ctx) +{ + struct spnego_context *sp_ctx; + NTSTATUS status; + + status = spnego_context_init(mem_ctx, + DCERPC_AUTH_TYPE_NTLMSSP, &sp_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = auth_ntlmssp_client_start(sp_ctx, + global_myname(), + lp_workgroup(), + lp_client_ntlmv2_auth(), + &sp_ctx->mech_ctx.ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sp_ctx); + return status; + } + + status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state, + username); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sp_ctx); + return status; + } + + status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state, + domain); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sp_ctx); + return status; + } + + status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state, + password); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sp_ctx); + return status; + } + + /* + * Turn off sign+seal to allow selected auth level to turn it back on. + */ + auth_ntlmssp_and_flags(sp_ctx->mech_ctx.ntlmssp_state, + ~(NTLMSSP_NEGOTIATE_SIGN | + NTLMSSP_NEGOTIATE_SEAL)); + + if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + auth_ntlmssp_or_flags(sp_ctx->mech_ctx.ntlmssp_state, + NTLMSSP_NEGOTIATE_SIGN); + } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + auth_ntlmssp_or_flags(sp_ctx->mech_ctx.ntlmssp_state, + NTLMSSP_NEGOTIATE_SEAL | + NTLMSSP_NEGOTIATE_SIGN); + } + + *spnego_ctx = sp_ctx; + return NT_STATUS_OK; +} + NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx, struct spnego_context *sp_ctx, DATA_BLOB *spnego_in, DATA_BLOB *spnego_out) { struct gse_context *gse_ctx; + struct auth_ntlmssp_state *ntlmssp_ctx; struct spnego_data sp_in, sp_out; DATA_BLOB token_in = data_blob_null; DATA_BLOB token_out = data_blob_null; @@ -129,6 +199,7 @@ NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx, if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) { if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) { sp_ctx->state = SPNEGO_CONV_AUTH_DONE; + *spnego_out = data_blob_null; status = NT_STATUS_OK; } else { status = NT_STATUS_ACCESS_DENIED; @@ -152,8 +223,21 @@ NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx, break; case DCERPC_AUTH_TYPE_NTLMSSP: - status = NT_STATUS_NOT_IMPLEMENTED; - goto done; + + ntlmssp_ctx = sp_ctx->mech_ctx.ntlmssp_state; + status = auth_ntlmssp_update(ntlmssp_ctx, + token_in, &token_out); + if (NT_STATUS_EQUAL(status, + NT_STATUS_MORE_PROCESSING_REQUIRED)) { + mech_wants_more = true; + } else if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + mech_oids[0] = OID_NTLMSSP; + + break; + default: status = NT_STATUS_INTERNAL_ERROR; goto done; @@ -227,6 +311,8 @@ bool spnego_require_more_processing(struct spnego_context *sp_ctx) case DCERPC_AUTH_TYPE_KRB5: gse_ctx = sp_ctx->mech_ctx.gssapi_state; return gse_require_more_processing(gse_ctx); + case DCERPC_AUTH_TYPE_NTLMSSP: + return false; default: DEBUG(0, ("Unsupported type in request!\n")); return false; @@ -242,7 +328,7 @@ NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx, *auth_context = sp_ctx->mech_ctx.gssapi_state; break; case DCERPC_AUTH_TYPE_NTLMSSP: - *auth_context = sp_ctx->mech_ctx.auth_ntlmssp_state; + *auth_context = sp_ctx->mech_ctx.ntlmssp_state; break; default: return NT_STATUS_INTERNAL_ERROR; @@ -252,3 +338,17 @@ NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx, return NT_STATUS_OK; } +DATA_BLOB spnego_get_session_key(struct spnego_context *sp_ctx) +{ + switch (sp_ctx->auth_type) { + case DCERPC_AUTH_TYPE_KRB5: + return gse_get_session_key(sp_ctx->mech_ctx.gssapi_state); + case DCERPC_AUTH_TYPE_NTLMSSP: + return auth_ntlmssp_get_session_key( + sp_ctx->mech_ctx.ntlmssp_state); + default: + DEBUG(0, ("Unsupported type in request!\n")); + return data_blob_null; + } +} + diff --git a/source3/librpc/rpc/dcerpc_spnego.h b/source3/librpc/rpc/dcerpc_spnego.h index 08458b246f..58363fd072 100644 --- a/source3/librpc/rpc/dcerpc_spnego.h +++ b/source3/librpc/rpc/dcerpc_spnego.h @@ -31,6 +31,12 @@ NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx, const char *password, uint32_t add_gss_c_flags, struct spnego_context **spengo_ctx); +NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthLevel auth_level, + const char *domain, + const char *username, + const char *password, + struct spnego_context **spnego_ctx); NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx, struct spnego_context *sp_ctx, @@ -43,4 +49,5 @@ NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx, enum dcerpc_AuthType *auth_type, void **auth_context); +DATA_BLOB spnego_get_session_key(struct spnego_context *sp_ctx); #endif /* _DCERPC_SPENGO_H_ */ -- cgit