예제 #1
0
static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
{
	NTSTATUS nt_status;
	int ret;
	struct gensec_gssapi_state *gensec_gssapi_state;
	struct cli_credentials *machine_account;
	struct gssapi_creds_container *gcc;

	nt_status = gensec_gssapi_start(gensec_security);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);

	machine_account = gensec_get_credentials(gensec_security);
	
	if (!machine_account) {
		DEBUG(3, ("No machine account credentials specified\n"));
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	} else {
		ret = cli_credentials_get_server_gss_creds(machine_account, 
							   gensec_security->settings->lp_ctx, &gcc);
		if (ret) {
			DEBUG(1, ("Aquiring acceptor credentials failed: %s\n", 
				  error_message(ret)));
			return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		}
	}

	gensec_gssapi_state->server_cred = gcc;
	return NT_STATUS_OK;

}
예제 #2
0
static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_security,
					   struct tevent_context *ev)
{
	struct gensec_gssapi_state *gensec_gssapi_state;
	struct gssapi_creds_container *gcc;
	struct cli_credentials *creds = gensec_get_credentials(gensec_security);
	const char *error_string;
	int ret;

	gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);

	/* Only run this the first time the update() call is made */
	if (gensec_gssapi_state->client_cred) {
		return NT_STATUS_OK;
	}

	ret = cli_credentials_get_client_gss_creds(creds,
						   ev,
						   gensec_security->settings->lp_ctx, &gcc, &error_string);
	switch (ret) {
	case 0:
		break;
	case EINVAL:
		DEBUG(3, ("Cannot obtain client GSS credentials we need to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
		return NT_STATUS_INVALID_PARAMETER;
	case KRB5KDC_ERR_PREAUTH_FAILED:
	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
		DEBUG(1, ("Wrong username or password: %s\n", error_string));
		return NT_STATUS_LOGON_FAILURE;
	case KRB5KDC_ERR_CLIENT_REVOKED:
		DEBUG(1, ("Account locked out: %s\n", error_string));
		return NT_STATUS_ACCOUNT_LOCKED_OUT;
	case KRB5_REALM_UNKNOWN:
	case KRB5_KDC_UNREACH:
		DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
		return NT_STATUS_NO_LOGON_SERVERS;
	case KRB5_CC_NOTFOUND:
	case KRB5_CC_END:
		DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
		return NT_STATUS_TIME_DIFFERENCE_AT_DC;
	default:
		DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
		return NT_STATUS_UNSUCCESSFUL;
	}

	gensec_gssapi_state->client_cred = gcc;
	if (!talloc_reference(gensec_gssapi_state, gcc)) {
		return NT_STATUS_NO_MEMORY;
	}

	return NT_STATUS_OK;
}
예제 #3
0
파일: ntlm_auth.c 프로젝트: rti7743/samba
static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, 
				  struct loadparm_context *lp_ctx,
				  char *buf, int length, void **private1,
				  unsigned int mux_id, void **private2) 
{
	DATA_BLOB in;
	DATA_BLOB out = data_blob(NULL, 0);
	char *out_base64 = NULL;
	const char *reply_arg = NULL;
	struct gensec_ntlm_state {
		struct gensec_security *gensec_state;
		const char *set_password;
	};
	struct gensec_ntlm_state *state;
	struct tevent_context *ev;
	struct imessaging_context *msg;

	NTSTATUS nt_status;
	bool first = false;
	const char *reply_code;
	struct cli_credentials *creds;

	static char *want_feature_list = NULL;
	static DATA_BLOB session_key;

	TALLOC_CTX *mem_ctx;

	if (*private1) {
		state = (struct gensec_ntlm_state *)*private1;
	} else {
		state = talloc_zero(NULL, struct gensec_ntlm_state);
		if (!state) {
			mux_printf(mux_id, "BH No Memory\n");
			exit(1);
		}
		*private1 = state;
		if (opt_password) {
			state->set_password = opt_password;
		}
	}
	
	if (strlen(buf) < 2) {
		DEBUG(1, ("query [%s] invalid", buf));
		mux_printf(mux_id, "BH Query invalid\n");
		return;
	}

	if (strlen(buf) > 3) {
		if(strncmp(buf, "SF ", 3) == 0) {
			DEBUG(10, ("Setting flags to negotiate\n"));
			talloc_free(want_feature_list);
			want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
			mux_printf(mux_id, "OK\n");
			return;
		}
		in = base64_decode_data_blob(buf + 3);
	} else {
		in = data_blob(NULL, 0);
	}

	if (strncmp(buf, "YR", 2) == 0) {
		if (state->gensec_state) {
			talloc_free(state->gensec_state);
			state->gensec_state = NULL;
		}
	} else if ( (strncmp(buf, "OK", 2) == 0)) {
		/* Just return BH, like ntlm_auth from Samba 3 does. */
		mux_printf(mux_id, "BH Command expected\n");
		data_blob_free(&in);
		return;
	} else if ( (strncmp(buf, "TT ", 3) != 0) &&
		    (strncmp(buf, "KK ", 3) != 0) &&
		    (strncmp(buf, "AF ", 3) != 0) &&
		    (strncmp(buf, "NA ", 3) != 0) && 
		    (strncmp(buf, "UG", 2) != 0) && 
		    (strncmp(buf, "PW ", 3) != 0) &&
		    (strncmp(buf, "GK", 2) != 0) &&
		    (strncmp(buf, "GF", 2) != 0)) {
		DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
		mux_printf(mux_id, "BH SPNEGO request invalid\n");
		data_blob_free(&in);
		return;
	}

	ev = s4_event_context_init(state);
	if (!ev) {
		exit(1);
	}

	mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");

	/* setup gensec */
	if (!(state->gensec_state)) {
		switch (stdio_helper_mode) {
		case GSS_SPNEGO_CLIENT:
		case NTLMSSP_CLIENT_1:
			/* setup the client side */

			nt_status = gensec_client_start(NULL, &state->gensec_state, ev, 
							lpcfg_gensec_settings(NULL, lp_ctx));
			if (!NT_STATUS_IS_OK(nt_status)) {
				talloc_free(mem_ctx);
				exit(1);
			}

			break;
		case GSS_SPNEGO_SERVER:
		case SQUID_2_5_NTLMSSP:
		{
			const char *winbind_method[] = { "winbind", NULL };
			struct auth4_context *auth_context;

			msg = imessaging_client_init(state, lpcfg_imessaging_path(state, lp_ctx), ev);
			if (!msg) {
				talloc_free(mem_ctx);
				exit(1);
			}
			nt_status = auth_context_create_methods(mem_ctx, 
								winbind_method,
								ev, 
								msg, 
								lp_ctx,
								NULL,
								&auth_context);
	
			if (!NT_STATUS_IS_OK(nt_status)) {
				talloc_free(mem_ctx);
				exit(1);
			}
			
			if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, 
								 lpcfg_gensec_settings(state, lp_ctx),
								 auth_context, &state->gensec_state))) {
				talloc_free(mem_ctx);
				exit(1);
			}
			break;
		}
		default:
			talloc_free(mem_ctx);
			abort();
		}

		creds = cli_credentials_init(state->gensec_state);
		cli_credentials_set_conf(creds, lp_ctx);
		if (opt_username) {
			cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
		}
		if (opt_domain) {
			cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
		}
		if (state->set_password) {
			cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
		} else {
			cli_credentials_set_password_callback(creds, get_password);
			creds->priv_data = (void*)(uintptr_t)mux_id;
		}
		if (opt_workstation) {
			cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
		}
		
		switch (stdio_helper_mode) {
		case GSS_SPNEGO_SERVER:
		case SQUID_2_5_NTLMSSP:
			cli_credentials_set_machine_account(creds, lp_ctx);
			break;
		default:
			break;
		}

		gensec_set_credentials(state->gensec_state, creds);
		gensec_want_feature_list(state->gensec_state, want_feature_list);

		switch (stdio_helper_mode) {
		case GSS_SPNEGO_CLIENT:
		case GSS_SPNEGO_SERVER:
			nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
			if (!in.length) {
				first = true;
			}
			break;
		case NTLMSSP_CLIENT_1:
			if (!in.length) {
				first = true;
			}
			/* fall through */
		case SQUID_2_5_NTLMSSP:
			nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
			break;
		default:
			talloc_free(mem_ctx);
			abort();
		}

		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
			mux_printf(mux_id, "BH GENSEC mech failed to start\n");
			talloc_free(mem_ctx);
			return;
		}

	}

	/* update */

	if (strncmp(buf, "PW ", 3) == 0) {
		state->set_password = talloc_strndup(state,
						     (const char *)in.data, 
						     in.length);
		
		cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
					     state->set_password,
					     CRED_SPECIFIED);
		mux_printf(mux_id, "OK\n");
		data_blob_free(&in);
		talloc_free(mem_ctx);
		return;
	}

	if (strncmp(buf, "UG", 2) == 0) {
		int i;
		char *grouplist = NULL;
		struct auth_session_info *session_info;

		nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("gensec_session_info failed: %s\n", nt_errstr(nt_status)));
			mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status));
			data_blob_free(&in);
			talloc_free(mem_ctx);
			return;
		}
		
		/* get the string onto the context */
		grouplist = talloc_strdup(mem_ctx, "");
		
		for (i=0; i<session_info->security_token->num_sids; i++) {
			struct security_token *token = session_info->security_token; 
			const char *sidstr = dom_sid_string(session_info, 
							    &token->sids[i]);
			grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr);
		}

		mux_printf(mux_id, "GL %s\n", grouplist);
		talloc_free(session_info);
		data_blob_free(&in);
		talloc_free(mem_ctx);
		return;
	}

	if (strncmp(buf, "GK", 2) == 0) {
		char *base64_key;
		DEBUG(10, ("Requested session key\n"));
		nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
		if(!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
			mux_printf(mux_id, "BH No session key\n");
			talloc_free(mem_ctx);
			return;
		} else {
			base64_key = base64_encode_data_blob(state, session_key);
			mux_printf(mux_id, "GK %s\n", base64_key);
			talloc_free(base64_key);
		}
		talloc_free(mem_ctx);
		return;
	}

	if (strncmp(buf, "GF", 2) == 0) {
		struct ntlmssp_state *ntlmssp_state;
		uint32_t neg_flags;

		ntlmssp_state = talloc_get_type(state->gensec_state->private_data,
				struct ntlmssp_state);
		neg_flags = ntlmssp_state->neg_flags;

		DEBUG(10, ("Requested negotiated feature flags\n"));
		mux_printf(mux_id, "GF 0x%08x\n", neg_flags);
		return;
	}

	nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
	
	/* don't leak 'bad password'/'no such user' info to the network client */
	nt_status = nt_status_squash(nt_status);

	if (out.length) {
		out_base64 = base64_encode_data_blob(mem_ctx, out);
	} else {
		out_base64 = NULL;
	}

	if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		reply_arg = "*";
		if (first) {
			reply_code = "YR";
		} else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { 
			reply_code = "KK";
		} else if (state->gensec_state->gensec_role == GENSEC_SERVER) { 
			reply_code = "TT";
		} else {
			abort();
		}


	} else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
		reply_code = "BH NT_STATUS_ACCESS_DENIED";
		reply_arg = nt_errstr(nt_status);
		DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
	} else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
		reply_code = "BH NT_STATUS_UNSUCCESSFUL";
		reply_arg = nt_errstr(nt_status);
		DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
	} else if (!NT_STATUS_IS_OK(nt_status)) {
		reply_code = "NA";
		reply_arg = nt_errstr(nt_status);
		DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
	} else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
		struct auth_session_info *session_info;

		nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
		if (!NT_STATUS_IS_OK(nt_status)) {
			reply_code = "BH Failed to retrive session info";
			reply_arg = nt_errstr(nt_status);
			DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
		} else {

			reply_code = "AF";
			reply_arg = talloc_asprintf(state->gensec_state, 
						    "%s%s%s", session_info->info->domain_name,
						    lpcfg_winbind_separator(lp_ctx), session_info->info->account_name);
			talloc_free(session_info);
		}
	} else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
		reply_code = "AF";
		reply_arg = out_base64;
	} else {
		abort();
	}

	switch (stdio_helper_mode) {
	case GSS_SPNEGO_SERVER:
		mux_printf(mux_id, "%s %s %s\n", reply_code, 
			  out_base64 ? out_base64 : "*", 
			  reply_arg ? reply_arg : "*");
		break;
	default:
		if (out_base64) {
			mux_printf(mux_id, "%s %s\n", reply_code, out_base64);
		} else if (reply_arg) {
			mux_printf(mux_id, "%s %s\n", reply_code, reply_arg);
		} else {
			mux_printf(mux_id, "%s\n", reply_code);
		}
	}

	talloc_free(mem_ctx);
	return;
}
예제 #4
0
static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
{
	struct gensec_gssapi_state *gensec_gssapi_state;
	struct cli_credentials *creds = gensec_get_credentials(gensec_security);
	NTSTATUS nt_status;
	gss_buffer_desc name_token;
	gss_OID name_type;
	OM_uint32 maj_stat, min_stat;
	const char *hostname = gensec_get_target_hostname(gensec_security);

	if (!hostname) {
		DEBUG(3, ("No hostname for target computer passed in, cannot use kerberos for this connection\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (is_ipaddress(hostname)) {
		DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (strcmp(hostname, "localhost") == 0) {
		DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	nt_status = gensec_gssapi_start(gensec_security);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);

	if (cli_credentials_get_impersonate_principal(creds)) {
		gensec_gssapi_state->gss_want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
	}

	gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
	if (gensec_gssapi_state->target_principal) {
		name_type = GSS_C_NULL_OID;
	} else {
		gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
					    gensec_get_target_service(gensec_security), 
					    hostname, cli_credentials_get_realm(creds));

		name_type = GSS_C_NT_USER_NAME;
	}
	name_token.value  = discard_const_p(uint8_t, gensec_gssapi_state->target_principal);
	name_token.length = strlen(gensec_gssapi_state->target_principal);


	maj_stat = gss_import_name (&min_stat,
				    &name_token,
				    name_type,
				    &gensec_gssapi_state->server_name);
	if (maj_stat) {
		DEBUG(2, ("GSS Import name of %s failed: %s\n",
			  (char *)name_token.value,
			  gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	return NT_STATUS_OK;
}
예제 #5
0
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi)
{
	krb5_error_code ret;
	struct gensec_krb5_state *gensec_krb5_state;
	struct cli_credentials *creds;
	const struct tsocket_address *tlocal_addr, *tremote_addr;
	krb5_address my_krb5_addr, peer_krb5_addr;
	
	creds = gensec_get_credentials(gensec_security);
	if (!creds) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
	if (!gensec_krb5_state) {
		return NT_STATUS_NO_MEMORY;
	}

	gensec_security->private_data = gensec_krb5_state;
	gensec_krb5_state->smb_krb5_context = NULL;
	gensec_krb5_state->auth_context = NULL;
	gensec_krb5_state->ticket = NULL;
	ZERO_STRUCT(gensec_krb5_state->enc_ticket);
	gensec_krb5_state->keyblock = NULL;
	gensec_krb5_state->gssapi = gssapi;

	talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); 

	if (cli_credentials_get_krb5_context(creds, 
					     gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	tlocal_addr = gensec_get_local_address(gensec_security);
	if (tlocal_addr) {
		ssize_t socklen;
		struct sockaddr_storage ss;

		socklen = tsocket_address_bsd_sockaddr(tlocal_addr,
				(struct sockaddr *) &ss,
				sizeof(struct sockaddr_storage));
		if (socklen < 0) {
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
				(const struct sockaddr *) &ss, &my_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	tremote_addr = gensec_get_remote_address(gensec_security);
	if (tremote_addr) {
		ssize_t socklen;
		struct sockaddr_storage ss;

		socklen = tsocket_address_bsd_sockaddr(tremote_addr,
				(struct sockaddr *) &ss,
				sizeof(struct sockaddr_storage));
		if (socklen < 0) {
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
				(const struct sockaddr *) &ss, &peer_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     tlocal_addr ? &my_krb5_addr : NULL,
				     tremote_addr ? &peer_krb5_addr : NULL);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	return NT_STATUS_OK;
}
예제 #6
0
static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, 
				   TALLOC_CTX *out_mem_ctx, 
				   struct tevent_context *ev,
				   const DATA_BLOB in, DATA_BLOB *out) 
{
	struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
	krb5_error_code ret = 0;
	NTSTATUS nt_status;

	switch (gensec_krb5_state->state_position) {
	case GENSEC_KRB5_CLIENT_START:
	{
		DATA_BLOB unwrapped_out;
		
		nt_status = gensec_krb5_common_client_creds(gensec_security, ev, gensec_krb5_state->gssapi);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return nt_status;
		}

		if (gensec_krb5_state->gssapi) {
			unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
			
			/* wrap that up in a nice GSS-API wrapping */
			*out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
		} else {
			*out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
		}
		if (gensec_krb5_state->ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
			gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
			nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
		} else {
			gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
			nt_status = NT_STATUS_OK;
		}
		return nt_status;
	}
		
	case GENSEC_KRB5_CLIENT_MUTUAL_AUTH:
	{
		DATA_BLOB unwrapped_in;
		krb5_data inbuf;
		krb5_ap_rep_enc_part *repl = NULL;
		uint8_t tok_id[2];

		if (gensec_krb5_state->gssapi) {
			if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
				DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n"));
				dump_data_pw("Mutual authentication message:\n", in.data, in.length);
				return NT_STATUS_INVALID_PARAMETER;
			}
		} else {
			unwrapped_in = in;
		}
		/* TODO: check the tok_id */

		inbuf.data = unwrapped_in.data;
		inbuf.length = unwrapped_in.length;
		ret = krb5_rd_rep(gensec_krb5_state->smb_krb5_context->krb5_context, 
				  gensec_krb5_state->auth_context,
				  &inbuf, &repl);
		if (ret) {
			DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n",
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, out_mem_ctx)));
			dump_data_pw("Mutual authentication message:\n", (uint8_t *)inbuf.data, inbuf.length);
			nt_status = NT_STATUS_ACCESS_DENIED;
		} else {
			*out = data_blob(NULL, 0);
			nt_status = NT_STATUS_OK;
			gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
		}
		if (repl) {
			krb5_free_ap_rep_enc_part(gensec_krb5_state->smb_krb5_context->krb5_context, repl);
		}
		return nt_status;
	}

	case GENSEC_KRB5_SERVER_START:
	{
		DATA_BLOB unwrapped_in;
		DATA_BLOB unwrapped_out = data_blob(NULL, 0);
		krb5_data inbuf, outbuf;
		uint8_t tok_id[2];
		struct keytab_container *keytab;
		krb5_principal server_in_keytab;
		const char *error_string;
		enum credentials_obtained obtained;

		if (!in.data) {
			return NT_STATUS_INVALID_PARAMETER;
		}	

		/* Grab the keytab, however generated */
		ret = cli_credentials_get_keytab(gensec_get_credentials(gensec_security), 
						 gensec_security->settings->lp_ctx, &keytab);
		if (ret) {
			return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		}
		
		/* This ensures we lookup the correct entry in that keytab */
		ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), 
						 gensec_krb5_state->smb_krb5_context, 
						 &server_in_keytab, &obtained, &error_string);

		if (ret) {
			DEBUG(2,("Failed to make credentials from principal: %s\n", error_string));
			return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		}

		/* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */
		if (gensec_krb5_state->gssapi
		    && gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
			inbuf.data = unwrapped_in.data;
			inbuf.length = unwrapped_in.length;
		} else {
			inbuf.data = in.data;
			inbuf.length = in.length;
		}

		ret = smb_rd_req_return_stuff(gensec_krb5_state->smb_krb5_context->krb5_context,
					      &gensec_krb5_state->auth_context, 
					      &inbuf, keytab->keytab, server_in_keytab,  
					      &outbuf, 
					      &gensec_krb5_state->ticket, 
					      &gensec_krb5_state->keyblock);

		if (ret) {
			return NT_STATUS_LOGON_FAILURE;
		}
		unwrapped_out.data = (uint8_t *)outbuf.data;
		unwrapped_out.length = outbuf.length;
		gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
		/* wrap that up in a nice GSS-API wrapping */
		if (gensec_krb5_state->gssapi) {
			*out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP);
		} else {
			*out = data_blob_talloc(out_mem_ctx, outbuf.data, outbuf.length);
		}
		krb5_data_free(&outbuf);
		return NT_STATUS_OK;
	}

	case GENSEC_KRB5_DONE:
	default:
		/* Asking too many times... */
		return NT_STATUS_INVALID_PARAMETER;
	}
}
예제 #7
0
static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_security,
						struct tevent_context *ev,
						bool gssapi)
{
	struct gensec_krb5_state *gensec_krb5_state;
	krb5_error_code ret;
	struct ccache_container *ccache_container;
	const char *error_string;
	const char *principal;
	const char *hostname;
	krb5_data in_data;
	struct tevent_context *previous_ev;

	gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;

	principal = gensec_get_target_principal(gensec_security);
	hostname = gensec_get_target_hostname(gensec_security);

	ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), 
				         ev,
					 gensec_security->settings->lp_ctx, &ccache_container, &error_string);
	switch (ret) {
	case 0:
		break;
	case KRB5KDC_ERR_PREAUTH_FAILED:
	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
		return NT_STATUS_LOGON_FAILURE;
	case KRB5_KDC_UNREACH:
		DEBUG(3, ("Cannot reach a KDC we require to contact %s: %s\n", principal, error_string));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	case KRB5_CC_NOTFOUND:
	case KRB5_CC_END:
		DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	default:
		DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_string));
		return NT_STATUS_UNSUCCESSFUL;
	}
	in_data.length = 0;
	
	/* Do this every time, in case we have weird recursive issues here */
	ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, ev, &previous_ev);
	if (ret != 0) {
		DEBUG(1, ("gensec_krb5_start: Setting event context failed\n"));
		return NT_STATUS_NO_MEMORY;
	}
	if (principal) {
		krb5_principal target_principal;
		ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal,
				      &target_principal);
		if (ret == 0) {
			ret = krb5_mk_req_exact(gensec_krb5_state->smb_krb5_context->krb5_context, 
						&gensec_krb5_state->auth_context,
						gensec_krb5_state->ap_req_options, 
						target_principal,
						&in_data, ccache_container->ccache, 
						&gensec_krb5_state->enc_ticket);
			krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    target_principal);
		}
	} else {
		ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, 
				  &gensec_krb5_state->auth_context,
				  gensec_krb5_state->ap_req_options,
				  gensec_get_target_service(gensec_security),
				  hostname,
				  &in_data, ccache_container->ccache, 
				  &gensec_krb5_state->enc_ticket);
	}

	smb_krb5_context_remove_event_ctx(gensec_krb5_state->smb_krb5_context, previous_ev, ev);

	switch (ret) {
	case 0:
		return NT_STATUS_OK;
	case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
		DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", 
			  hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	case KRB5_KDC_UNREACH:
		DEBUG(3, ("Cannot reach a KDC we require to contact host [%s]: %s\n",
			  hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	case KRB5KDC_ERR_PREAUTH_FAILED:
	case KRB5KRB_AP_ERR_TKT_EXPIRED:
	case KRB5_CC_END:
		/* Too much clock skew - we will need to kinit to re-skew the clock */
	case KRB5KRB_AP_ERR_SKEW:
	case KRB5_KDCREP_SKEW:
	{
		DEBUG(3, ("kerberos (mk_req) failed: %s\n", 
			  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		/*fall through*/
	}
	
	/* just don't print a message for these really ordinary messages */
	case KRB5_FCC_NOFILE:
	case KRB5_CC_NOTFOUND:
	case ENOENT:
		
		return NT_STATUS_UNSUCCESSFUL;
		break;
		
	default:
		DEBUG(0, ("kerberos: %s\n", 
			  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_UNSUCCESSFUL;
	}
}
예제 #8
0
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi)
{
	krb5_error_code ret;
	struct gensec_krb5_state *gensec_krb5_state;
	struct cli_credentials *creds;
	const struct socket_address *my_addr, *peer_addr;
	krb5_address my_krb5_addr, peer_krb5_addr;
	
	creds = gensec_get_credentials(gensec_security);
	if (!creds) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
	if (!gensec_krb5_state) {
		return NT_STATUS_NO_MEMORY;
	}

	gensec_security->private_data = gensec_krb5_state;
	gensec_krb5_state->smb_krb5_context = NULL;
	gensec_krb5_state->auth_context = NULL;
	gensec_krb5_state->ticket = NULL;
	ZERO_STRUCT(gensec_krb5_state->enc_ticket);
	gensec_krb5_state->keyblock = NULL;
	gensec_krb5_state->session_key = data_blob(NULL, 0);
	gensec_krb5_state->pac = data_blob(NULL, 0);
	gensec_krb5_state->gssapi = gssapi;

	talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); 

	if (cli_credentials_get_krb5_context(creds, 
					     gensec_security->event_ctx, 
					     gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	my_addr = gensec_get_my_addr(gensec_security);
	if (my_addr && my_addr->sockaddr) {
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    my_addr->sockaddr, &my_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	peer_addr = gensec_get_peer_addr(gensec_security);
	if (peer_addr && peer_addr->sockaddr) {
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    peer_addr->sockaddr, &peer_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     my_addr ? &my_krb5_addr : NULL, 
				     peer_addr ? &peer_krb5_addr : NULL);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	return NT_STATUS_OK;
}
예제 #9
0
static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi)
{
	struct gensec_krb5_state *gensec_krb5_state;
	krb5_error_code ret;
	NTSTATUS nt_status;
	struct ccache_container *ccache_container;
	const char *hostname;

	const char *principal;
	krb5_data in_data;

	hostname = gensec_get_target_hostname(gensec_security);
	if (!hostname) {
		DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (is_ipaddress(hostname)) {
		DEBUG(2, ("Cannot do krb5 to an IP address"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (strcmp(hostname, "localhost") == 0) {
		DEBUG(2, ("krb5 to 'localhost' does not make sense"));
		return NT_STATUS_INVALID_PARAMETER;
	}
			
	nt_status = gensec_krb5_start(gensec_security, gssapi);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
	gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START;
	gensec_krb5_state->ap_req_options = AP_OPTS_USE_SUBKEY;

	if (gensec_krb5_state->gssapi) {
		/* The Fake GSSAPI modal emulates Samba3, which does not do mutual authentication */
		if (gensec_setting_bool(gensec_security->settings, "gensec_fake_gssapi_krb5", "mutual", false)) {
			gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
		}
	} else {
		/* The wrapping for KPASSWD (a user of the raw KRB5 API) should be mutually authenticated */
		if (gensec_setting_bool(gensec_security->settings, "gensec_krb5", "mutual", true)) {
			gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
		}
	}

	principal = gensec_get_target_principal(gensec_security);

	ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), 
				         gensec_security->event_ctx, 
					 gensec_security->settings->lp_ctx, &ccache_container);
	switch (ret) {
	case 0:
		break;
	case KRB5KDC_ERR_PREAUTH_FAILED:
		return NT_STATUS_LOGON_FAILURE;
	case KRB5_KDC_UNREACH:
		DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	default:
		DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_message(ret)));
		return NT_STATUS_UNSUCCESSFUL;
	}
	in_data.length = 0;
	
	if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
		krb5_principal target_principal;
		ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal,
				      &target_principal);
		if (ret == 0) {
			ret = krb5_mk_req_exact(gensec_krb5_state->smb_krb5_context->krb5_context, 
						&gensec_krb5_state->auth_context,
						gensec_krb5_state->ap_req_options, 
						target_principal,
						&in_data, ccache_container->ccache, 
						&gensec_krb5_state->enc_ticket);
			krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    target_principal);
		}
	} else {
		ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, 
				  &gensec_krb5_state->auth_context,
				  gensec_krb5_state->ap_req_options,
				  gensec_get_target_service(gensec_security),
				  hostname,
				  &in_data, ccache_container->ccache, 
				  &gensec_krb5_state->enc_ticket);
	}
	switch (ret) {
	case 0:
		return NT_STATUS_OK;
	case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
		DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", 
			  hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	case KRB5_KDC_UNREACH:
		DEBUG(3, ("Cannot reach a KDC we require to contact host [%s]: %s\n",
			  hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
	case KRB5KDC_ERR_PREAUTH_FAILED:
	case KRB5KRB_AP_ERR_TKT_EXPIRED:
	case KRB5_CC_END:
		/* Too much clock skew - we will need to kinit to re-skew the clock */
	case KRB5KRB_AP_ERR_SKEW:
	case KRB5_KDCREP_SKEW:
	{
		DEBUG(3, ("kerberos (mk_req) failed: %s\n", 
			  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		/*fall through*/
	}
	
	/* just don't print a message for these really ordinary messages */
	case KRB5_FCC_NOFILE:
	case KRB5_CC_NOTFOUND:
	case ENOENT:
		
		return NT_STATUS_UNSUCCESSFUL;
		break;
		
	default:
		DEBUG(0, ("kerberos: %s\n", 
			  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
		return NT_STATUS_UNSUCCESSFUL;
	}
}