예제 #1
0
NTSTATUS auth_generic_server_get_user_info(struct gensec_security *gensec_security,
				      TALLOC_CTX *mem_ctx,
				      struct auth_session_info **session_info)
{
	NTSTATUS status;

	status = gensec_session_info(gensec_security, mem_ctx, session_info);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, (__location__ ": Failed to get authenticated user "
			  "info: %s\n", nt_errstr(status)));
		return status;
	}

	DEBUG(5, (__location__ "OK: user: %s domain: %s\n",
		  (*session_info)->info->account_name,
		  (*session_info)->info->domain_name));

	return NT_STATUS_OK;
}
예제 #2
0
/*
  add any auth information needed in a alter ack, and process the authentication
  information found in the alter.
*/
NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
{
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;

	/* on a pure interface change there is no auth_info structure
	   setup */
	if (!call->conn->auth_state.auth_info ||
	    dce_conn->auth_state.auth_info->credentials.length == 0) {
		return NT_STATUS_OK;
	}

	if (!call->conn->auth_state.gensec_security) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	status = gensec_update(dce_conn->auth_state.gensec_security,
			       call, call->event_ctx,
			       dce_conn->auth_state.auth_info->credentials, 
			       &dce_conn->auth_state.auth_info->credentials);

	if (NT_STATUS_IS_OK(status)) {
		status = gensec_session_info(dce_conn->auth_state.gensec_security,
					     dce_conn,
					     &dce_conn->auth_state.session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
			return status;
		}

		/* Now that we are authenticated, got back to the generic session key... */
		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
		return NT_STATUS_OK;
	} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		dce_conn->auth_state.auth_info->auth_pad_length = 0;
		dce_conn->auth_state.auth_info->auth_reserved = 0;
		return NT_STATUS_OK;
	}

	DEBUG(4, ("GENSEC mech rejected the incoming authentication at auth alter_ack: %s\n",
		  nt_errstr(status)));
	return status;
}
예제 #3
0
/*
  process the final stage of a auth request
*/
bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
{
	struct ncacn_packet *pkt = &call->pkt;
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;
	uint32_t auth_length;

	/* We can't work without an existing gensec state, and an new blob to feed it */
	if (!dce_conn->auth_state.auth_info ||
	    !dce_conn->auth_state.gensec_security ||
	    pkt->u.auth3.auth_info.length == 0) {
		return false;
	}

	status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
					  dce_conn->auth_state.auth_info, &auth_length, true);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	/* Pass the extra data we got from the client down to gensec for processing */
	status = gensec_update(dce_conn->auth_state.gensec_security,
			       call, call->event_ctx,
			       dce_conn->auth_state.auth_info->credentials, 
			       &dce_conn->auth_state.auth_info->credentials);
	if (NT_STATUS_IS_OK(status)) {
		status = gensec_session_info(dce_conn->auth_state.gensec_security,
					     dce_conn,
					     &dce_conn->auth_state.session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
			return false;
		}
		/* Now that we are authenticated, go back to the generic session key... */
		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
		return true;
	} else {
		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
			  nt_errstr(status)));
		return false;
	}
}
예제 #4
0
/*
  add any auth information needed in a bind ack, and process the authentication
  information found in the bind.
*/
NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
{
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;

	if (!call->conn->auth_state.gensec_security) {
		return NT_STATUS_OK;
	}

	status = gensec_update(dce_conn->auth_state.gensec_security,
			       call,
			       dce_conn->auth_state.auth_info->credentials, 
			       &dce_conn->auth_state.auth_info->credentials);
	
	if (NT_STATUS_IS_OK(status)) {
		status = gensec_session_info(dce_conn->auth_state.gensec_security,
					     &dce_conn->auth_state.session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
			return status;
		}

		if (dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) {
			gensec_want_feature(dce_conn->auth_state.gensec_security,
					    GENSEC_FEATURE_SIGN_PKT_HEADER);
		}

		/* Now that we are authenticated, go back to the generic session key... */
		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
		return NT_STATUS_OK;
	} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		dce_conn->auth_state.auth_info->auth_pad_length = 0;
		dce_conn->auth_state.auth_info->auth_reserved = 0;
		return NT_STATUS_OK;
	} else {
		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n",
			  nt_errstr(status)));
		return status;
	}
}
예제 #5
0
NTSTATUS auth_generic_server_get_user_info(struct gensec_security *gensec_security,
				      TALLOC_CTX *mem_ctx,
				      struct auth_session_info **session_info)
{
	NTSTATUS status;

