diff options
| -rw-r--r-- | source3/rpc_server/srv_pipe.c | 377 | 
1 files changed, 173 insertions, 204 deletions
| diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index f1bc54250a..01cf65184d 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -33,8 +33,7 @@  #include "../librpc/gen_ndr/ndr_krb5pac.h"  #include "../libcli/auth/schannel.h"  #include "../libcli/auth/spnego.h" -#include "../libcli/auth/ntlmssp.h" -#include "ntlmssp_wrap.h" +#include "dcesrv_ntlmssp.h"  #include "rpc_server.h"  #include "rpc_dce.h"  #include "librpc/crypto/gse.h" @@ -251,72 +250,49 @@ bool create_next_pdu(struct pipes_struct *p)   the pipe struct.  *******************************************************************/ -static bool pipe_ntlmssp_verify_final(struct pipes_struct *p, -				      DATA_BLOB *p_resp_blob) +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, reply; +	DATA_BLOB session_key;  	NTSTATUS status; -	struct auth_ntlmssp_state *a = p->auth.a_u.auth_ntlmssp_state;  	bool ret; -	DEBUG(5,("pipe_ntlmssp_verify_final: pipe %s checking user details\n", -		 get_pipe_name_from_syntax(talloc_tos(), &p->syntax))); - -	ZERO_STRUCT(reply); - -	/* this has to be done as root in order to verify the password */ -	become_root(); -	status = auth_ntlmssp_update(a, *p_resp_blob, &reply); -	unbecome_root(); - -	/* Don't generate a reply. */ -	data_blob_free(&reply); - -	if (!NT_STATUS_IS_OK(status)) { -		return False; -	} +	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. */ -	if (p->auth.auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { -		if (!auth_ntlmssp_negotiated_sign(a)) { -			DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet integrity requested " -				"but client declined signing.\n", -				 get_pipe_name_from_syntax(talloc_tos(), -							   &p->syntax))); -			return False; -		} -	} -	if (p->auth.auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { -		if (!auth_ntlmssp_negotiated_seal(a)) { -			DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet privacy requested " -				"but client declined sealing.\n", -				 get_pipe_name_from_syntax(talloc_tos(), -							   &p->syntax))); -			return False; -		} +	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;  	} -	DEBUG(5, ("pipe_ntlmssp_verify_final: OK: user: %s domain: %s " -		  "workstation: %s\n", -		  auth_ntlmssp_get_username(a), -		  auth_ntlmssp_get_domain(a), -		  auth_ntlmssp_get_client(a))); - -	TALLOC_FREE(p->server_info); +	TALLOC_FREE(*server_info); -	status = auth_ntlmssp_steal_server_info(p, a, &p->server_info); +	status = ntlmssp_server_get_user_info(ntlmssp_ctx, +						mem_ctx, server_info);  	if (!NT_STATUS_IS_OK(status)) { -		DEBUG(0, ("auth_ntlmssp_server_info failed to obtain the server info for authenticated user: %s\n", -			  nt_errstr(status))); +		DEBUG(0, (__location__ ": failed to obtain the server info " +			  "for authenticated user: %s\n", nt_errstr(status)));  		return false;  	} -	if (p->server_info->ptok == NULL) { -		DEBUG(1,("Error: Authmodule failed to provide nt_user_token\n")); -		return False; +	if ((*server_info)->ptok == NULL) { +		DEBUG(1, ("Auth module failed to provide nt_user_token\n")); +		return false;  	}  	/* @@ -327,20 +303,27 @@ static bool pipe_ntlmssp_verify_final(struct pipes_struct *p,  	session_key = generic_session_key();  	if (session_key.data == NULL) { -		return False; +		return false;  	} -	ret = server_info_set_session_key(p->server_info, session_key); - +	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; +	return true;  }  static NTSTATUS pipe_gssapi_auth_bind_next(struct pipes_struct *p,  					   TALLOC_CTX *mem_ctx,  					   struct dcerpc_auth *pauth_info,  					   DATA_BLOB *response); +static NTSTATUS finalize_gssapi_bind(TALLOC_CTX *mem_ctx, +				     struct gse_context *gse_ctx, +				     struct client_address *client_id, +				     struct auth_serversupplied_info **sinfo);  /*******************************************************************   This is the "stage3" response after a bind request and reply. @@ -388,22 +371,52 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)  	switch (auth_info.auth_type) {  	case DCERPC_AUTH_TYPE_NTLMSSP: -		if (!pipe_ntlmssp_verify_final(p, &auth_info.credentials)) { -			goto err; -		} +		status = ntlmssp_server_step(p->auth.a_u.auth_ntlmssp_state, +					     pkt, &auth_info.credentials, +					     &response);  		break;  	case DCERPC_AUTH_TYPE_KRB5:  		status = pipe_gssapi_auth_bind_next(p, pkt,  						    &auth_info, &response); -		if (!NT_STATUS_IS_OK(status)) { +		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 */ + +	switch (auth_info.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)) {  			goto err;  		} -		if (response.length) { -			DEBUG(0, (__location__ ": This was supposed to be " -				  "the final leg, but gssapi machinery " -				  "claims a response is needed, " -				  "aborting auth!\n")); -			data_blob_free(&response); +		break; +	case DCERPC_AUTH_TYPE_KRB5: +		status = finalize_gssapi_bind(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)));  			goto err;  		} @@ -638,90 +651,72 @@ static bool pipe_spnego_auth_bind_negotiate(struct pipes_struct *p,  					    struct dcerpc_auth *pauth_info,  					    DATA_BLOB *response)  { -	DATA_BLOB secblob; -	DATA_BLOB chal; +	DATA_BLOB secblob = data_blob_null; +	DATA_BLOB chal = data_blob_null;  	char *OIDs[ASN1_MAX_OIDS];          int i;  	NTSTATUS status;          bool got_kerberos_mechanism = false; -	struct auth_ntlmssp_state *a = NULL; - -	ZERO_STRUCT(secblob); -	ZERO_STRUCT(chal); +	bool ret;  	if (pauth_info->credentials.data[0] != ASN1_APPLICATION(0)) { -		goto err; +		ret = false; +		goto done;  	}  	/* parse out the OIDs and the first sec blob */ -	if (!spnego_parse_negTokenInit(talloc_tos(), -			pauth_info->credentials, OIDs, NULL, &secblob)) { -		DEBUG(0,("pipe_spnego_auth_bind_negotiate: Failed to parse the security blob.\n")); -		goto err; +	ret = spnego_parse_negTokenInit(talloc_tos(), +			pauth_info->credentials, OIDs, NULL, &secblob); +	if (!ret) { +		DEBUG(0, (__location__ ": Failed to parse the secblob.\n")); +		goto done;          } -	if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) { +	if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || +	    strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {  		got_kerberos_mechanism = true;  	} -	for (i=0;OIDs[i];i++) { -		DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got OID %s\n", OIDs[i])); +	for (i = 0; OIDs[i]; i++) { +		DEBUG(3, (__location__ ": Got OID %s\n", OIDs[i]));  		TALLOC_FREE(OIDs[i]);  	} -	DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length)); +	DEBUG(3, (__location__ ": Got secblob of size %lu\n", +		  (unsigned long)secblob.length)); -	if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || USE_KERBEROS_KEYTAB) ) { -		bool ret; +	if (got_kerberos_mechanism && +	    ((lp_security()==SEC_ADS) || USE_KERBEROS_KEYTAB)) {  		ret = pipe_spnego_auth_bind_kerberos(p, mem_ctx, pauth_info,  						     &secblob, response); -		data_blob_free(&secblob); -		return ret; +		goto done;  	}  	/* Free any previous auth type. */  	free_pipe_auth_data(&p->auth); +	p->auth.a_u.auth_ntlmssp_state = NULL;  	if (!got_kerberos_mechanism) {  		/* Initialize the NTLM engine. */ -		status = auth_ntlmssp_start(&a); -		if (!NT_STATUS_IS_OK(status)) { -			goto err; -		} - -		/* Clear flags, -		 * then set them according to requested Auth Level */ -		auth_ntlmssp_and_flags(a, ~(NTLMSSP_NEGOTIATE_SIGN | -						NTLMSSP_NEGOTIATE_SEAL)); -		switch (pauth_info->auth_level) { -			case DCERPC_AUTH_LEVEL_INTEGRITY: -				auth_ntlmssp_or_flags(a, -						NTLMSSP_NEGOTIATE_SIGN); -				break; -			case DCERPC_AUTH_LEVEL_PRIVACY: -				/* Privacy always implies both sign and seal -				 * for ntlmssp */ -				auth_ntlmssp_or_flags(a, -						NTLMSSP_NEGOTIATE_SIGN | -						NTLMSSP_NEGOTIATE_SEAL); -				break; -			default: -				break; -		} -		/* -		 * Pass the first security blob of data to it. -		 * This can return an error or NT_STATUS_MORE_PROCESSING_REQUIRED -		 * which means we need another packet to complete the bind. -		 */ - -		status = auth_ntlmssp_update(a, secblob, &chal); +		status = ntlmssp_server_auth_start(p, +					(pauth_info->auth_level == +						DCERPC_AUTH_LEVEL_INTEGRITY), +					(pauth_info->auth_level == +						DCERPC_AUTH_LEVEL_PRIVACY), +					true, &secblob, &chal, +					&p->auth.a_u.auth_ntlmssp_state); -		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { -			DEBUG(3,("pipe_spnego_auth_bind_negotiate: auth_ntlmssp_update failed.\n")); -			goto err; +		if (!NT_STATUS_IS_OK(status)) { +			DEBUG(3, (__location__ ": Failed to start NTLMSSP " +				  "auth (%s).\n", nt_errstr(status))); +			ret = false; +			goto done;  		}  		/* Generate the response blob we need for step 2 of the bind. */ -		*response = spnego_gen_auth_response(mem_ctx, &chal, status, OID_NTLMSSP); +		*response = spnego_gen_auth_response( +					mem_ctx, &chal, +					NT_STATUS_MORE_PROCESSING_REQUIRED, +					OID_NTLMSSP);  	} else {  		/*  		 * SPNEGO negotiate down to NTLMSSP. The subsequent @@ -733,27 +728,18 @@ static bool pipe_spnego_auth_bind_negotiate(struct pipes_struct *p,  					OID_NTLMSSP);  	} -	/* auth_pad_len will be handled by the caller */ - -	p->auth.a_u.auth_ntlmssp_state = a;  	p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;  	p->auth.auth_type = DCERPC_AUTH_TYPE_SPNEGO;  	p->auth.spnego_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; -	data_blob_free(&secblob); -	data_blob_free(&chal); - -	/* We can't set pipe_bound True yet - we need an RPC_ALTER_CONTEXT response packet... */ -	return True; +	ret = true; - err: +done:  	data_blob_free(&secblob);  	data_blob_free(&chal); -	p->auth.a_u.auth_ntlmssp_state = NULL; - -	return False; +	return ret;  }  /******************************************************************* @@ -765,61 +751,75 @@ static bool pipe_spnego_auth_bind_continue(struct pipes_struct *p,  					   struct dcerpc_auth *pauth_info,  					   DATA_BLOB *response)  { -	DATA_BLOB auth_blob; -	DATA_BLOB auth_reply; -	struct auth_ntlmssp_state *a = p->auth.a_u.auth_ntlmssp_state; - -	ZERO_STRUCT(auth_blob); -	ZERO_STRUCT(auth_reply); +	DATA_BLOB auth_blob = data_blob_null; +	DATA_BLOB auth_reply = data_blob_null; +	NTSTATUS status; +	bool ret;  	/*  	 * NB. If we've negotiated down from krb5 to NTLMSSP we'll currently  	 * fail here as 'a' == NULL.  	 */  	if (p->auth.auth_type != DCERPC_AUTH_TYPE_SPNEGO || -	    p->auth.spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP || !a) { -		DEBUG(0,("pipe_spnego_auth_bind_continue: not in NTLMSSP auth state.\n")); +	    p->auth.spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP || +	    p->auth.a_u.auth_ntlmssp_state == NULL) { +		DEBUG(0, (__location__ ": not in NTLMSSP auth state.\n"));  		goto err;  	}  	if (pauth_info->credentials.data[0] != ASN1_CONTEXT(1)) { -		DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob type.\n")); +		DEBUG(0, (__location__ ": invalid SPNEGO blob type.\n"));  		goto err;  	} -	if (!spnego_parse_auth(talloc_tos(), pauth_info->credentials, &auth_blob)) { -		DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob.\n")); +	ret = spnego_parse_auth(talloc_tos(), +				pauth_info->credentials, &auth_blob); +	if (!ret) { +		DEBUG(0, (__location__ ": invalid SPNEGO blob.\n"));  		goto err;  	} -	/* -	 * The following call actually checks the challenge/response data. -	 * for correctness against the given DOMAIN\user name. -	 */ +	status = ntlmssp_server_step(p->auth.a_u.auth_ntlmssp_state, +				     p, &auth_blob, &auth_reply); +	if (NT_STATUS_EQUAL(status, +			    NT_STATUS_MORE_PROCESSING_REQUIRED) || +	    auth_reply.length) { +		DEBUG(0, (__location__ ": This was supposed to be the final " +			  "leg, but crypto machinery claims a response is " +			  "needed, aborting auth!\n")); +		goto err; +	} +	if (!NT_STATUS_IS_OK(status)) { +		DEBUG(0, ("Auth failed (%s)\n", nt_errstr(status))); +		goto err; +	} -	if (!pipe_ntlmssp_verify_final(p, &auth_blob)) { +	ret = pipe_ntlmssp_verify_final(p, +					p->auth.a_u.auth_ntlmssp_state, +					p->auth.auth_level, +					p->client_id, &p->syntax, +					&p->server_info); +	if (!ret) {  		goto err;  	}  	data_blob_free(&auth_blob);  	/* Generate the spnego "accept completed" blob - no incoming data. */ -	*response = spnego_gen_auth_response(mem_ctx, &auth_reply, NT_STATUS_OK, OID_NTLMSSP); +	*response = spnego_gen_auth_response(mem_ctx, &auth_reply, +					     NT_STATUS_OK, OID_NTLMSSP);  	data_blob_free(&auth_reply); -	p->pipe_bound = True; - -	return True; - - err: +	p->pipe_bound = true; +	return true; +err:  	data_blob_free(&auth_blob);  	data_blob_free(&auth_reply); -  	free_pipe_auth_data(&p->auth); -	return False; +	return false;  }  /******************************************************************* @@ -951,61 +951,37 @@ static bool pipe_ntlmssp_auth_bind(struct pipes_struct *p,  				   DATA_BLOB *response)  {          NTSTATUS status; -	struct auth_ntlmssp_state *a = NULL;  	if (strncmp((char *)auth_info->credentials.data, "NTLMSSP", 7) != 0) {  		DEBUG(0, ("Failed to read NTLMSSP in blob\n")); -                goto err; +                return false;          }  	/* We have an NTLMSSP blob. */ -	status = auth_ntlmssp_start(&a); -	if (!NT_STATUS_IS_OK(status)) { -		DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_start failed: %s\n", -			nt_errstr(status) )); -		goto err; -	} - -	/* Clear flags, then set them according to requested Auth Level */ -	auth_ntlmssp_and_flags(a, ~(NTLMSSP_NEGOTIATE_SIGN | -					NTLMSSP_NEGOTIATE_SEAL)); - -	switch (auth_info->auth_level) { -	case DCERPC_AUTH_LEVEL_INTEGRITY: -		auth_ntlmssp_or_flags(a, NTLMSSP_NEGOTIATE_SIGN); -		break; -	case DCERPC_AUTH_LEVEL_PRIVACY: -		/* Privacy always implies both sign and seal for ntlmssp */ -		auth_ntlmssp_or_flags(a, NTLMSSP_NEGOTIATE_SIGN | -					 NTLMSSP_NEGOTIATE_SEAL); -		break; -	default: -		break; -	} - -	status = auth_ntlmssp_update(a, auth_info->credentials, response); -	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { -		DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_update failed: %s\n", -			nt_errstr(status) )); -		goto err; +	status = ntlmssp_server_auth_start(p, +					   (auth_info->auth_level == +						DCERPC_AUTH_LEVEL_INTEGRITY), +					   (auth_info->auth_level == +						DCERPC_AUTH_LEVEL_PRIVACY), +					   true, +					   &auth_info->credentials, +					   response, +					   &p->auth.a_u.auth_ntlmssp_state); +	if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { +		DEBUG(0, (__location__ ": auth_ntlmssp_start failed: %s\n", +			  nt_errstr(status))); +		return false;  	}  	/* Make sure data is bound to the memctx, to be freed the caller */  	talloc_steal(mem_ctx, response->data); -	p->auth.a_u.auth_ntlmssp_state = a;  	p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;  	p->auth.auth_type = DCERPC_AUTH_TYPE_NTLMSSP; -	DEBUG(10,("pipe_ntlmssp_auth_bind: NTLMSSP auth started\n")); - -	/* We can't set pipe_bound True yet - we need an DCERPC_PKT_AUTH3 response packet... */ -	return True; +	DEBUG(10, (__location__ ": NTLMSSP auth started\n")); -  err: - -	TALLOC_FREE(a); -	return False; +	return true;  }  /******************************************************************* @@ -1280,14 +1256,7 @@ static NTSTATUS pipe_gssapi_auth_bind_next(struct pipes_struct *p,  	if (gse_require_more_processing(gse_ctx)) {  		/* ask for next leg */ -		return NT_STATUS_OK; -	} - -	status = finalize_gssapi_bind(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 NT_STATUS_ACCESS_DENIED; +		return NT_STATUS_MORE_PROCESSING_REQUIRED;  	}  	return NT_STATUS_OK; | 
