static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, size_t num_sids, const DOM_SID *sids, int *numgroups, DOM_GID **pgids) { int i; *numgroups=0; *pgids = NULL; for (i=0; i<num_sids; i++) { DOM_GID gid; if (!sid_peek_check_rid(domain_sid, &sids[i], &gid.g_rid)) { continue; } gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT| SE_GROUP_ENABLED); ADD_TO_ARRAY(mem_ctx, DOM_GID, gid, pgids, numgroups); if (*pgids == NULL) { return NT_STATUS_NO_MEMORY; } } return NT_STATUS_OK; }
static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid) { uint32 rid; if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) return NT_STATUS_UNSUCCESSFUL; return tdbsam_getsampwrid(my_methods, user, rid); }
static NTSTATUS wbcsids_to_samr_RidWithAttributeArray( TALLOC_CTX *mem_ctx, struct samr_RidWithAttributeArray *groups, const struct dom_sid *domain_sid, const struct wbcSidWithAttr *sids, size_t num_sids) { unsigned int i, j = 0; bool ok; groups->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, num_sids); if (!groups->rids) { return NT_STATUS_NO_MEMORY; } /* a wbcDomainSid is the same as a dom_sid */ for (i = 0; i < num_sids; i++) { ok = sid_peek_check_rid(domain_sid, (const struct dom_sid *)&sids[i].sid, &groups->rids[j].rid); if (!ok) continue; groups->rids[j].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; j++; } groups->count = j; return NT_STATUS_OK; }
uint32 pdb_get_group_rid (struct samu *sampass) { uint32 g_rid; if (sampass) if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_group_sid(sampass),&g_rid)) return g_rid; return (0); }
uint32 pdb_get_user_rid (const struct samu *sampass) { uint32 u_rid; if (sampass) if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_user_sid(sampass),&u_rid)) return u_rid; return (0); }
static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const struct dom_sid *sid) { uint32_t rid; if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) ) return NT_STATUS_UNSUCCESSFUL; return tdbsam_getsampwrid(my_methods, user, rid); }
NTSTATUS pdb_default_alias_memberships(struct pdb_methods *methods, TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, const DOM_SID *members, size_t num_members, uint32 **pp_alias_rids, size_t *p_num_alias_rids) { DOM_SID *alias_sids; size_t i, num_alias_sids; NTSTATUS result; if (!init_group_mapping()) { DEBUG(0,("failed to initialize group mapping\n")); return NT_STATUS_UNSUCCESSFUL; } alias_sids = NULL; num_alias_sids = 0; result = alias_memberships(members, num_members, &alias_sids, &num_alias_sids); if (!NT_STATUS_IS_OK(result)) return result; *p_num_alias_rids = 0; if (num_alias_sids == 0) { TALLOC_FREE(alias_sids); return NT_STATUS_OK; } *pp_alias_rids = TALLOC_ARRAY(mem_ctx, uint32, num_alias_sids); if (*pp_alias_rids == NULL) return NT_STATUS_NO_MEMORY; for (i=0; i<num_alias_sids; i++) { if (!sid_peek_check_rid(domain_sid, &alias_sids[i], &(*pp_alias_rids)[*p_num_alias_rids])) continue; *p_num_alias_rids += 1; } TALLOC_FREE(alias_sids); return NT_STATUS_OK; }
/* Fills the samr_RidWithAttributeArray with the provided sids. * If it happens that we have additional groups that do not belong * to the domain, add their sids as extra sids */ static NTSTATUS group_sids_to_info3(struct netr_SamInfo3 *info3, const struct dom_sid *sids, size_t num_sids) { uint32_t attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; struct samr_RidWithAttributeArray *groups; struct dom_sid *domain_sid; unsigned int i; NTSTATUS status; uint32_t rid; bool ok; domain_sid = info3->base.domain_sid; groups = &info3->base.groups; groups->rids = talloc_array(info3, struct samr_RidWithAttribute, num_sids); if (!groups->rids) { return NT_STATUS_NO_MEMORY; } for (i = 0; i < num_sids; i++) { ok = sid_peek_check_rid(domain_sid, &sids[i], &rid); if (ok) { /* store domain group rid */ groups->rids[groups->count].rid = rid; groups->rids[groups->count].attributes = attributes; groups->count++; continue; } /* if this wasn't a domain sid, add it as extra sid */ status = append_netr_SidAttr(info3, &info3->sids, &info3->sidcount, &sids[i], attributes); if (!NT_STATUS_IS_OK(status)) { return status; } } return NT_STATUS_OK; }
enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain, struct winbindd_cli_state *state) { DOM_SID sid; WINBIND_USERINFO user_info; NTSTATUS status; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, state->request.data.sid)); if (!string_to_sid(&sid, state->request.data.sid)) { DEBUG(5, ("%s not a SID\n", state->request.data.sid)); return WINBINDD_ERROR; } status = domain->methods->query_user(domain, state->mem_ctx, &sid, &user_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("error getting user info for sid %s\n", sid_string_dbg(&sid))); return WINBINDD_ERROR; } fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name); fstrcpy(state->response.data.user_info.full_name, user_info.full_name); fstrcpy(state->response.data.user_info.homedir, user_info.homedir); fstrcpy(state->response.data.user_info.shell, user_info.shell); state->response.data.user_info.primary_gid = user_info.primary_gid; if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid, &state->response.data.user_info.group_rid)) { DEBUG(1, ("Could not extract group rid out of %s\n", sid_string_dbg(&sid))); return WINBINDD_ERROR; } return WINBINDD_OK; }
/* Lookup group membership given a rid. */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *group_sid, uint32 *num_names, DOM_SID ***sid_mem, char ***names, uint32 **name_types) { CLI_POLICY_HND *hnd = NULL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; uint32 i, total_names = 0; POLICY_HND dom_pol, group_pol; uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; BOOL got_dom_pol = False, got_group_pol = False; uint32 *rid_mem = NULL; uint32 group_rid; int retry; unsigned int j; fstring sid_string; DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name, sid_to_string(sid_string, group_sid))); if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid)) { goto done; } *num_names = 0; retry = 0; do { /* Get sam handle */ if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) goto done; /* Get domain handle */ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, des_access, &domain->sid, &dom_pol); } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1); if (!NT_STATUS_IS_OK(result)) goto done; got_dom_pol = True; /* Get group handle */ result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol, des_access, group_rid, &group_pol); if (!NT_STATUS_IS_OK(result)) goto done; got_group_pol = True; /* Step #1: Get a list of user rids that are the members of the group. */ result = cli_samr_query_groupmem(hnd->cli, mem_ctx, &group_pol, num_names, &rid_mem, name_types); if (!NT_STATUS_IS_OK(result)) goto done; if (!*num_names) { names = NULL; name_types = NULL; sid_mem = NULL; goto done; } /* Step #2: Convert list of rids into list of usernames. Do this in bunches of ~1000 to avoid crashing NT4. It looks like there is a buffer overflow or something like that lurking around somewhere. */ #define MAX_LOOKUP_RIDS 900 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *)); *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32)); *sid_mem = talloc_zero(mem_ctx, *num_names * sizeof(DOM_SID *)); for (j=0;j<(*num_names);j++) { (*sid_mem)[j] = rid_to_talloced_sid(domain, mem_ctx, (rid_mem)[j]); } if (*num_names>0 && (!*names || !*name_types)) { result = NT_STATUS_NO_MEMORY; goto done; } for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) { int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS); uint32 tmp_num_names = 0; char **tmp_names = NULL; uint32 *tmp_types = NULL; /* Lookup a chunk of rids */ result = cli_samr_lookup_rids(hnd->cli, mem_ctx, &dom_pol, 1000, /* flags */ num_lookup_rids, &rid_mem[i], &tmp_num_names, &tmp_names, &tmp_types); /* see if we have a real error (and yes the STATUS_SOME_UNMAPPED is the one returned from 2k) */ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED)) goto done; /* Copy result into array. The talloc system will take care of freeing the temporary arrays later on. */ memcpy(&(*names)[i], tmp_names, sizeof(char *) * tmp_num_names); memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) * tmp_num_names); total_names += tmp_num_names; } *num_names = total_names; result = NT_STATUS_OK; done: if (got_group_pol) cli_samr_close(hnd->cli, mem_ctx, &group_pol); if (got_dom_pol) cli_samr_close(hnd->cli, mem_ctx, &dom_pol); return result; }
/* Lookup groups a user is a member of. I wish Unix had a call like this! */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *user_sid, uint32 *num_groups, DOM_SID ***user_grpsids) { CLI_POLICY_HND *hnd; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; POLICY_HND dom_pol, user_pol; uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; BOOL got_dom_pol = False, got_user_pol = False; DOM_GID *user_groups; unsigned int i; unsigned int retry; fstring sid_string; uint32 user_rid; NET_USER_INFO_3 *user; DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid))); *num_groups = 0; *user_grpsids = NULL; /* so lets see if we have a cached user_info_3 */ if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL ) { DEBUG(5,("query_user: Cache lookup succeeded for %s\n", sid_string_static(user_sid))); *num_groups = user->num_groups; (*user_grpsids) = talloc(mem_ctx, sizeof(DOM_SID*) * (*num_groups)); for (i=0;i<(*num_groups);i++) { (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid); } SAFE_FREE(user); return NT_STATUS_OK; } /* no cache; hit the wire */ retry = 0; do { /* Get sam handle; if we fail here there is no hope */ if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) goto done; /* Get domain handle */ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, des_access, &domain->sid, &dom_pol); } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1); if (!NT_STATUS_IS_OK(result)) goto done; got_dom_pol = True; if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) { goto done; } /* Get user handle */ result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, des_access, user_rid, &user_pol); if (!NT_STATUS_IS_OK(result)) goto done; got_user_pol = True; /* Query user rids */ result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, num_groups, &user_groups); if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0) goto done; (*user_grpsids) = talloc(mem_ctx, sizeof(DOM_SID*) * (*num_groups)); if (!(*user_grpsids)) { result = NT_STATUS_NO_MEMORY; goto done; } for (i=0;i<(*num_groups);i++) { (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid); } done: /* Clean up policy handles */ if (got_user_pol) cli_samr_close(hnd->cli, mem_ctx, &user_pol); if (got_dom_pol) cli_samr_close(hnd->cli, mem_ctx, &dom_pol); return result; }
/* Lookup user information from a rid or username. */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *user_sid, WINBIND_USERINFO *user_info) { CLI_POLICY_HND *hnd = NULL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; POLICY_HND dom_pol, user_pol; BOOL got_dom_pol = False, got_user_pol = False; SAM_USERINFO_CTR *ctr; int retry; fstring sid_string; uint32 user_rid; NET_USER_INFO_3 *user; DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid))); if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) { goto done; } /* try netsamlogon cache first */ if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL ) { DEBUG(5,("query_user: Cache lookup succeeded for %s\n", sid_string_static(user_sid))); user_info->user_sid = rid_to_talloced_sid( domain, mem_ctx, user_rid ); user_info->group_sid = rid_to_talloced_sid( domain, mem_ctx, user->group_rid ); user_info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name); user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name); SAFE_FREE(user); return NT_STATUS_OK; } /* no cache; hit the wire */ retry = 0; do { /* Get sam handle; if we fail here there is no hope */ if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) goto done; /* Get domain handle */ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, SEC_RIGHTS_MAXIMUM_ALLOWED, &domain->sid, &dom_pol); } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1); if (!NT_STATUS_IS_OK(result)) goto done; got_dom_pol = True; /* Get user handle */ result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol); if (!NT_STATUS_IS_OK(result)) goto done; got_user_pol = True; /* Get user info */ result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 0x15, &ctr); if (!NT_STATUS_IS_OK(result)) goto done; cli_samr_close(hnd->cli, mem_ctx, &user_pol); got_user_pol = False; user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid); user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid); user_info->acct_name = unistr2_tdup(mem_ctx, &ctr->info.id21->uni_user_name); user_info->full_name = unistr2_tdup(mem_ctx, &ctr->info.id21->uni_full_name); done: /* Clean up policy handles */ if (got_user_pol) cli_samr_close(hnd->cli, mem_ctx, &user_pol); if (got_dom_pol) cli_samr_close(hnd->cli, mem_ctx, &dom_pol); return result; }
/* list all domain groups */ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, struct wb_acct_info **info) { ADS_STRUCT *ads = NULL; const char *attrs[] = {"userPrincipalName", "sAMAccountName", "name", "objectSid", NULL}; int i, count; ADS_STATUS rc; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; const char *filter; bool enum_dom_local_groups = False; *num_entries = 0; DEBUG(3,("ads: enum_dom_groups\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } /* only grab domain local groups for our domain */ if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) { enum_dom_local_groups = True; } /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o * rollup-fixes: * * According to Section 5.1(4) of RFC 2251 if a value of a type is it's * default value, it MUST be absent. In case of extensible matching the * "dnattr" boolean defaults to FALSE and so it must be only be present * when set to TRUE. * * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a * filter using bitwise matching rule then the buggy AD fails to decode * the extensible match. As a workaround set it to TRUE and thereby add * the dnAttributes "dn" field to cope with those older AD versions. * It should not harm and won't put any additional load on the AD since * none of the dn components have a bitmask-attribute. * * Thanks to Ralf Haferkamp for input and testing - Guenther */ filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED, ADS_LDAP_MATCHING_RULE_BIT_AND, enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP); if (filter == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry(ads, &res, filter, attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc))); goto done; } count = ads_count_replies(ads, res); if (count == 0) { DEBUG(1,("enum_dom_groups: No groups found\n")); goto done; } (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count); if (!*info) { status = NT_STATUS_NO_MEMORY; goto done; } i = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { char *name, *gecos; struct dom_sid sid; uint32 rid; name = ads_pull_username(ads, mem_ctx, msg); gecos = ads_pull_string(ads, mem_ctx, msg, "name"); if (!ads_pull_sid(ads, msg, "objectSid", &sid)) { DEBUG(1,("No sid for %s !?\n", name)); continue; } if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) { DEBUG(1,("No rid for %s !?\n", name)); continue; } fstrcpy((*info)[i].acct_name, name); fstrcpy((*info)[i].acct_desc, gecos); (*info)[i].rid = rid; i++; } (*num_entries) = i; status = NT_STATUS_OK; DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries))); done: if (res) ads_msgfree(ads, res); return status; }
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; }
static NTSTATUS SamInfo3_handle_sids(const char *username, const struct dom_sid *user_sid, const struct dom_sid *group_sid, struct netr_SamInfo3 *info3, struct dom_sid *domain_sid, struct extra_auth_info *extra) { if (sid_check_is_in_unix_users(user_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.rid = (uint32_t)(-1); sid_copy(&extra->user_sid, user_sid); DEBUG(10, ("Unix User found. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(user_sid))); } else { sid_copy(domain_sid, user_sid); sid_split_rid(domain_sid, &info3->base.rid); } if (is_null_sid(domain_sid)) { sid_copy(domain_sid, get_global_sam_sid()); } /* check if this is a "Unix Groups" domain group, * if so we need special handling */ if (sid_check_is_in_unix_groups(group_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.primary_gid = (uint32_t)(-1); sid_copy(&extra->pgid_sid, group_sid); DEBUG(10, ("Unix Group found. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(group_sid))); } else { bool ok = sid_peek_check_rid(domain_sid, group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group domain sid(%s) does not " "match the domain sid(%s) for %s(%s)\n", sid_string_dbg(group_sid), sid_string_dbg(domain_sid), username, sid_string_dbg(user_sid))); return NT_STATUS_INVALID_SID; } } return NT_STATUS_OK; }
NTSTATUS passwd_to_SamInfo3(TALLOC_CTX *mem_ctx, const char *unix_username, const struct passwd *pwd, struct netr_SamInfo3 **pinfo3, struct extra_auth_info *extra) { struct netr_SamInfo3 *info3; NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *domain_name = NULL; const char *user_name = NULL; struct dom_sid domain_sid; struct dom_sid user_sid; struct dom_sid group_sid; enum lsa_SidType type; uint32_t num_sids = 0; struct dom_sid *user_sids = NULL; bool is_null; bool ok; tmp_ctx = talloc_stackframe(); ok = lookup_name_smbconf(tmp_ctx, unix_username, LOOKUP_NAME_ALL, &domain_name, &user_name, &user_sid, &type); if (!ok) { status = NT_STATUS_NO_SUCH_USER; goto done; } if (type != SID_NAME_USER) { status = NT_STATUS_NO_SUCH_USER; goto done; } ok = winbind_lookup_usersids(tmp_ctx, &user_sid, &num_sids, &user_sids); /* Check if winbind is running */ if (ok) { /* * Winbind is running and the first element of the user_sids * is the primary group. */ if (num_sids > 0) { group_sid = user_sids[0]; } } else { /* * Winbind is not running, try to create the group_sid from the * passwd group id. */ /* * This can lead to a primary group of S-1-22-2-XX which * will be rejected by other Samba code. */ gid_to_sid(&group_sid, pwd->pw_gid); } /* * If we are a unix group, or a wellknown/builtin alias, * set the group_sid to the * 'Domain Users' RID of 513 which will always resolve to a * name. */ if (sid_check_is_in_unix_groups(&group_sid) || sid_check_is_in_builtin(&group_sid) || sid_check_is_in_wellknown_domain(&group_sid)) { if (sid_check_is_in_unix_users(&user_sid)) { sid_compose(&group_sid, get_global_sam_sid(), DOMAIN_RID_USERS); } else { sid_copy(&domain_sid, &user_sid); sid_split_rid(&domain_sid, NULL); sid_compose(&group_sid, &domain_sid, DOMAIN_RID_USERS); } } /* Make sure we have a valid group sid */ is_null = is_null_sid(&group_sid); if (is_null) { status = NT_STATUS_NO_SUCH_USER; goto done; } /* Construct a netr_SamInfo3 from the information we have */ info3 = talloc_zero(tmp_ctx, struct netr_SamInfo3); if (!info3) { status = NT_STATUS_NO_MEMORY; goto done; } info3->base.account_name.string = talloc_strdup(info3, unix_username); if (info3->base.account_name.string == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } ZERO_STRUCT(domain_sid); status = SamInfo3_handle_sids(unix_username, &user_sid, &group_sid, info3, &domain_sid, extra); if (!NT_STATUS_IS_OK(status)) { goto done; } info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); if (info3->base.domain_sid == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } ok = sid_peek_check_rid(&domain_sid, &group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group domain sid(%s) does not " "match the domain sid(%s) for %s(%s)\n", sid_string_dbg(&group_sid), sid_string_dbg(&domain_sid), unix_username, sid_string_dbg(&user_sid))); status = NT_STATUS_INVALID_SID; goto done; } info3->base.acct_flags = ACB_NORMAL; if (num_sids) { status = group_sids_to_info3(info3, user_sids, num_sids); if (!NT_STATUS_IS_OK(status)) { goto done; } } *pinfo3 = talloc_steal(mem_ctx, info3); status = NT_STATUS_OK; done: talloc_free(tmp_ctx); return status; }
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx, struct samu *samu, const char *login_server, struct netr_SamInfo3 **_info3, struct extra_auth_info *extra) { struct netr_SamInfo3 *info3; const struct dom_sid *user_sid; const struct dom_sid *group_sid; struct dom_sid domain_sid; struct dom_sid *group_sids; uint32_t num_group_sids = 0; const char *tmp; gid_t *gids; NTSTATUS status; bool ok; user_sid = pdb_get_user_sid(samu); group_sid = pdb_get_group_sid(samu); if (!user_sid || !group_sid) { DEBUG(1, ("Sam account is missing sids!\n")); return NT_STATUS_UNSUCCESSFUL; } info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); if (!info3) { return NT_STATUS_NO_MEMORY; } ZERO_STRUCT(domain_sid); /* check if this is a "Unix Users" domain user, * we need to handle it in a special way if that's the case */ if (sid_check_is_in_unix_users(user_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.rid = (uint32_t)(-1); sid_copy(&extra->user_sid, user_sid); DEBUG(10, ("Unix User found in struct samu. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(user_sid))); } else { sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &info3->base.rid); } if (is_null_sid(&domain_sid)) { sid_copy(&domain_sid, get_global_sam_sid()); } /* check if this is a "Unix Groups" domain group, * if so we need special handling */ if (sid_check_is_in_unix_groups(group_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.primary_gid = (uint32_t)(-1); sid_copy(&extra->pgid_sid, group_sid); DEBUG(10, ("Unix Group found in struct samu. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(group_sid))); } else { ok = sid_peek_check_rid(&domain_sid, group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group domain sid(%s) does not " "match the domain sid(%s) for %s(%s)\n", sid_string_dbg(group_sid), sid_string_dbg(&domain_sid), pdb_get_username(samu), sid_string_dbg(user_sid))); TALLOC_FREE(info3); return NT_STATUS_UNSUCCESSFUL; } } unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu)); unix_to_nt_time(&info3->base.last_logoff, get_time_t_max()); unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max()); unix_to_nt_time(&info3->base.last_password_change, pdb_get_pass_last_set_time(samu)); unix_to_nt_time(&info3->base.allow_password_change, pdb_get_pass_can_change_time(samu)); unix_to_nt_time(&info3->base.force_password_change, pdb_get_pass_must_change_time(samu)); tmp = pdb_get_username(samu); if (tmp) { info3->base.account_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.account_name.string); } tmp = pdb_get_fullname(samu); if (tmp) { info3->base.full_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.full_name.string); } tmp = pdb_get_logon_script(samu); if (tmp) { info3->base.logon_script.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.logon_script.string); } tmp = pdb_get_profile_path(samu); if (tmp) { info3->base.profile_path.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.profile_path.string); } tmp = pdb_get_homedir(samu); if (tmp) { info3->base.home_directory.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_directory.string); } tmp = pdb_get_dir_drive(samu); if (tmp) { info3->base.home_drive.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_drive.string); } info3->base.logon_count = pdb_get_logon_count(samu); info3->base.bad_password_count = pdb_get_bad_password_count(samu); info3->base.domain.string = talloc_strdup(info3, pdb_get_domain(samu)); RET_NOMEM(info3->base.domain.string); info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); RET_NOMEM(info3->base.domain_sid); status = pdb_enum_group_memberships(mem_ctx, samu, &group_sids, &gids, &num_group_sids); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to get groups from sam account.\n")); TALLOC_FREE(info3); return status; } if (num_group_sids) { status = group_sids_to_info3(info3, group_sids, num_group_sids); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return status; } } /* We don't need sids and gids after the conversion */ TALLOC_FREE(group_sids); TALLOC_FREE(gids); num_group_sids = 0; /* FIXME: should we add other flags ? */ info3->base.user_flags = NETLOGON_EXTRA_SIDS; if (login_server) { info3->base.logon_server.string = talloc_strdup(info3, login_server); RET_NOMEM(info3->base.logon_server.string); } info3->base.acct_flags = pdb_get_acct_ctrl(samu); *_info3 = info3; return NT_STATUS_OK; }
struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx, const struct wbcAuthUserInfo *info) { struct netr_SamInfo3 *info3; struct dom_sid user_sid; struct dom_sid group_sid; struct dom_sid domain_sid; NTSTATUS status; bool ok; memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid)); memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid)); info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); if (!info3) return NULL; unix_to_nt_time(&info3->base.logon_time, info->logon_time); unix_to_nt_time(&info3->base.logoff_time, info->logoff_time); unix_to_nt_time(&info3->base.kickoff_time, info->kickoff_time); unix_to_nt_time(&info3->base.last_password_change, info->pass_last_set_time); unix_to_nt_time(&info3->base.allow_password_change, info->pass_can_change_time); unix_to_nt_time(&info3->base.force_password_change, info->pass_must_change_time); if (info->account_name) { info3->base.account_name.string = talloc_strdup(info3, info->account_name); RET_NOMEM(info3->base.account_name.string); } if (info->full_name) { info3->base.full_name.string = talloc_strdup(info3, info->full_name); RET_NOMEM(info3->base.full_name.string); } if (info->logon_script) { info3->base.logon_script.string = talloc_strdup(info3, info->logon_script); RET_NOMEM(info3->base.logon_script.string); } if (info->profile_path) { info3->base.profile_path.string = talloc_strdup(info3, info->profile_path); RET_NOMEM(info3->base.profile_path.string); } if (info->home_directory) { info3->base.home_directory.string = talloc_strdup(info3, info->home_directory); RET_NOMEM(info3->base.home_directory.string); } if (info->home_drive) { info3->base.home_drive.string = talloc_strdup(info3, info->home_drive); RET_NOMEM(info3->base.home_drive.string); } info3->base.logon_count = info->logon_count; info3->base.bad_password_count = info->bad_password_count; sid_copy(&domain_sid, &user_sid); sid_split_rid(&domain_sid, &info3->base.rid); ok = sid_peek_check_rid(&domain_sid, &group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group sid domain does not" "match user sid domain for user: %s\n", info->account_name)); TALLOC_FREE(info3); return NULL; } status = wbcsids_to_samr_RidWithAttributeArray(info3, &info3->base.groups, &domain_sid, &info->sids[1], info->num_sids - 1); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return NULL; } status = wbcsids_to_netr_SidAttrArray(&domain_sid, &info->sids[1], info->num_sids - 1, info3, &info3->sids, &info3->sidcount); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return NULL; } info3->base.user_flags = info->user_flags; memcpy(info3->base.key.key, info->user_session_key, 16); if (info->logon_server) { info3->base.logon_server.string = talloc_strdup(info3, info->logon_server); RET_NOMEM(info3->base.logon_server.string); } if (info->domain_name) { info3->base.logon_domain.string = talloc_strdup(info3, info->domain_name); RET_NOMEM(info3->base.logon_domain.string); } info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); RET_NOMEM(info3->base.domain_sid); memcpy(info3->base.LMSessKey.key, info->lm_session_key, 8); info3->base.acct_flags = info->acct_flags; return info3; }