	/* this has to be done as root in order to get to the
	 * messaging sockets for IDMAP and privilege.ldb in the AD
	 * DC */
	become_root();
	status = gensec_session_info(gensec_security, mem_ctx, session_info);
	unbecome_root();
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, (__location__ ": Failed to get authenticated user "
			  "info: %s\n", nt_errstr(status)));
		return status;
	}

	DEBUG(5, (__location__ "OK: user: %s domain: %s\n",
		  (*session_info)->info->account_name,
		  (*session_info)->info->domain_name));

	return NT_STATUS_OK;
}
예제 #6
0
static void reply_sesssetup_and_X_spnego(struct smb_request *req)
{
	const uint8_t *p;
	DATA_BLOB in_blob;
	DATA_BLOB out_blob = data_blob_null;
	size_t bufrem;
	char *tmp;
	const char *native_os;
	const char *native_lanman;
	const char *primary_domain;
	uint16_t data_blob_len = SVAL(req->vwv+7, 0);
	enum remote_arch_types ra_type = get_remote_arch();
	uint64_t vuid = req->vuid;
	NTSTATUS status = NT_STATUS_OK;
	struct smbXsrv_connection *xconn = req->xconn;
	struct smbd_server_connection *sconn = req->sconn;
	uint16_t action = 0;
	bool is_authenticated = false;
	NTTIME now = timeval_to_nttime(&req->request_time);
	struct smbXsrv_session *session = NULL;
	uint16_t smb_bufsize = SVAL(req->vwv+2, 0);
	uint32_t client_caps = IVAL(req->vwv+10, 0);
	struct smbXsrv_session_auth0 *auth;

	DEBUG(3,("Doing spnego session setup\n"));

	if (!xconn->smb1.sessions.done_sesssetup) {
		global_client_caps = client_caps;

		if (!(global_client_caps & CAP_STATUS32)) {
			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
		}
	}

	p = req->buf;

	if (data_blob_len == 0) {
		/* an invalid request */
		reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
		return;
	}

	bufrem = smbreq_bufrem(req, p);
	/* pull the spnego blob */
	in_blob = data_blob_const(p, MIN(bufrem, data_blob_len));

#if 0
	file_save("negotiate.dat", in_blob.data, in_blob.length);
#endif

	p = req->buf + in_blob.length;

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	native_os = tmp ? tmp : "";

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	native_lanman = tmp ? tmp : "";

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	primary_domain = tmp ? tmp : "";

	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
		native_os, native_lanman, primary_domain));

	if ( ra_type == RA_WIN2K ) {
		/* Vista sets neither the OS or lanman strings */

		if ( !strlen(native_os) && !strlen(native_lanman) )
			set_remote_arch(RA_VISTA);

		/* Windows 2003 doesn't set the native lanman string,
		   but does set primary domain which is a bug I think */

		if ( !strlen(native_lanman) ) {
			ra_lanman_string( primary_domain );
		} else {
			ra_lanman_string( native_lanman );
		}
	} else if ( ra_type == RA_VISTA ) {
		if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
			set_remote_arch(RA_OSX);
		}
	}

	if (vuid != 0) {
		status = smb1srv_session_lookup(xconn,
						vuid, now,
						&session);
		if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
			reply_force_doserror(req, ERRSRV, ERRbaduid);
			return;
		}
		if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
			status = NT_STATUS_OK;
		}
		if (NT_STATUS_IS_OK(status)) {
			session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
			status = NT_STATUS_MORE_PROCESSING_REQUIRED;
			TALLOC_FREE(session->pending_auth);
		}
		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	if (session == NULL) {
		/* create a new session */
		status = smbXsrv_session_create(xconn,
					        now, &session);
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	status = smbXsrv_session_find_auth(session, xconn, now, &auth);
	if (!NT_STATUS_IS_OK(status)) {
		status = smbXsrv_session_create_auth(session, xconn, now,
						     0, /* flags */
						     0, /* security */
						     &auth);
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	if (auth->gensec == NULL) {
		status = auth_generic_prepare(session,
					      xconn->remote_address,
					      xconn->local_address,
					      "SMB",
					      &auth->gensec);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			reply_nterror(req, nt_status_squash(status));
			return;
		}

		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY);
		gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);

		status = gensec_start_mech_by_oid(auth->gensec,
						  GENSEC_OID_SPNEGO);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Failed to start SPNEGO handler!\n"));
			TALLOC_FREE(session);;
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	become_root();
	status = gensec_update(auth->gensec,
			       talloc_tos(),
			       in_blob, &out_blob);
	unbecome_root();
	if (!NT_STATUS_IS_OK(status) &&
	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		TALLOC_FREE(session);
		reply_nterror(req, nt_status_squash(status));
		return;
	}

	if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) {
		struct auth_session_info *session_info = NULL;

		status = gensec_session_info(auth->gensec,
					     session,
					     &session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1,("Failed to generate session_info "
				 "(user and group token) for session setup: %s\n",
				 nt_errstr(status)));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, nt_status_squash(status));
			return;
		}

		if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) {
			action |= SMB_SETUP_GUEST;
		}

		if (session_info->session_key.length > 0) {
			struct smbXsrv_session *x = session;

			/*
			 * Note: the SMB1 signing key is not truncated to 16 byte!
			 */
			x->global->signing_key =
				data_blob_dup_talloc(x->global,
						     session_info->session_key);
			if (x->global->signing_key.data == NULL) {
				data_blob_free(&out_blob);
				TALLOC_FREE(session);
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				return;
			}

			/*
			 * clear the session key
			 * the first tcon will add setup the application key
			 */
			data_blob_clear_free(&session_info->session_key);
		}

		session->compat = talloc_zero(session, struct user_struct);
		if (session->compat == NULL) {
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		session->compat->session = session;
		session->compat->homes_snum = -1;
		session->compat->session_info = session_info;
		session->compat->session_keystr = NULL;
		session->compat->vuid = session->global->session_wire_id;
		DLIST_ADD(sconn->users, session->compat);
		sconn->num_users++;

		if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
			is_authenticated = true;
			session->compat->homes_snum =
				register_homes_share(session_info->unix_info->unix_name);
		}

		if (srv_is_signing_negotiated(xconn) &&
		    is_authenticated &&
		    session->global->signing_key.length > 0)
		{
			/*
			 * Try and turn on server signing on the first non-guest
			 * sessionsetup.
			 */
			srv_set_signing(xconn,
				session->global->signing_key,
				data_blob_null);
		}

		set_current_user_info(session_info->unix_info->sanitized_username,
				      session_info->unix_info->unix_name,
				      session_info->info->domain_name);

		session->status = NT_STATUS_OK;
		session->global->auth_session_info = talloc_move(session->global,
								 &session_info);
		session->global->auth_session_info_seqnum += 1;
		session->global->channels[0].auth_session_info_seqnum =
			session->global->auth_session_info_seqnum;
		session->global->auth_time = now;
		if (client_caps & CAP_DYNAMIC_REAUTH) {
			session->global->expiration_time =
				gensec_expire_time(auth->gensec);
		} else {
			session->global->expiration_time =
				GENSEC_EXPIRE_TIME_INFINITY;
		}

		if (!session_claim(session)) {
			DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n",
				  (unsigned long long)session->compat->vuid));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_LOGON_FAILURE);
			return;
		}

		status = smbXsrv_session_update(session);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n",
				  (unsigned long long)session->compat->vuid,
				  nt_errstr(status)));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_LOGON_FAILURE);
			return;
		}

		if (!xconn->smb1.sessions.done_sesssetup) {
			if (smb_bufsize < SMB_BUFFER_SIZE_MIN) {
				reply_force_doserror(req, ERRSRV, ERRerror);
				return;
			}
			xconn->smb1.sessions.max_send = smb_bufsize;
			xconn->smb1.sessions.done_sesssetup = true;
		}

		/* current_user_info is changed on new vuid */
		reload_services(sconn, conn_snum_used, true);
	} else if (NT_STATUS_IS_OK(status)) {
예제 #7
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;
}
예제 #8
0
/*
  add any auth information needed in a bind ack, and process the authentication
  information found in the bind.
*/
NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
{
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;
	bool want_header_signing = false;

	if (!call->conn->auth_state.gensec_security) {
		return NT_STATUS_OK;
	}

	if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
		dce_conn->auth_state.client_hdr_signing = true;
		want_header_signing = true;
	}

	if (!lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", true)) {
		want_header_signing = false;
	}

	status = gensec_update(dce_conn->auth_state.gensec_security,
			       call, call->event_ctx,
			       dce_conn->auth_state.auth_info->credentials, 
			       &dce_conn->auth_state.auth_info->credentials);
	
	if (NT_STATUS_IS_OK(status)) {
		status = gensec_session_info(dce_conn->auth_state.gensec_security,
					     dce_conn,
					     &dce_conn->auth_state.session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
			return status;
		}

		if (!gensec_have_feature(dce_conn->auth_state.gensec_security,
					 GENSEC_FEATURE_SIGN_PKT_HEADER))
		{
			want_header_signing = false;
		}

		if (want_header_signing) {
			gensec_want_feature(dce_conn->auth_state.gensec_security,
					    GENSEC_FEATURE_SIGN_PKT_HEADER);
			dce_conn->auth_state.hdr_signing = true;
			pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
		}

		/* Now that we are authenticated, go back to the generic session key... */
		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
		return NT_STATUS_OK;
	} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		dce_conn->auth_state.auth_info->auth_pad_length = 0;
		dce_conn->auth_state.auth_info->auth_reserved = 0;

		if (!gensec_have_feature(dce_conn->auth_state.gensec_security,
					 GENSEC_FEATURE_SIGN_PKT_HEADER))
		{
			want_header_signing = false;
		}

		if (want_header_signing) {
			gensec_want_feature(dce_conn->auth_state.gensec_security,
					    GENSEC_FEATURE_SIGN_PKT_HEADER);
			dce_conn->auth_state.hdr_signing = true;
			pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
		}

		return NT_STATUS_OK;
	} else {
		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n",
			  nt_errstr(status)));
		return status;
	}
}
예제 #9
0
static bool kpasswd_process_request(struct kdc_server *kdc,
				    TALLOC_CTX *mem_ctx,
				    struct gensec_security *gensec_security,
				    uint16_t version,
				    DATA_BLOB *input,
				    DATA_BLOB *reply)
{
	struct auth_session_info *session_info;
	size_t pw_len;

	if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
						 &session_info))) {
		return kpasswdd_make_error_reply(kdc, mem_ctx,
						KRB5_KPASSWD_HARDERROR,
						"gensec_session_info failed!",
						reply);
	}

	switch (version) {
	case KRB5_KPASSWD_VERS_CHANGEPW:
	{
		DATA_BLOB password;
		if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
					       CH_UTF8, CH_UTF16,
					       (const char *)input->data,
					       input->length,
					       (void **)&password.data, &pw_len, false)) {
			return false;
		}
		password.length = pw_len;

		return kpasswdd_change_password(kdc, mem_ctx, session_info,
						&password, reply);
		break;
	}
	case KRB5_KPASSWD_VERS_SETPW:
	{
		NTSTATUS status;
		enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
		struct samr_DomInfo1 *dominfo = NULL;
		struct ldb_context *samdb;
		struct ldb_message *msg;
		krb5_context context = kdc->smb_krb5_context->krb5_context;

		ChangePasswdDataMS chpw;
		DATA_BLOB password;

		krb5_principal principal;
		char *set_password_on_princ;
		struct ldb_dn *set_password_on_dn;

		size_t len;
		int ret;

		msg = ldb_msg_new(mem_ctx);
		if (!msg) {
			return false;
		}

		ret = decode_ChangePasswdDataMS(input->data, input->length,
						&chpw, &len);
		if (ret) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"failed to decode password change structure",
							reply);
		}

		if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
					       CH_UTF8, CH_UTF16,
					       (const char *)chpw.newpasswd.data,
					       chpw.newpasswd.length,
					       (void **)&password.data, &pw_len, false)) {
			free_ChangePasswdDataMS(&chpw);
			return false;
		}

		password.length = pw_len;

		if ((chpw.targname && !chpw.targrealm)
		    || (!chpw.targname && chpw.targrealm)) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"Realm and principal must be both present, or neither present",
							reply);
		}
		if (chpw.targname && chpw.targrealm) {
#ifdef SAMBA4_INTERNAL_HEIMDAL
			if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context,
							       &principal, *chpw.targname,
							       *chpw.targrealm) != 0) {
				free_ChangePasswdDataMS(&chpw);
				return kpasswdd_make_error_reply(kdc, mem_ctx,
								KRB5_KPASSWD_MALFORMED,
								"failed to extract principal to set",
								reply);

			}
