/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
NTSTATUS samba_server_gensec_start(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct messaging_context *msg_ctx, struct loadparm_context *lp_ctx, struct cli_credentials *server_credentials, const char *target_service, struct gensec_security **gensec_context) { NTSTATUS nt_status; struct gensec_security *gensec_ctx; struct auth_context *auth_context; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } nt_status = auth_context_create(tmp_ctx, event_ctx, msg_ctx, lp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(nt_status))); talloc_free(tmp_ctx); return nt_status; } nt_status = gensec_server_start(tmp_ctx, event_ctx, lpcfg_gensec_settings(mem_ctx, lp_ctx), auth_context, &gensec_ctx); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(nt_status))); return nt_status; } gensec_set_credentials(gensec_ctx, server_credentials); if (target_service) { gensec_set_target_service(gensec_ctx, target_service); } *gensec_context = talloc_steal(mem_ctx, gensec_ctx); talloc_free(tmp_ctx); return nt_status; }
/* handler for NT1 style session setup */ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) { NTSTATUS status; struct auth_usersupplied_info *user_info = NULL; struct tsocket_address *remote_address; const char *remote_machine = NULL; struct tevent_req *subreq; struct sesssetup_context *state; sess->nt1.out.vuid = 0; sess->nt1.out.action = 0; sesssetup_common_strings(req, &sess->nt1.out.os, &sess->nt1.out.lanman, &sess->nt1.out.domain); if (!req->smb_conn->negotiate.done_sesssetup) { req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize; req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; } state = talloc(req, struct sesssetup_context); if (!state) goto nomem; state->req = req; if (req->smb_conn->negotiate.oid) { if (sess->nt1.in.user && *sess->nt1.in.user) { /* We can't accept a normal login, because we * don't have a challenge */ status = NT_STATUS_LOGON_FAILURE; goto failed; } /* TODO: should we use just "anonymous" here? */ status = auth_context_create(state, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, &state->auth_context); if (!NT_STATUS_IS_OK(status)) goto failed; } else if (req->smb_conn->negotiate.auth_context) { state->auth_context = req->smb_conn->negotiate.auth_context; } else { /* TODO: should we use just "anonymous" here? */ status = auth_context_create(state, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, &state->auth_context); if (!NT_STATUS_IS_OK(status)) goto failed; } if (req->smb_conn->negotiate.calling_name) { remote_machine = req->smb_conn->negotiate.calling_name->name; } remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req); if (!remote_address) goto nomem; if (!remote_machine) { remote_machine = tsocket_address_inet_addr_string(remote_address, req); if (!remote_machine) goto nomem; } user_info = talloc_zero(req, struct auth_usersupplied_info); if (!user_info) goto nomem; user_info->mapped_state = false; user_info->logon_parameters = 0; user_info->flags = 0; user_info->client.account_name = sess->nt1.in.user; user_info->client.domain_name = sess->nt1.in.domain; user_info->workstation_name = remote_machine; user_info->remote_host = talloc_steal(user_info, remote_address); user_info->password_state = AUTH_PASSWORD_RESPONSE; user_info->password.response.lanman = sess->nt1.in.password1; user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data); user_info->password.response.nt = sess->nt1.in.password2; user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data); subreq = auth_check_password_send(state, req->smb_conn->connection->event.ctx, state->auth_context, user_info); if (!subreq) goto nomem; tevent_req_set_callback(subreq, sesssetup_nt1_send, state); return; nomem: status = NT_STATUS_NO_MEMORY; failed: status = nt_status_squash(status); smbsrv_sesssetup_backend_send(req, sess, status); }
/* handler for old style session setup */ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) { struct auth_usersupplied_info *user_info = NULL; struct tsocket_address *remote_address; const char *remote_machine = NULL; struct tevent_req *subreq; struct sesssetup_context *state; sess->old.out.vuid = 0; sess->old.out.action = 0; sesssetup_common_strings(req, &sess->old.out.os, &sess->old.out.lanman, &sess->old.out.domain); if (!req->smb_conn->negotiate.done_sesssetup) { req->smb_conn->negotiate.max_send = sess->old.in.bufsize; } if (req->smb_conn->negotiate.calling_name) { remote_machine = req->smb_conn->negotiate.calling_name->name; } remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req); if (!remote_address) goto nomem; if (!remote_machine) { remote_machine = tsocket_address_inet_addr_string(remote_address, req); if (!remote_machine) goto nomem; } user_info = talloc_zero(req, struct auth_usersupplied_info); if (!user_info) goto nomem; user_info->mapped_state = false; user_info->logon_parameters = 0; user_info->flags = 0; user_info->client.account_name = sess->old.in.user; user_info->client.domain_name = sess->old.in.domain; user_info->workstation_name = remote_machine; user_info->remote_host = talloc_steal(user_info, remote_address); user_info->password_state = AUTH_PASSWORD_RESPONSE; user_info->password.response.lanman = sess->old.in.password; user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data); user_info->password.response.nt = data_blob(NULL, 0); state = talloc(req, struct sesssetup_context); if (!state) goto nomem; if (req->smb_conn->negotiate.auth_context) { state->auth_context = req->smb_conn->negotiate.auth_context; } else { /* TODO: should we use just "anonymous" here? */ NTSTATUS status = auth_context_create(state, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, &state->auth_context); if (!NT_STATUS_IS_OK(status)) { smbsrv_sesssetup_backend_send(req, sess, status); return; } } state->req = req; subreq = auth_check_password_send(state, req->smb_conn->connection->event.ctx, req->smb_conn->negotiate.auth_context, user_info); if (!subreq) goto nomem; tevent_req_set_callback(subreq, sesssetup_old_send, state); return; nomem: smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY); }
static NTSTATUS check_samba4_security(const struct auth_context *auth_context, void *my_private_data, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { TALLOC_CTX *frame = talloc_stackframe(); struct netr_SamInfo3 *info3 = NULL; NTSTATUS nt_status; struct auth_user_info_dc *user_info_dc; struct auth4_context *auth4_context; struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(frame, loadparm_s3_context()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); talloc_free(frame); return NT_STATUS_INVALID_SERVER_STATE; } /* We create a private tevent context here to avoid nested loops in * the s3 one, as that may not be expected */ nt_status = auth_context_create(mem_ctx, s4_event_context_init(frame), NULL, lp_ctx, &auth4_context); NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = auth_context_set_challenge(auth4_context, auth_context->challenge.data, "auth_samba4"); NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth4_context); nt_status = auth_check_password(auth4_context, auth4_context, user_info, &user_info_dc); NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth4_context); nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, user_info_dc, &info3); if (NT_STATUS_IS_OK(nt_status)) { /* We need the strings from the server_info to be valid as long as the info3 is around */ talloc_steal(info3, user_info_dc); } talloc_free(auth4_context); if (!NT_STATUS_IS_OK(nt_status)) { goto done; } nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, user_info->mapped.domain_name, server_info, info3); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("make_server_info_info3 failed: %s\n", nt_errstr(nt_status))); TALLOC_FREE(frame); return nt_status; } nt_status = NT_STATUS_OK; done: TALLOC_FREE(frame); return nt_status; }
/* It's allowed to pass NULL as session_info, when the caller doesn't need a session_info */ _PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct imessaging_context *msg, struct loadparm_context *lp_ctx, const char *nt4_domain, const char *nt4_username, const char *password, const uint32_t logon_parameters, struct auth_session_info **session_info) { struct auth4_context *auth_context; struct auth_usersupplied_info *user_info; struct auth_user_info_dc *user_info_dc; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } nt_status = auth_context_create(tmp_ctx, ev, msg, lp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } user_info = talloc_zero(tmp_ctx, struct auth_usersupplied_info); if (!user_info) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } user_info->mapped_state = true; user_info->client.account_name = nt4_username; user_info->mapped.account_name = nt4_username; user_info->client.domain_name = nt4_domain; user_info->mapped.domain_name = nt4_domain; user_info->workstation_name = NULL; user_info->remote_host = NULL; user_info->password_state = AUTH_PASSWORD_PLAIN; user_info->password.plaintext = talloc_strdup(user_info, password); user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | USER_INFO_DONT_CHECK_UNIX_ACCOUNT; user_info->logon_parameters = logon_parameters | MSV1_0_CLEARTEXT_PASSWORD_ALLOWED | MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED; nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } if (session_info) { uint32_t flags = AUTH_SESSION_INFO_DEFAULT_GROUPS; if (user_info_dc->info->authenticated) { flags |= AUTH_SESSION_INFO_AUTHENTICATED; } nt_status = auth_context->generate_session_info(auth_context, tmp_ctx, user_info_dc, nt4_username, flags, session_info); if (NT_STATUS_IS_OK(nt_status)) { talloc_steal(mem_ctx, *session_info); } } talloc_free(tmp_ctx); return nt_status; }
/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context, TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); /* Allow forcing a specific auth4 module */ if (!auth_context->forced_samba4_methods) { status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); } else { const char * const *forced_auth_methods = (const char * const *)str_list_make(mem_ctx, auth_context->forced_samba4_methods, NULL); status = auth_context_create_methods(mem_ctx, forced_auth_methods, event_ctx, msg_ctx, lp_ctx, NULL, auth4_context); } if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, struct event_context *ev, struct messaging_context *msg, const char *nt4_domain, const char *nt4_username, const char *password, struct auth_session_info **session_info) { struct auth_context *auth_context; struct auth_usersupplied_info *user_info; struct auth_serversupplied_info *server_info; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } nt_status = auth_context_create(tmp_ctx, lp_auth_methods(), ev, msg, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } user_info = talloc(tmp_ctx, struct auth_usersupplied_info); if (!user_info) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } user_info->mapped_state = True; user_info->client.account_name = nt4_username; user_info->mapped.account_name = nt4_username; user_info->client.domain_name = nt4_domain; user_info->mapped.domain_name = nt4_domain; user_info->workstation_name = NULL; user_info->remote_host = NULL; user_info->password_state = AUTH_PASSWORD_PLAIN; user_info->password.plaintext = talloc_strdup(user_info, password); user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | USER_INFO_DONT_CHECK_UNIX_ACCOUNT; user_info->logon_parameters = 0; nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = auth_generate_session_info(tmp_ctx, server_info, session_info); if (NT_STATUS_IS_OK(nt_status)) { talloc_steal(mem_ctx, *session_info); } return nt_status; }