NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u) { NTSTATUS status = NT_STATUS_OK; NET_USER_INFO_3 *usr_info = NULL; NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr; DOM_CRED srv_cred; UNISTR2 *uni_samlogon_user = NULL; UNISTR2 *uni_samlogon_domain = NULL; UNISTR2 *uni_samlogon_workstation = NULL; fstring nt_username, nt_domain, nt_workstation; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; extern userdom_struct current_user_info; SAM_ACCOUNT *sampw; struct auth_context *auth_context = NULL; usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3)); if (!usr_info) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(usr_info); /* store the user information, if there is any. */ r_u->user = usr_info; r_u->switch_value = 0; /* indicates no info */ r_u->auth_resp = 1; /* authoritative response */ r_u->switch_value = 3; /* indicates type of validation user info */ if (!get_valid_user_struct(p->vuid)) return NT_STATUS_NO_SUCH_USER; if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) { /* 'server schannel = yes' should enforce use of schannel, the client did offer it in auth2, but obviously did not use it. */ return NT_STATUS_ACCESS_DENIED; } /* checks and updates credentials. creates reply credentials */ if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))) return NT_STATUS_INVALID_HANDLE; memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred)); r_u->buffer_creds = 1; /* yes, we have valid server credentials */ memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds)); /* find the username */ switch (q_u->sam_id.logon_level) { case INTERACTIVE_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id1.uni_user_name; uni_samlogon_domain = &ctr->auth.id1.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name; DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); break; case NET_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id2.uni_user_name; uni_samlogon_domain = &ctr->auth.id2.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name; DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); break; default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0); rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0); rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0); DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain)); fstrcpy(current_user_info.smb_name, nt_username); sub_set_smb_name(nt_username); DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username)); status = NT_STATUS_OK; switch (ctr->switch_value) { case NET_LOGON_TYPE: { const char *wksname = nt_workstation; if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) { return status; } /* For a network logon, the workstation name comes in with two * backslashes in the front. Strip them if they are there. */ if (*wksname == '\\') wksname++; if (*wksname == '\\') wksname++; /* Standard challenge/response authenticaion */ if (!make_user_info_netlogon_network(&user_info, nt_username, nt_domain, wksname, ctr->auth.id2.lm_chal_resp.buffer, ctr->auth.id2.lm_chal_resp.str_str_len, ctr->auth.id2.nt_chal_resp.buffer, ctr->auth.id2.nt_chal_resp.str_str_len)) { status = NT_STATUS_NO_MEMORY; } break; } case INTERACTIVE_LOGON_TYPE: /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted with the session key. We will convert this to chellange/responce for the auth subsystem to chew on */ { const uint8 *chal; if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) { return status; } chal = auth_context->get_ntlm_challenge(auth_context); if (!make_user_info_netlogon_interactive(&user_info, nt_username, nt_domain, nt_workstation, chal, ctr->auth.id1.lm_owf.data, ctr->auth.id1.nt_owf.data, p->dc.sess_key)) { status = NT_STATUS_NO_MEMORY; } break; } default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ if ( NT_STATUS_IS_OK(status) ) { status = auth_context->check_ntlm_password(auth_context, user_info, &server_info); } (auth_context->free)(&auth_context); free_user_info(&user_info); DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", nt_errstr(status))); /* Check account and password */ if (!NT_STATUS_IS_OK(status)) { free_server_info(&server_info); return status; } if (server_info->guest) { /* We don't like guest domain logons... */ DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n")); free_server_info(&server_info); return NT_STATUS_LOGON_FAILURE; } /* This is the point at which, if the login was successful, that the SAM Local Security Authority should record that the user is logged in to the domain. */ { DOM_GID *gids = NULL; const DOM_SID *user_sid = NULL; const DOM_SID *group_sid = NULL; DOM_SID domain_sid; uint32 user_rid, group_rid; int num_gids = 0; pstring my_name; fstring user_sid_string; fstring group_sid_string; uchar user_session_key[16]; uchar lm_session_key[16]; uchar netlogon_sess_key[16]; sampw = server_info->sam_account; /* set up pointer indicating user/password failed to be found */ usr_info->ptr_user_info = 0; user_sid = pdb_get_user_sid(sampw); group_sid = pdb_get_group_sid(sampw); sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &user_rid); if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", pdb_get_domain(sampw), pdb_get_username(sampw), sid_to_string(user_sid_string, user_sid), sid_to_string(group_sid_string, group_sid))); return NT_STATUS_UNSUCCESSFUL; } pstrcpy(my_name, global_myname()); if (!NT_STATUS_IS_OK(status = nt_token_to_group_list(p->mem_ctx, &domain_sid, server_info->ptok, &num_gids, &gids))) { return status; } ZERO_STRUCT(netlogon_sess_key); memcpy(netlogon_sess_key, p->dc.sess_key, 8); if (server_info->user_session_key.length) { memcpy(user_session_key, server_info->user_session_key.data, MIN(sizeof(user_session_key), server_info->user_session_key.length)); SamOEMhash(user_session_key, netlogon_sess_key, 16); } if (server_info->lm_session_key.length) { memcpy(lm_session_key, server_info->lm_session_key.data, MIN(sizeof(lm_session_key), server_info->lm_session_key.length)); SamOEMhash(lm_session_key, netlogon_sess_key, 16); } ZERO_STRUCT(netlogon_sess_key); init_net_user_info3(p->mem_ctx, usr_info, user_rid, group_rid, pdb_get_username(sampw), pdb_get_fullname(sampw), pdb_get_homedir(sampw), pdb_get_dir_drive(sampw), pdb_get_logon_script(sampw), pdb_get_profile_path(sampw), pdb_get_logon_time(sampw), get_time_t_max(), get_time_t_max(), pdb_get_pass_last_set_time(sampw), pdb_get_pass_can_change_time(sampw), pdb_get_pass_must_change_time(sampw), 0, /* logon_count */ 0, /* bad_pw_count */ num_gids, /* uint32 num_groups */ gids , /* DOM_GID *gids */ 0x20 , /* uint32 user_flgs (?) */ server_info->user_session_key.length ? user_session_key : NULL, server_info->lm_session_key.length ? lm_session_key : NULL, my_name , /* char *logon_srv */ pdb_get_domain(sampw), &domain_sid, /* DOM_SID *dom_sid */ /* Should be users domain sid, not servers - for trusted domains */ NULL); /* char *other_sids */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); } free_server_info(&server_info); return status; }
NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info, uint8_t pipe_session_key[16], struct netr_SamInfo3 *sam3) { struct samu *sampw; DOM_GID *gids = NULL; const DOM_SID *user_sid = NULL; const DOM_SID *group_sid = NULL; DOM_SID domain_sid; uint32 user_rid, group_rid; NTSTATUS status; int num_gids = 0; const char *my_name; struct netr_UserSessionKey user_session_key; struct netr_LMSessionKey lm_session_key; NTTIME last_logon, last_logoff, acct_expiry, last_password_change; NTTIME allow_password_change, force_password_change; struct samr_RidWithAttributeArray groups; int i; struct dom_sid2 *sid = NULL; ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); sampw = server_info->sam_account; user_sid = pdb_get_user_sid(sampw); group_sid = pdb_get_group_sid(sampw); if ((user_sid == NULL) || (group_sid == NULL)) { DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n")); return NT_STATUS_UNSUCCESSFUL; } sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &user_rid); sid = sid_dup_talloc(sam3, &domain_sid); if (!sid) { return NT_STATUS_NO_MEMORY; } if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid " "%s\n but group sid %s.\n" "The conflicting domain portions are not " "supported for NETLOGON calls\n", pdb_get_domain(sampw), pdb_get_username(sampw), sid_string_dbg(user_sid), sid_string_dbg(group_sid))); return NT_STATUS_UNSUCCESSFUL; } if(server_info->login_server) { my_name = server_info->login_server; } else { my_name = global_myname(); } status = nt_token_to_group_list(sam3, &domain_sid, server_info->num_sids, server_info->sids, &num_gids, &gids); if (!NT_STATUS_IS_OK(status)) { return status; } if (server_info->user_session_key.length) { memcpy(user_session_key.key, server_info->user_session_key.data, MIN(sizeof(user_session_key.key), server_info->user_session_key.length)); SamOEMhash(user_session_key.key, pipe_session_key, 16); } if (server_info->lm_session_key.length) { memcpy(lm_session_key.key, server_info->lm_session_key.data, MIN(sizeof(lm_session_key.key), server_info->lm_session_key.length)); SamOEMhash(lm_session_key.key, pipe_session_key, 8); } groups.count = num_gids; groups.rids = TALLOC_ARRAY(sam3, struct samr_RidWithAttribute, groups.count); if (!groups.rids) { return NT_STATUS_NO_MEMORY; } for (i=0; i < groups.count; i++) { groups.rids[i].rid = gids[i].g_rid; groups.rids[i].attributes = gids[i].attr; } unix_to_nt_time(&last_logon, pdb_get_logon_time(sampw)); unix_to_nt_time(&last_logoff, get_time_t_max()); unix_to_nt_time(&acct_expiry, get_time_t_max()); unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(sampw)); unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(sampw)); unix_to_nt_time(&force_password_change, pdb_get_pass_must_change_time(sampw)); init_netr_SamInfo3(sam3, last_logon, last_logoff, acct_expiry, last_password_change, allow_password_change, force_password_change, talloc_strdup(sam3, pdb_get_username(sampw)), talloc_strdup(sam3, pdb_get_fullname(sampw)), talloc_strdup(sam3, pdb_get_logon_script(sampw)), talloc_strdup(sam3, pdb_get_profile_path(sampw)), talloc_strdup(sam3, pdb_get_homedir(sampw)), talloc_strdup(sam3, pdb_get_dir_drive(sampw)), 0, /* logon_count */ 0, /* bad_password_count */ user_rid, group_rid, groups, NETLOGON_EXTRA_SIDS, user_session_key, my_name, talloc_strdup(sam3, pdb_get_domain(sampw)), sid, lm_session_key, pdb_get_acct_ctrl(sampw), 0, /* sidcount */ NULL); /* struct netr_SidAttr *sids */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); return NT_STATUS_OK; }