#else /* SAMBA4_INTERNAL_HEIMDAL */
				return kpasswdd_make_error_reply(kdc, mem_ctx,
								KRB5_KPASSWD_BAD_VERSION,
								"Operation Not Implemented",
								reply);
#endif /* SAMBA4_INTERNAL_HEIMDAL */
		} else {
			free_ChangePasswdDataMS(&chpw);
			return kpasswdd_change_password(kdc, mem_ctx, session_info,
							&password, reply);
		}
		free_ChangePasswdDataMS(&chpw);

		if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) {
			krb5_free_principal(context, principal);
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"krb5_unparse_name failed!",
							reply);
		}

		krb5_free_principal(context, principal);

		samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info);
		if (!samdb) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							 KRB5_KPASSWD_HARDERROR,
							 "Unable to open database!",
							 reply);
		}

		DEBUG(3, ("%s\\%s (%s) is changing password of %s\n",
			  session_info->server_info->domain_name,
			  session_info->server_info->account_name,
			  dom_sid_string(mem_ctx, session_info->security_token->user_sid),
			  set_password_on_princ));
		ret = ldb_transaction_start(samdb);
		if (ret) {
			status = NT_STATUS_TRANSACTION_ABORTED;
			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
							   status,
							   SAM_PWD_CHANGE_NO_ERROR,
							   NULL,
							   reply);
		}

		status = crack_user_principal_name(samdb, mem_ctx,
						   set_password_on_princ,
						   &set_password_on_dn, NULL);
		free(set_password_on_princ);
		if (!NT_STATUS_IS_OK(status)) {
			ldb_transaction_cancel(samdb);
			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
							   status,
							   SAM_PWD_CHANGE_NO_ERROR,
							   NULL,
							   reply);
		}

		msg = ldb_msg_new(mem_ctx);
		if (msg == NULL) {
			ldb_transaction_cancel(samdb);
			status = NT_STATUS_NO_MEMORY;
		} else {
			msg->dn = ldb_dn_copy(msg, set_password_on_dn);
			if (!msg->dn) {
				status = NT_STATUS_NO_MEMORY;
			}
		}

		if (NT_STATUS_IS_OK(status)) {
			/* Admin password set */
			status = samdb_set_password(samdb, mem_ctx,
						    set_password_on_dn, NULL,
						    msg, &password, NULL, NULL,
						    false, /* this is not a user password change */
						    &reject_reason, &dominfo);
		}

		if (NT_STATUS_IS_OK(status)) {
			/* modify the samdb record */
			ret = samdb_replace(samdb, mem_ctx, msg);
			if (ret != 0) {
				DEBUG(2,("Failed to modify record to set password on %s: %s\n",
					 ldb_dn_get_linearized(msg->dn),
					 ldb_errstring(samdb)));
				status = NT_STATUS_ACCESS_DENIED;
			}
		}
		if (NT_STATUS_IS_OK(status)) {
			ret = ldb_transaction_commit(samdb);
			if (ret != 0) {
				DEBUG(1,("Failed to commit transaction to set password on %s: %s\n",
					 ldb_dn_get_linearized(msg->dn),
					 ldb_errstring(samdb)));
				status = NT_STATUS_TRANSACTION_ABORTED;
			}
		} else {
			ldb_transaction_cancel(samdb);
		}
		return kpasswd_make_pwchange_reply(kdc, mem_ctx,
						   status,
						   reject_reason,
						   dominfo,
						   reply);
	}
	default:
		return kpasswdd_make_error_reply(kdc, mem_ctx,
						 KRB5_KPASSWD_BAD_VERSION,
						 talloc_asprintf(mem_ctx,
								 "Protocol version %u not supported",
								 version),
						 reply);
	}
	return true;
}
예제 #10
0
static NTSTATUS smbd_smb2_auth_generic(struct smbd_smb2_session *session,
				       struct smbd_smb2_request *smb2req,
				       uint8_t in_security_mode,
				       DATA_BLOB in_security_buffer,
				       uint16_t *out_session_flags,
				       DATA_BLOB *out_security_buffer,
				       uint64_t *out_session_id)
{
	NTSTATUS status;

	*out_security_buffer = data_blob_null;

	if (session->gensec_security == NULL) {
		status = auth_generic_prepare(session, session->sconn->remote_address,
					    &session->gensec_security);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}

		gensec_want_feature(session->gensec_security, GENSEC_FEATURE_SESSION_KEY);
		gensec_want_feature(session->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);

		status = gensec_start_mech_by_oid(session->gensec_security, GENSEC_OID_SPNEGO);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}
	}

	become_root();
	status = gensec_update(session->gensec_security,
			       smb2req, NULL,
			       in_security_buffer,
			       out_security_buffer);
	unbecome_root();
	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
	    !NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(session);
		return nt_status_squash(status);
	}

	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		*out_session_id = session->vuid;
		return status;
	}

	status = gensec_session_info(session->gensec_security,
				     session,
				     &session->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(session);
		return status;
	}
	*out_session_id = session->vuid;

	return smbd_smb2_auth_generic_return(session,
					     smb2req,
					     in_security_mode,
					     in_security_buffer,
					     out_session_flags,
					     out_session_id);
}
예제 #11
0
파일: authdata.c 프로젝트: sprymak/samba
/*
 * Given the username/password, do a kinit, store the ticket in
 * cache_name if specified, and return the PAC_LOGON_INFO (the
 * structure containing the important user information such as
 * groups).
 */
NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
			     const char *name,
			     const char *pass,
			     time_t time_offset,
			     time_t *expire_time,
			     time_t *renew_till_time,
			     const char *cache_name,
			     bool request_pac,
			     bool add_netbios_addr,
			     time_t renewable_time,
			     const char *impersonate_princ_s,
			     struct PAC_LOGON_INFO **_logon_info)
{
	krb5_error_code ret;
	NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
	DATA_BLOB tkt, tkt_wrapped, ap_rep, sesskey1;
	const char *auth_princ = NULL;
	const char *local_service = NULL;
	const char *cc = "MEMORY:kerberos_return_pac";
	struct auth_session_info *session_info;
	struct gensec_security *gensec_server_context;

	struct gensec_settings *gensec_settings;
	size_t idx = 0;
	struct auth4_context *auth_context;
	struct loadparm_context *lp_ctx;
	struct PAC_LOGON_INFO *logon_info = NULL;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	ZERO_STRUCT(tkt);
	ZERO_STRUCT(ap_rep);
	ZERO_STRUCT(sesskey1);

	if (!name || !pass) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (cache_name) {
		cc = cache_name;
	}

	if (!strchr_m(name, '@')) {
		auth_princ = talloc_asprintf(mem_ctx, "%s@%s", name,
			lp_realm());
	} else {
		auth_princ = name;
	}
	NT_STATUS_HAVE_NO_MEMORY(auth_princ);

