From a129e271b5385853fb39a8e54b56b508b00a3e41 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 1 Apr 2012 21:19:53 +0200 Subject: [PATCH] s3:smbd: make use of smbXsrv_session for smb1 Pair-Programmed-With: Michael Adam metze --- source3/smbd/globals.h | 8 -- source3/smbd/password.c | 194 +--------------------------------------- source3/smbd/process.c | 7 +- source3/smbd/proto.h | 8 -- source3/smbd/reply.c | 26 ++++-- source3/smbd/sesssetup.c | 225 +++++++++++++++++++++++++++++++++++------------ 6 files changed, 194 insertions(+), 274 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index feda48b2e76..dd05d1a9644 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -498,8 +498,6 @@ struct user_struct { struct auth_session_info *session_info; - struct gensec_security *gensec_security; - struct smbXsrv_session0 *session; }; @@ -607,12 +605,6 @@ struct smbd_server_connection { */ int max_send; uint64_t last_session_tag; - - /* - * this holds info on user ids that are already - * validated for this VC - */ - uint16_t next_vuid; } sessions; struct smb_signing_state *signing_state; diff --git a/source3/smbd/password.c b/source3/smbd/password.c index b1ba66ac3fc..103403aaa9a 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -91,22 +91,6 @@ struct user_struct *get_valid_user_struct(struct smbd_server_connection *sconn, SERVER_ALLOCATED_REQUIRED_YES); } -bool is_partial_auth_vuid(struct smbd_server_connection *sconn, uint64_t vuid) -{ - return (get_partial_auth_user_struct(sconn, vuid) != NULL); -} - -/**************************************************************************** - Get the user struct of a partial NTLMSSP login -****************************************************************************/ - -struct user_struct *get_partial_auth_user_struct(struct smbd_server_connection *sconn, - uint64_t vuid) -{ - return get_valid_user_struct_internal(sconn, vuid, - SERVER_ALLOCATED_REQUIRED_NO); -} - /**************************************************************************** Invalidate a uid. ****************************************************************************/ @@ -123,10 +107,6 @@ void invalidate_vuid(struct smbd_server_connection *sconn, uint64_t vuid) session_yield(vuser); - if (vuser->gensec_security) { - TALLOC_FREE(vuser->gensec_security); - } - DLIST_REMOVE(sconn->users, vuser); SMB_ASSERT(sconn->num_users > 0); sconn->num_users--; @@ -144,68 +124,7 @@ void invalidate_vuid(struct smbd_server_connection *sconn, uint64_t vuid) void invalidate_all_vuids(struct smbd_server_connection *sconn) { - if (sconn->using_smb2) { - smbXsrv_session_logoff_all(sconn->conn); - return; - } - - while (sconn->users != NULL) { - invalidate_vuid(sconn, sconn->users->vuid); - } -} - -static void increment_next_vuid(uint16_t *vuid) -{ - *vuid += 1; - - /* Check for vuid wrap. */ - if (*vuid == UID_FIELD_INVALID) { - *vuid = VUID_OFFSET; - } -} - -/**************************************************** - Create a new partial auth user struct. -*****************************************************/ - -uint64_t register_initial_vuid(struct smbd_server_connection *sconn) -{ - struct user_struct *vuser; - - /* Limit allowed vuids to 16bits - VUID_OFFSET. */ - if (sconn->num_users >= 0xFFFF-VUID_OFFSET) { - return UID_FIELD_INVALID; - } - - if((vuser = talloc_zero(NULL, struct user_struct)) == NULL) { - DEBUG(0,("register_initial_vuid: " - "Failed to talloc users struct!\n")); - return UID_FIELD_INVALID; - } - - /* Allocate a free vuid. Yes this is a linear search... */ - while( get_valid_user_struct_internal(sconn, - sconn->smb1.sessions.next_vuid, - SERVER_ALLOCATED_REQUIRED_ANY) != NULL ) { - increment_next_vuid(&sconn->smb1.sessions.next_vuid); - } - - DEBUG(10,("register_initial_vuid: allocated vuid = %u\n", - (unsigned int)sconn->smb1.sessions.next_vuid )); - - vuser->vuid = sconn->smb1.sessions.next_vuid; - - /* - * This happens in an unfinished NTLMSSP session setup. We - * need to allocate a vuid between the first and second calls - * to NTLMSSP. - */ - increment_next_vuid(&sconn->smb1.sessions.next_vuid); - - sconn->num_users++; - DLIST_ADD(sconn->users, vuser); - - return vuser->vuid; + smbXsrv_session_logoff_all(sconn->conn); } int register_homes_share(const char *username) @@ -238,114 +157,3 @@ int register_homes_share(const char *username) TALLOC_FREE(pwd); return result; } - -/** - * register that a valid login has been performed, establish 'session'. - * @param session_info The token returned from the authentication process. - * (now 'owned' by register_existing_vuid) - * - * @param session_key The User session key for the login session (now also - * 'owned' by register_existing_vuid) - * - * @param respose_blob The NT challenge-response, if available. (May be - * freed after this call) - * - * @param smb_name The untranslated name of the user - * - * @return Newly allocated vuid, biased by an offset. (This allows us to - * tell random client vuid's (normally zero) from valid vuids.) - * - */ - -uint64_t register_existing_vuid(struct smbd_server_connection *sconn, - uint64_t vuid, - struct auth_session_info *session_info, - DATA_BLOB response_blob) -{ - struct user_struct *vuser; - bool guest = security_session_user_level(session_info, NULL) < SECURITY_USER; - - vuser = get_partial_auth_user_struct(sconn, vuid); - if (!vuser) { - goto fail; - } - - /* Use this to keep tabs on all our info from the authentication */ - vuser->session_info = talloc_move(vuser, &session_info); - - /* Make clear that we require the optional unix_token and unix_info in the source3 code */ - SMB_ASSERT(vuser->session_info->unix_token); - SMB_ASSERT(vuser->session_info->unix_info); - - DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n", - (unsigned int)vuser->session_info->unix_token->uid, - (unsigned int)vuser->session_info->unix_token->gid, - vuser->session_info->unix_info->unix_name, - vuser->session_info->unix_info->sanitized_username, - vuser->session_info->info->domain_name, - guest)); - - DEBUG(3, ("register_existing_vuid: User name: %s\t" - "Real name: %s\n", vuser->session_info->unix_info->unix_name, - vuser->session_info->info->full_name ? - vuser->session_info->info->full_name : "")); - - if (!vuser->session_info->security_token) { - DEBUG(1, ("register_existing_vuid: session_info does not " - "contain a user_token - cannot continue\n")); - goto fail; - } - - /* Make clear that we require the optional unix_token in the source3 code */ - SMB_ASSERT(vuser->session_info->unix_token); - - DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, " - "and will be vuid %llu\n", (int)vuser->session_info->unix_token->uid, - vuser->session_info->unix_info->unix_name, - (unsigned long long)vuser->vuid)); - - if (!session_claim(sconn, vuser)) { - DEBUG(1, ("register_existing_vuid: Failed to claim session " - "for vuid=%llu\n", - (unsigned long long)vuser->vuid)); - goto fail; - } - - /* Register a home dir service for this user if - (a) This is not a guest connection, - (b) we have a home directory defined - (c) there s not an existing static share by that name - If a share exists by this name (autoloaded or not) reuse it . */ - - vuser->homes_snum = -1; - - - if (!guest) { - vuser->homes_snum = register_homes_share( - vuser->session_info->unix_info->unix_name); - } - - if (srv_is_signing_negotiated(sconn) && - !guest) { - /* Try and turn on server signing on the first non-guest - * sessionsetup. */ - srv_set_signing(sconn, - vuser->session_info->session_key, - response_blob); - } - - /* fill in the current_user_info struct */ - set_current_user_info( - vuser->session_info->unix_info->sanitized_username, - vuser->session_info->unix_info->unix_name, - vuser->session_info->info->domain_name); - - return vuser->vuid; - - fail: - - if (vuser) { - invalidate_vuid(sconn, vuid); - } - return UID_FIELD_INVALID; -} diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 311ef9dd2d0..1cff64a3001 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -3185,6 +3185,11 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn, return status; } } else { + status = smb1srv_session_table_init(conn); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = smb1srv_tcon_table_init(conn); if (!NT_STATUS_IS_OK(status)) { return status; @@ -3528,8 +3533,6 @@ void smbd_process(struct tevent_context *ev_ctx, sconn->smb1.sessions.done_sesssetup = false; sconn->smb1.sessions.max_send = BUFFER_SIZE; sconn->smb1.sessions.last_session_tag = UID_FIELD_INVALID; - /* this holds info on user ids that are already validated for this VC */ - sconn->smb1.sessions.next_vuid = VUID_OFFSET; if (!init_dptrs(sconn)) { exit_server("init_dptrs() failed"); diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index e8dbdfb928d..fc670aba8e8 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -693,17 +693,9 @@ struct kernel_oplocks *linux_init_kernel_oplocks(struct smbd_server_connection * struct user_struct *get_valid_user_struct(struct smbd_server_connection *sconn, uint64_t vuid); -bool is_partial_auth_vuid(struct smbd_server_connection *sconn, uint64_t vuid); -struct user_struct *get_partial_auth_user_struct(struct smbd_server_connection *sconn, - uint64_t vuid); void invalidate_vuid(struct smbd_server_connection *sconn, uint64_t vuid); void invalidate_all_vuids(struct smbd_server_connection *sconn); -uint64_t register_initial_vuid(struct smbd_server_connection *sconn); int register_homes_share(const char *username); -uint64_t register_existing_vuid(struct smbd_server_connection *sconn, - uint64_t vuid, - struct auth_session_info *session_info, - DATA_BLOB response_blob); /* The following definitions come from smbd/pipes.c */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 50c974f22b8..080be5cc941 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -2096,6 +2096,8 @@ void reply_ulogoffX(struct smb_request *req) { struct smbd_server_connection *sconn = req->sconn; struct user_struct *vuser; + struct smbXsrv_session *session = NULL; + NTSTATUS status; START_PROFILE(SMBulogoffX); @@ -2111,13 +2113,27 @@ void reply_ulogoffX(struct smb_request *req) return; } - /* in user level security we are supposed to close any files - open by this user */ - if (vuser != NULL) { - file_close_user(sconn, req->vuid); + session = vuser->session; + vuser = NULL; + + /* + * TODO: cancel all outstanding requests on the session + */ + status = smbXsrv_session_logoff(session); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("reply_ulogoff: " + "smbXsrv_session_logoff() failed: %s\n", + nt_errstr(status))); + /* + * If we hit this case, there is something completely + * wrong, so we better disconnect the transport connection. + */ + END_PROFILE(SMBulogoffX); + exit_server(__location__ ": smbXsrv_session_logoff failed"); + return; } - invalidate_vuid(sconn, req->vuid); + TALLOC_FREE(session); reply_outbuf(req, 2, 0); SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 81e56eb2084..be838a8656f 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -127,10 +127,11 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) uint16 data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); uint64_t vuid = req->vuid; - struct user_struct *vuser = NULL; NTSTATUS status = NT_STATUS_OK; struct smbd_server_connection *sconn = req->sconn; uint16_t action = 0; + NTTIME now = timeval_to_nttime(&req->request_time); + struct smbXsrv_session *session = NULL; DEBUG(3,("Doing spnego session setup\n")); @@ -195,82 +196,80 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) } } - vuser = get_valid_user_struct(sconn, vuid); - if (vuser != NULL) { - reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); - return; - } - - /* Do we have a valid vuid now ? */ - if (!is_partial_auth_vuid(sconn, vuid)) { - if (vuid != 0) { + if (vuid != 0) { + status = smb1srv_session_lookup(sconn->conn, + vuid, now, + &session); + if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { reply_force_doserror(req, ERRSRV, ERRbaduid); return; } - - /* No, start a new authentication setup. */ - vuid = register_initial_vuid(sconn); - if (vuid == UID_FIELD_INVALID) { - reply_nterror(req, nt_status_squash( - NT_STATUS_INVALID_PARAMETER)); + if (NT_STATUS_IS_OK(status)) { + reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + return; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + reply_nterror(req, nt_status_squash(status)); return; } } - vuser = get_partial_auth_user_struct(sconn, vuid); - /* This MUST be valid. */ - if (!vuser) { - smb_panic("reply_sesssetup_and_X_spnego: invalid vuid."); + if (session == NULL) { + /* create a new session */ + status = smbXsrv_session_create(sconn->conn, + now, &session); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, nt_status_squash(status)); + return; + } } - if (!vuser->gensec_security) { - status = auth_generic_prepare(vuser, sconn->remote_address, - &vuser->gensec_security); + if (!session->gensec) { + status = auth_generic_prepare(session, sconn->remote_address, + &session->gensec); if (!NT_STATUS_IS_OK(status)) { - /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } - gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_SESSION_KEY); - gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_UNIX_TOKEN); + gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); + gensec_want_feature(session->gensec, GENSEC_FEATURE_UNIX_TOKEN); - status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_SPNEGO); + status = gensec_start_mech_by_oid(session->gensec, + GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start SPNEGO handler!\n")); - /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session);; reply_nterror(req, nt_status_squash(status)); return; } } - status = gensec_update(vuser->gensec_security, + become_root(); + status = gensec_update(session->gensec, talloc_tos(), NULL, in_blob, &out_blob); + unbecome_root(); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (NT_STATUS_IS_OK(status)) { struct auth_session_info *session_info = NULL; - uint64_t tmp_vuid; - status = gensec_session_info(vuser->gensec_security, - talloc_tos(), + status = gensec_session_info(session->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))); - /* Kill the intermediate vuid */ data_blob_free(&out_blob); - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } @@ -279,13 +278,63 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) action = 1; } - /* register_existing_vuid keeps the server info */ - tmp_vuid = register_existing_vuid(sconn, vuid, - session_info, - data_blob_null); - if (tmp_vuid != vuid) { + 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) { + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); + } + + if (!session_claim(sconn, session->compat)) { + 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; + } + + if (srv_is_signing_negotiated(sconn) && action == 0) { + /* + * Try and turn on server signing on the first non-guest + * sessionsetup. + */ + srv_set_signing(sconn, + session_info->session_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; + + 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); - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } @@ -294,6 +343,8 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) reload_services(sconn, conn_snum_used, true); } + vuid = session->global->session_wire_id; + reply_outbuf(req, 4, 0); SSVAL(req->outbuf, smb_uid, vuid); @@ -304,14 +355,14 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) if (message_push_blob(&req->outbuf, out_blob) == -1) { data_blob_free(&out_blob); - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } data_blob_free(&out_blob); if (push_signature(&req->outbuf) == -1) { - invalidate_vuid(sconn, vuid); + TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -408,6 +459,8 @@ void reply_sesssetup_and_X(struct smb_request *req) struct auth_session_info *session_info = NULL; uint16 smb_flag2 = req->flags2; uint16_t action = 0; + NTTIME now = timeval_to_nttime(&req->request_time); + struct smbXsrv_session *session = NULL; NTSTATUS nt_status; struct smbd_server_connection *sconn = req->sconn; @@ -759,25 +812,79 @@ void reply_sesssetup_and_X(struct smb_request *req) /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ - /* Ignore the initial vuid. */ - sess_vuid = register_initial_vuid(sconn); - if (sess_vuid == UID_FIELD_INVALID) { + nt_status = smbXsrv_session_create(sconn->conn, + now, &session); + if (!NT_STATUS_IS_OK(nt_status)) { + data_blob_free(&nt_resp); + data_blob_free(&lm_resp); + reply_nterror(req, nt_status_squash(nt_status)); + END_PROFILE(SMBsesssetupX); + return; + } + + session->compat = talloc_zero(session, struct user_struct); + if (session->compat == NULL) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); - reply_nterror(req, nt_status_squash( - NT_STATUS_LOGON_FAILURE)); + TALLOC_FREE(session); + reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBsesssetupX); return; } - /* register_existing_vuid keeps the session_info */ - sess_vuid = register_existing_vuid(sconn, sess_vuid, - session_info, - nt_resp.data ? nt_resp : lm_resp); - if (sess_vuid == UID_FIELD_INVALID) { + 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) { + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); + } + + if (!session_claim(sconn, session->compat)) { + DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", + (unsigned long long)session->compat->vuid)); data_blob_free(&nt_resp); data_blob_free(&lm_resp); - reply_nterror(req, nt_status_squash( - NT_STATUS_LOGON_FAILURE)); + TALLOC_FREE(session); + reply_nterror(req, NT_STATUS_LOGON_FAILURE); + END_PROFILE(SMBsesssetupX); + return; + } + + if (srv_is_signing_negotiated(sconn) && action == 0) { + /* + * Try and turn on server signing on the first non-guest + * sessionsetup. + */ + srv_set_signing(sconn, + session_info->session_key, + nt_resp.data ? nt_resp : lm_resp); + } + + 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; + + nt_status = smbXsrv_session_update(session); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", + (unsigned long long)session->compat->vuid, + nt_errstr(nt_status))); + data_blob_free(&nt_resp); + data_blob_free(&lm_resp); + TALLOC_FREE(session); + reply_nterror(req, nt_status_squash(nt_status)); END_PROFILE(SMBsesssetupX); return; } @@ -785,6 +892,8 @@ void reply_sesssetup_and_X(struct smb_request *req) /* current_user_info is changed on new vuid */ reload_services(sconn, conn_snum_used, true); + sess_vuid = session->global->session_wire_id; + data_blob_free(&nt_resp); data_blob_free(&lm_resp); -- 2.11.4.GIT