diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index ba6acc82899..fab7383ce33 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -248,259 +248,6 @@ bool create_next_pdu(struct pipes_struct *p) return true; } -/******************************************************************* - Process an NTLMSSP authentication response. - If this function succeeds, the user has been authenticated - and their domain, name and calling workstation stored in - the pipe struct. -*******************************************************************/ - -static bool pipe_ntlmssp_verify_final(TALLOC_CTX *mem_ctx, - struct auth_ntlmssp_state *ntlmssp_ctx, - enum dcerpc_AuthLevel auth_level, - struct client_address *client_id, - struct ndr_syntax_id *syntax, - struct auth_serversupplied_info **server_info) -{ - DATA_BLOB session_key; - NTSTATUS status; - bool ret; - - DEBUG(5, (__location__ ": pipe %s checking user details\n", - get_pipe_name_from_syntax(talloc_tos(), syntax))); - - /* Finally - if the pipe negotiated integrity (sign) or privacy (seal) - ensure the underlying NTLMSSP flags are also set. If not we should - refuse the bind. */ - - status = ntlmssp_server_check_flags(ntlmssp_ctx, - (auth_level == - DCERPC_AUTH_LEVEL_INTEGRITY), - (auth_level == - DCERPC_AUTH_LEVEL_PRIVACY)); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, (__location__ ": Client failed to negotatie proper " - "security for pipe %s\n", - get_pipe_name_from_syntax(talloc_tos(), syntax))); - return false; - } - - TALLOC_FREE(*server_info); - - status = ntlmssp_server_get_user_info(ntlmssp_ctx, - mem_ctx, server_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, (__location__ ": failed to obtain the server info " - "for authenticated user: %s\n", nt_errstr(status))); - return false; - } - - if ((*server_info)->ptok == NULL) { - DEBUG(1, ("Auth module failed to provide nt_user_token\n")); - return false; - } - - /* - * We're an authenticated bind over smb, so the session key needs to - * be set to "SystemLibraryDTC". Weird, but this is what Windows - * does. See the RPC-SAMBA3SESSIONKEY. - */ - - session_key = generic_session_key(); - if (session_key.data == NULL) { - return false; - } - - ret = server_info_set_session_key((*server_info), session_key); - data_blob_free(&session_key); - if (!ret) { - DEBUG(0, ("Failed to set session key!\n")); - return false; - } - - return true; -} - -static NTSTATUS pipe_gssapi_verify_final(TALLOC_CTX *mem_ctx, - struct gse_context *gse_ctx, - struct client_address *client_id, - struct auth_serversupplied_info **server_info); - -static NTSTATUS pipe_auth_verify_final(struct pipes_struct *p); - -/******************************************************************* - This is the "stage3" response after a bind request and reply. -*******************************************************************/ - -bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) -{ - struct dcerpc_auth auth_info; - DATA_BLOB response = data_blob_null; - NTSTATUS status; - - DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); - - if (pkt->auth_length == 0) { - DEBUG(0, ("No auth field sent for bind request!\n")); - goto err; - } - - /* Ensure there's enough data for an authenticated request. */ - if (pkt->frag_length < RPC_HEADER_LEN - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len " - "%u is too large.\n", - (unsigned int)pkt->auth_length)); - goto err; - } - - /* - * Decode the authentication verifier response. - */ - - status = dcerpc_pull_dcerpc_auth(pkt, - &pkt->u.auth3.auth_info, - &auth_info, p->endian); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n")); - goto err; - } - - /* We must NEVER look at auth_info->auth_pad_len here, - * as old Samba client code gets it wrong and sends it - * as zero. JRA. - */ - - switch (auth_info.auth_type) { - case DCERPC_AUTH_TYPE_NTLMSSP: - status = ntlmssp_server_step(p->auth.a_u.auth_ntlmssp_state, - pkt, &auth_info.credentials, - &response); - break; - case DCERPC_AUTH_TYPE_KRB5: - status = gssapi_server_step(p->auth.a_u.gssapi_state, - pkt, &auth_info.credentials, - &response); - break; - case DCERPC_AUTH_TYPE_SPNEGO: - status = spnego_server_step(p->auth.a_u.spnego_state, - pkt, &auth_info.credentials, - &response); - break; - default: - DEBUG(0, (__location__ ": incorrect auth type (%u).\n", - (unsigned int)auth_info.auth_type)); - return false; - } - - if (NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED) || - response.length) { - DEBUG(0, (__location__ ": This was supposed to be the final " - "leg, but crypto machinery claims a response is " - "needed, aborting auth!\n")); - data_blob_free(&response); - goto err; - } - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Auth failed (%s)\n", nt_errstr(status))); - goto err; - } - - /* Now verify auth was indeed successful and extract server info */ - status = pipe_auth_verify_final(p); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Auth Verify failed (%s)\n", nt_errstr(status))); - goto err; - } - - return true; - -err: - - free_pipe_auth_data(&p->auth); - return false; -} - - -static NTSTATUS pipe_auth_verify_final(struct pipes_struct *p) -{ - enum spnego_mech auth_type; - struct auth_ntlmssp_state *ntlmssp_ctx; - struct gse_context *gse_ctx; - void *mech_ctx; - NTSTATUS status; - - switch (p->auth.auth_type) { - case DCERPC_AUTH_TYPE_NTLMSSP: - if (!pipe_ntlmssp_verify_final(p, - p->auth.a_u.auth_ntlmssp_state, - p->auth.auth_level, - p->client_id, &p->syntax, - &p->server_info)) { - return NT_STATUS_ACCESS_DENIED; - } - break; - case DCERPC_AUTH_TYPE_KRB5: - status = pipe_gssapi_verify_final(p, - p->auth.a_u.gssapi_state, - p->client_id, - &p->server_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("gssapi bind failed with: %s", - nt_errstr(status))); - return status; - } - break; - case DCERPC_AUTH_TYPE_SPNEGO: - status = spnego_get_negotiated_mech(p->auth.a_u.spnego_state, - &auth_type, &mech_ctx); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Bad SPNEGO state (%s)\n", - nt_errstr(status))); - return status; - } - switch(auth_type) { - case SPNEGO_KRB5: - gse_ctx = talloc_get_type_abort(mech_ctx, - struct gse_context); - status = pipe_gssapi_verify_final(p, gse_ctx, - p->client_id, - &p->server_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("gssapi bind failed with: %s", - nt_errstr(status))); - return status; - } - break; - case SPNEGO_NTLMSSP: - ntlmssp_ctx = talloc_get_type_abort(mech_ctx, - struct auth_ntlmssp_state); - if (!pipe_ntlmssp_verify_final(p, ntlmssp_ctx, - p->auth.auth_level, - p->client_id, - &p->syntax, - &p->server_info)) { - return NT_STATUS_ACCESS_DENIED; - } - break; - default: - DEBUG(0, (__location__ ": incorrect spnego type " - "(%d).\n", auth_type)); - return NT_STATUS_ACCESS_DENIED; - } - break; - default: - DEBUG(0, (__location__ ": incorrect auth type (%u).\n", - (unsigned int)p->auth.auth_type)); - return NT_STATUS_ACCESS_DENIED; - } - - p->pipe_bound = true; - - return NT_STATUS_OK; -} static bool pipe_init_outgoing_data(struct pipes_struct *p); @@ -890,6 +637,79 @@ static bool pipe_ntlmssp_auth_bind(struct pipes_struct *p, return true; } +/******************************************************************* + Process an NTLMSSP authentication response. + If this function succeeds, the user has been authenticated + and their domain, name and calling workstation stored in + the pipe struct. +*******************************************************************/ + +static bool pipe_ntlmssp_verify_final(TALLOC_CTX *mem_ctx, + struct auth_ntlmssp_state *ntlmssp_ctx, + enum dcerpc_AuthLevel auth_level, + struct client_address *client_id, + struct ndr_syntax_id *syntax, + struct auth_serversupplied_info **server_info) +{ + DATA_BLOB session_key; + NTSTATUS status; + bool ret; + + DEBUG(5, (__location__ ": pipe %s checking user details\n", + get_pipe_name_from_syntax(talloc_tos(), syntax))); + + /* Finally - if the pipe negotiated integrity (sign) or privacy (seal) + ensure the underlying NTLMSSP flags are also set. If not we should + refuse the bind. */ + + status = ntlmssp_server_check_flags(ntlmssp_ctx, + (auth_level == + DCERPC_AUTH_LEVEL_INTEGRITY), + (auth_level == + DCERPC_AUTH_LEVEL_PRIVACY)); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, (__location__ ": Client failed to negotatie proper " + "security for pipe %s\n", + get_pipe_name_from_syntax(talloc_tos(), syntax))); + return false; + } + + TALLOC_FREE(*server_info); + + status = ntlmssp_server_get_user_info(ntlmssp_ctx, + mem_ctx, server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, (__location__ ": failed to obtain the server info " + "for authenticated user: %s\n", nt_errstr(status))); + return false; + } + + if ((*server_info)->ptok == NULL) { + DEBUG(1, ("Auth module failed to provide nt_user_token\n")); + return false; + } + + /* + * We're an authenticated bind over smb, so the session key needs to + * be set to "SystemLibraryDTC". Weird, but this is what Windows + * does. See the RPC-SAMBA3SESSIONKEY. + */ + + session_key = generic_session_key(); + if (session_key.data == NULL) { + return false; + } + + ret = server_info_set_session_key((*server_info), session_key); + data_blob_free(&session_key); + if (!ret) { + DEBUG(0, ("Failed to set session key!\n")); + return false; + } + + return true; +} + /******************************************************************* Handle a GSSAPI bind auth. *******************************************************************/ @@ -992,6 +812,84 @@ static NTSTATUS pipe_gssapi_verify_final(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +static NTSTATUS pipe_auth_verify_final(struct pipes_struct *p) +{ + enum spnego_mech auth_type; + struct auth_ntlmssp_state *ntlmssp_ctx; + struct gse_context *gse_ctx; + void *mech_ctx; + NTSTATUS status; + + switch (p->auth.auth_type) { + case DCERPC_AUTH_TYPE_NTLMSSP: + if (!pipe_ntlmssp_verify_final(p, + p->auth.a_u.auth_ntlmssp_state, + p->auth.auth_level, + p->client_id, &p->syntax, + &p->server_info)) { + return NT_STATUS_ACCESS_DENIED; + } + break; + case DCERPC_AUTH_TYPE_KRB5: + status = pipe_gssapi_verify_final(p, + p->auth.a_u.gssapi_state, + p->client_id, + &p->server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("gssapi bind failed with: %s", + nt_errstr(status))); + return status; + } + break; + case DCERPC_AUTH_TYPE_SPNEGO: + status = spnego_get_negotiated_mech(p->auth.a_u.spnego_state, + &auth_type, &mech_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Bad SPNEGO state (%s)\n", + nt_errstr(status))); + return status; + } + switch(auth_type) { + case SPNEGO_KRB5: + gse_ctx = talloc_get_type_abort(mech_ctx, + struct gse_context); + status = pipe_gssapi_verify_final(p, gse_ctx, + p->client_id, + &p->server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("gssapi bind failed with: %s", + nt_errstr(status))); + return status; + } + break; + case SPNEGO_NTLMSSP: + ntlmssp_ctx = talloc_get_type_abort(mech_ctx, + struct auth_ntlmssp_state); + if (!pipe_ntlmssp_verify_final(p, ntlmssp_ctx, + p->auth.auth_level, + p->client_id, + &p->syntax, + &p->server_info)) { + return NT_STATUS_ACCESS_DENIED; + } + break; + default: + DEBUG(0, (__location__ ": incorrect spnego type " + "(%d).\n", auth_type)); + return NT_STATUS_ACCESS_DENIED; + } + break; + default: + DEBUG(0, (__location__ ": incorrect auth type (%u).\n", + (unsigned int)p->auth.auth_type)); + return NT_STATUS_ACCESS_DENIED; + } + + p->pipe_bound = true; + + return NT_STATUS_OK; +} + /******************************************************************* Respond to a pipe bind request. *******************************************************************/ @@ -1279,6 +1177,101 @@ static bool api_pipe_bind_req(struct pipes_struct *p, return setup_bind_nak(p, pkt); } +/******************************************************************* + This is the "stage3" response after a bind request and reply. +*******************************************************************/ + +bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) +{ + struct dcerpc_auth auth_info; + DATA_BLOB response = data_blob_null; + NTSTATUS status; + + DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); + + if (pkt->auth_length == 0) { + DEBUG(0, ("No auth field sent for bind request!\n")); + goto err; + } + + /* Ensure there's enough data for an authenticated request. */ + if (pkt->frag_length < RPC_HEADER_LEN + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length) { + DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len " + "%u is too large.\n", + (unsigned int)pkt->auth_length)); + goto err; + } + + /* + * Decode the authentication verifier response. + */ + + status = dcerpc_pull_dcerpc_auth(pkt, + &pkt->u.auth3.auth_info, + &auth_info, p->endian); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n")); + goto err; + } + + /* We must NEVER look at auth_info->auth_pad_len here, + * as old Samba client code gets it wrong and sends it + * as zero. JRA. + */ + + switch (auth_info.auth_type) { + case DCERPC_AUTH_TYPE_NTLMSSP: + status = ntlmssp_server_step(p->auth.a_u.auth_ntlmssp_state, + pkt, &auth_info.credentials, + &response); + break; + case DCERPC_AUTH_TYPE_KRB5: + status = gssapi_server_step(p->auth.a_u.gssapi_state, + pkt, &auth_info.credentials, + &response); + break; + case DCERPC_AUTH_TYPE_SPNEGO: + status = spnego_server_step(p->auth.a_u.spnego_state, + pkt, &auth_info.credentials, + &response); + break; + default: + DEBUG(0, (__location__ ": incorrect auth type (%u).\n", + (unsigned int)auth_info.auth_type)); + return false; + } + + if (NT_STATUS_EQUAL(status, + NT_STATUS_MORE_PROCESSING_REQUIRED) || + response.length) { + DEBUG(0, (__location__ ": This was supposed to be the final " + "leg, but crypto machinery claims a response is " + "needed, aborting auth!\n")); + data_blob_free(&response); + goto err; + } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Auth failed (%s)\n", nt_errstr(status))); + goto err; + } + + /* Now verify auth was indeed successful and extract server info */ + status = pipe_auth_verify_final(p); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Auth Verify failed (%s)\n", nt_errstr(status))); + goto err; + } + + return true; + +err: + + free_pipe_auth_data(&p->auth); + return false; +} + /**************************************************************************** Deal with an alter context call. Can be third part of 3 leg auth request for SPNEGO calls. @@ -1376,6 +1369,12 @@ static bool api_pipe_alter_context(struct pipes_struct *p, &auth_info.credentials, &auth_resp); break; + case DCERPC_AUTH_TYPE_NTLMSSP: + status = ntlmssp_server_step(p->auth.a_u.auth_ntlmssp_state, + pkt, + &auth_info.credentials, + &auth_resp); + break; default: DEBUG(3, (__location__ ": Usupported auth type (%d) "