	local_service = talloc_asprintf(mem_ctx, "%s$@%s",
					lp_netbios_name(), lp_realm());
	NT_STATUS_HAVE_NO_MEMORY(local_service);

	ret = kerberos_kinit_password_ext(auth_princ,
					  pass,
					  time_offset,
					  expire_time,
					  renew_till_time,
					  cc,
					  request_pac,
					  add_netbios_addr,
					  renewable_time,
					  &status);
	if (ret) {
		DEBUG(1,("kinit failed for '%s' with: %s (%d)\n",
			auth_princ, error_message(ret), ret));
		/* status already set */
		goto out;
	}

	DEBUG(10,("got TGT for %s in %s\n", auth_princ, cc));
	if (expire_time) {
		DEBUGADD(10,("\tvalid until: %s (%d)\n",
			http_timestring(talloc_tos(), *expire_time),
			(int)*expire_time));
	}
	if (renew_till_time) {
		DEBUGADD(10,("\trenewable till: %s (%d)\n",
			http_timestring(talloc_tos(), *renew_till_time),
			(int)*renew_till_time));
	}

	/* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set,
	 * in that case fallback to NTLM - gd */

	if (expire_time && renew_till_time &&
	    (*expire_time == 0) && (*renew_till_time == 0)) {
		return NT_STATUS_INVALID_LOGON_TYPE;
	}

	ret = cli_krb5_get_ticket(mem_ctx,
				  local_service,
				  time_offset,
				  &tkt,
				  &sesskey1,
				  0,
				  cc,
				  NULL,
				  impersonate_princ_s);
	if (ret) {
		DEBUG(1,("failed to get ticket for %s: %s\n",
			local_service, error_message(ret)));
		if (impersonate_princ_s) {
			DEBUGADD(1,("tried S4U2SELF impersonation as: %s\n",
				impersonate_princ_s));
		}
		status = krb5_to_nt_status(ret);
		goto out;
	}

	/* wrap that up in a nice GSS-API wrapping */
	tkt_wrapped = spnego_gen_krb5_wrap(tmp_ctx, tkt, TOK_ID_KRB_AP_REQ);
	if (tkt_wrapped.data == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}

	auth_context = talloc_zero(tmp_ctx, struct auth4_context);
	if (auth_context == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}
	auth_context->generate_session_info_pac = kerberos_fetch_pac;

	lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context());
	if (lp_ctx == NULL) {
		status = NT_STATUS_INVALID_SERVER_STATE;
		DEBUG(10, ("loadparm_init_s3 failed\n"));
		goto out;
	}

	gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
	if (lp_ctx == NULL) {
		status = NT_STATUS_NO_MEMORY;
		DEBUG(10, ("lpcfg_gensec_settings failed\n"));
		goto out;
	}

	gensec_settings->backends = talloc_zero_array(gensec_settings,
						      struct gensec_security_ops *, 2);
	if (gensec_settings->backends == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}

	gensec_init();

	gensec_settings->backends[idx++] = &gensec_gse_krb5_security_ops;

	status = gensec_server_start(tmp_ctx, gensec_settings,
					auth_context, &gensec_server_context);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, (__location__ "Failed to start server-side GENSEC to validate a Kerberos ticket: %s\n", nt_errstr(status)));
		goto out;
	}

	talloc_unlink(tmp_ctx, lp_ctx);
	talloc_unlink(tmp_ctx, gensec_settings);
	talloc_unlink(tmp_ctx, auth_context);

	status = gensec_start_mech_by_oid(gensec_server_context, GENSEC_OID_KERBEROS5);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, (__location__ "Failed to start server-side GENSEC krb5 to validate a Kerberos ticket: %s\n", nt_errstr(status)));
		goto out;
	}

	/* Do a client-server update dance */
	status = gensec_update(gensec_server_context, tmp_ctx, NULL, tkt_wrapped, &ap_rep);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("gensec_update() failed: %s\n", nt_errstr(status)));
		goto out;
	}

	/* Now return the PAC information to the callers.  We ingore
	 * the session_info and instead pick out the PAC via the
	 * private_data on the auth_context */
	status = gensec_session_info(gensec_server_context, tmp_ctx, &session_info);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Unable to obtain PAC via gensec_session_info\n"));
		goto out;
	}

	logon_info = talloc_get_type_abort(gensec_server_context->auth_context->private_data,
					   struct PAC_LOGON_INFO);
	if (logon_info == NULL) {
		DEBUG(1,("no PAC\n"));
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	*_logon_info = talloc_move(mem_ctx, &logon_info);

out:
	talloc_free(tmp_ctx);
	if (cc != cache_name) {
		ads_kdestroy(cc);
	}

	data_blob_free(&tkt);
	data_blob_free(&ap_rep);
	data_blob_free(&sesskey1);

	return status;
}
예제 #12
0
파일: dlz_bind9.c 프로젝트: sprymak/samba
/*
  authorize a zone update
 */
_PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
				    const char *type, const char *key, uint32_t keydatalen, uint8_t *keydata,
				    void *dbdata)
{
	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
	TALLOC_CTX *tmp_ctx;
	DATA_BLOB ap_req;
	struct cli_credentials *server_credentials;
	char *keytab_name;
	int ret;
	int ldb_ret;
	NTSTATUS nt_status;
	struct gensec_security *gensec_ctx;
	struct auth_session_info *session_info;
	struct ldb_dn *dn;
	isc_result_t result;
	struct ldb_result *res;
	const char * attrs[] = { NULL };
	uint32_t access_mask;

	/* Remove cached credentials, if any */
	if (state->session_info) {
		talloc_free(state->session_info);
		state->session_info = NULL;
	}
	if (state->update_name) {
		talloc_free(state->update_name);
		state->update_name = NULL;
	}

	tmp_ctx = talloc_new(NULL);
	if (tmp_ctx == NULL) {
		state->log(ISC_LOG_ERROR, "samba_dlz: no memory");
		return ISC_FALSE;
	}

	ap_req = data_blob_const(keydata, keydatalen);
	server_credentials = cli_credentials_init(tmp_ctx);
	if (!server_credentials) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to init server credentials");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	cli_credentials_set_krb5_context(server_credentials, state->smb_krb5_ctx);
	cli_credentials_set_conf(server_credentials, state->lp);

	keytab_name = talloc_asprintf(tmp_ctx, "file:%s/dns.keytab",
					lpcfg_private_dir(state->lp));
	ret = cli_credentials_set_keytab_name(server_credentials, state->lp, keytab_name,
						CRED_SPECIFIED);
	if (ret != 0) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to obtain server credentials from %s",
			   keytab_name);
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}
	talloc_free(keytab_name);

	nt_status = gensec_server_start(tmp_ctx,
					lpcfg_gensec_settings(tmp_ctx, state->lp),
					state->auth_context, &gensec_ctx);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to start gensec server");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	gensec_set_credentials(gensec_ctx, server_credentials);

	nt_status = gensec_start_mech_by_name(gensec_ctx, "spnego");
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to start spnego");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	nt_status = gensec_update(gensec_ctx, tmp_ctx, state->ev_ctx, ap_req, &ap_req);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: spnego update failed");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	nt_status = gensec_session_info(gensec_ctx, tmp_ctx, &session_info);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to create session info");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Get the DN from name */
	result = b9_find_name_dn(state, name, tmp_ctx, &dn);
	if (result != ISC_R_SUCCESS) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to find name %s", name);
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* make sure the dn exists, or find parent dn in case new object is being added */
	ldb_ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
				attrs, "objectClass=dnsNode");
	if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT) {
		ldb_dn_remove_child_components(dn, 1);
		access_mask = SEC_ADS_CREATE_CHILD;
		talloc_free(res);
	} else if (ldb_ret == LDB_SUCCESS) {
		access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE;
		talloc_free(res);
	} else {
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Do ACL check */
	ldb_ret = dsdb_check_access_on_dn(state->samdb, tmp_ctx, dn,
						session_info->security_token,
						access_mask, NULL);
	if (ldb_ret != LDB_SUCCESS) {
		state->log(ISC_LOG_INFO,
			"samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s",
			signer, name, type, ldb_strerror(ldb_ret));
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Cache session_info, so it can be used in the actual add/delete operation */
	state->update_name = talloc_strdup(state, name);
	if (state->update_name == NULL) {
		state->log(ISC_LOG_ERROR, "samba_dlz: memory allocation error");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}
	state->session_info = talloc_steal(state, session_info);

	state->log(ISC_LOG_INFO, "samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s",
		   signer, name, tcpaddr, type, key);

	talloc_free(tmp_ctx);
	return ISC_TRUE;
}
예제 #13
0
파일: remote_pac.c 프로젝트: gojdic/samba
static bool test_PACVerify(struct torture_context *tctx,
                           struct dcerpc_pipe *p,
                           struct cli_credentials *credentials)
{
    NTSTATUS status;

    struct netr_LogonSamLogon r;

    union netr_LogonLevel logon;
    union netr_Validation validation;
    uint8_t authoritative;
    struct netr_Authenticator return_authenticator;

    struct netr_GenericInfo generic;
    struct netr_Authenticator auth, auth2;


    struct netlogon_creds_CredentialState *creds;
    struct gensec_security *gensec_client_context;
    struct gensec_security *gensec_server_context;

    DATA_BLOB client_to_server, server_to_client, pac_wrapped, payload;
    struct PAC_Validate pac_wrapped_struct;

    enum ndr_err_code ndr_err;

    struct auth_session_info *session_info;

    char *tmp_dir;

    TALLOC_CTX *tmp_ctx = talloc_new(tctx);

    torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");

    if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
                                credentials, SEC_CHAN_BDC,
                                &creds)) {
        return false;
    }

    status = torture_temp_dir(tctx, "PACVerify", &tmp_dir);
    torture_assert_ntstatus_ok(tctx, status, "torture_temp_dir failed");

    status = gensec_client_start(tctx, &gensec_client_context, tctx->ev,
                                 lp_gensec_settings(tctx, tctx->lp_ctx));
    torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");

    status = gensec_set_target_hostname(gensec_client_context, TEST_MACHINE_NAME);

    status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
    torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");

    status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
    torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");

    status = gensec_server_start(tctx, tctx->ev,
                                 lp_gensec_settings(tctx, tctx->lp_ctx),
                                 NULL, &gensec_server_context);
    torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");

    status = gensec_set_credentials(gensec_server_context, credentials);
    torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");

    status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
    torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");

    server_to_client = data_blob(NULL, 0);

    do {
        /* Do a client-server update dance */
        status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
            ;
            torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
        }

        status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
            ;
            torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
        }

        if (NT_STATUS_IS_OK(status)) {
            break;
        }
    } while (1);

    /* Extract the PAC using Samba's code */

    status = gensec_session_info(gensec_server_context, &session_info);
    torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;
    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;
    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    /* Validate it over the netlogon pipe */

    generic.identity_info.parameter_control = 0;
    generic.identity_info.logon_id_high = 0;
    generic.identity_info.logon_id_low = 0;
    generic.identity_info.domain_name.string = session_info->server_info->domain_name;
    generic.identity_info.account_name.string = session_info->server_info->account_name;
    generic.identity_info.workstation.string = TEST_MACHINE_NAME;

    generic.package_name.string = "Kerberos";

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon = &logon;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;
    r.out.validation = &validation;
    r.out.authoritative = &authoritative;
    r.out.return_authenticator = &return_authenticator;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");

    /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
    generic.data[generic.length-1]++;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
    generic.length--;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds,
                   &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;

    /* Break the SignatureType */
    pac_wrapped_struct.SignatureType++;

    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;
    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;
    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;

    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    /* Break the signature length */
    pac_wrapped_struct.SignatureLength++;

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");
    return true;
}
예제 #14
0
krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
				       TALLOC_CTX *mem_ctx,
				       struct gensec_security *gensec_security,
				       uint16_t verno,
				       DATA_BLOB *decoded_data,
				       DATA_BLOB *kpasswd_reply,
				       const char **error_string)
{
	struct auth_session_info *session_info;
	NTSTATUS status;

	status = gensec_session_info(gensec_security,
				     mem_ctx,
				     &session_info);
	if (!NT_STATUS_IS_OK(status)) {
		*error_string = talloc_asprintf(mem_ctx,
						"gensec_session_info failed - "
						"%s",
						nt_errstr(status));
		return KRB5_KPASSWD_HARDERROR;
	}

	switch(verno) {
	case 1: {
		DATA_BLOB password;
		bool ok;

		ok = convert_string_talloc_handle(mem_ctx,
						  lpcfg_iconv_handle(kdc->task->lp_ctx),
						  CH_UTF8,
						  CH_UTF16,
						  (const char *)decoded_data->data,
						  decoded_data->length,
						  (void **)&password.data,
						  &password.length);
		if (!ok) {
			*error_string = "String conversion failed!";
			DBG_WARNING("%s\n", *error_string);
			return KRB5_KPASSWD_HARDERROR;
		}

		return kpasswd_change_password(kdc,
					       mem_ctx,
					       session_info,
					       &password,
					       kpasswd_reply,
					       error_string);
	}
	case RFC3244_VERSION: {
		return kpasswd_set_password(kdc,
					    mem_ctx,
					    session_info,
					    decoded_data,
					    kpasswd_reply,
					    error_string);
	}
	default:
		return KRB5_KPASSWD_BAD_VERSION;
	}

	return 0;
}