/* Lookup groups a user is a member of. */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, uint32 *p_num_groups, struct dom_sid **user_sids) { ADS_STRUCT *ads = NULL; const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL}; ADS_STATUS rc; int count; LDAPMessage *msg = NULL; char *user_dn = NULL; struct dom_sid *sids; int i; struct dom_sid primary_group; uint32 primary_group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; uint32_t num_groups = 0; DEBUG(3,("ads: lookup_usergroups\n")); *p_num_groups = 0; status = lookup_usergroups_cached(domain, mem_ctx, sid, p_num_groups, user_sids); if (NT_STATUS_IS_OK(status)) { return NT_STATUS_OK; } if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n", domain->name)); /* Tell the cache manager not to remember this one */ return NT_STATUS_SYNCHRONIZATION_REQUIRED; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry_sid(ads, &msg, sid, attrs); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: " "%s\n", sid_string_dbg(sid), ads_errstr(rc))); goto done; } count = ads_count_replies(ads, msg); if (count != 1) { status = NT_STATUS_UNSUCCESSFUL; DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: " "invalid number of results (count=%d)\n", sid_string_dbg(sid), count)); goto done; } if (!msg) { DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", sid_string_dbg(sid))); status = NT_STATUS_UNSUCCESSFUL; goto done; } user_dn = ads_get_dn(ads, mem_ctx, msg); if (user_dn == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { DEBUG(1,("%s: No primary group for sid=%s !?\n", domain->name, sid_string_dbg(sid))); goto done; } sid_compose(&primary_group, &domain->sid, primary_group_rid); count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); /* there must always be at least one group in the token, unless we are talking to a buggy Win2k server */ /* actually this only happens when the machine account has no read * permissions on the tokenGroup attribute - gd */ if (count == 0) { /* no tokenGroups */ /* lookup what groups this user is a member of by DN search on * "memberOf" */ status = lookup_usergroups_memberof(domain, mem_ctx, user_dn, &primary_group, &num_groups, user_sids); *p_num_groups = num_groups; if (NT_STATUS_IS_OK(status)) { goto done; } /* lookup what groups this user is a member of by DN search on * "member" */ status = lookup_usergroups_member(domain, mem_ctx, user_dn, &primary_group, &num_groups, user_sids); *p_num_groups = num_groups; goto done; } *user_sids = NULL; num_groups = 0; status = add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } for (i=0;i<count;i++) { /* ignore Builtin groups from ADS - Guenther */ if (sid_check_is_in_builtin(&sids[i])) { continue; } status = add_sid_to_array_unique(mem_ctx, &sids[i], user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } } *p_num_groups = (uint32)num_groups; status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n", sid_string_dbg(sid))); done: TALLOC_FREE(user_dn); ads_msgfree(ads, msg); return status; }
static NTSTATUS _idmap_adex_init(struct idmap_domain *dom) { ADS_STRUCT *ads = NULL; ADS_STATUS status; static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; struct dom_sid domain_sid; fstring dcname; struct sockaddr_storage ip; struct likewise_cell *lwcell; if (NT_STATUS_IS_OK(init_status)) return NT_STATUS_OK; /* Silently fail if we are not a member server in security = ads */ if ((lp_server_role() != ROLE_DOMAIN_MEMBER) || (lp_security() != SEC_ADS)) { init_status = NT_STATUS_INVALID_SERVER_STATE; BAIL_ON_NTSTATUS_ERROR(init_status); } /* fetch our domain SID first */ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; BAIL_ON_NTSTATUS_ERROR(init_status); } /* reuse the same ticket cache as winbindd */ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); /* Establish a connection to a DC */ if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) { init_status = NT_STATUS_NO_MEMORY; BAIL_ON_NTSTATUS_ERROR(init_status); } ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); ads->auth.realm = SMB_STRDUP(lp_realm()); /* get the DC name here to setup the server affinity cache and local krb5.conf */ get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip); status = ads_connect(ads); if (!ADS_ERR_OK(status)) { DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n", ads_errstr(status))); } init_status = ads_ntstatus(status); BAIL_ON_NTSTATUS_ERROR(init_status); /* Find out cell membership */ init_status = cell_locate_membership(ads); if (!NT_STATUS_IS_OK(init_status)) { DEBUG(0,("LWI: Fail to locate cell membership (%s).", nt_errstr(init_status))); goto done; } /* Fill in the cell information */ lwcell = cell_list_head(); init_status = cell_lookup_settings(lwcell); BAIL_ON_NTSTATUS_ERROR(init_status); /* Miscellaneous setup. E.g. set up the list of GC servers and domain list for our forest (does not actually connect). */ init_status = gc_init_list(); BAIL_ON_NTSTATUS_ERROR(init_status); init_status = domain_init_list(); BAIL_ON_NTSTATUS_ERROR(init_status); done: if (!NT_STATUS_IS_OK(init_status)) { DEBUG(1,("Likewise initialization failed (%s)\n", nt_errstr(init_status))); } /* cleanup */ if (!NT_STATUS_IS_OK(init_status)) { cell_list_destroy(); /* init_status stores the failure reason but we need to return success or else idmap_init() will drop us from the backend list */ return NT_STATUS_OK; } init_status = NT_STATUS_OK; return init_status; }
/* Lookup groups a user is a member of - alternate method, for when tokenGroups are not available. */ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const char *user_dn, struct dom_sid *primary_group, uint32_t *p_num_groups, struct dom_sid **user_sids) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; int count; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; char *ldap_exp; ADS_STRUCT *ads; const char *group_attrs[] = {"objectSid", NULL}; char *escaped_dn; uint32_t num_groups = 0; DEBUG(3,("ads: lookup_usergroups_member\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) { status = NT_STATUS_NO_MEMORY; goto done; } ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))", escaped_dn, ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED); if (!ldap_exp) { DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn)); TALLOC_FREE(escaped_dn); status = NT_STATUS_NO_MEMORY; goto done; } TALLOC_FREE(escaped_dn); rc = ads_search_retry(ads, &res, ldap_exp, group_attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); return ads_ntstatus(rc); } count = ads_count_replies(ads, res); *user_sids = NULL; num_groups = 0; /* always add the primary group to the sid array */ status = add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } if (count > 0) { for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { struct dom_sid group_sid; if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { DEBUG(1,("No sid for this group ?!?\n")); continue; } /* ignore Builtin groups from ADS - Guenther */ if (sid_check_is_in_builtin(&group_sid)) { continue; } status = add_sid_to_array(mem_ctx, &group_sid, user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } } } *p_num_groups = num_groups; status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn)); done: if (res) ads_msgfree(ads, res); return status; }
/* Lookup groups a user is a member of - alternate method, for when tokenGroups are not available. */ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const char *user_dn, struct dom_sid *primary_group, uint32_t *p_num_groups, struct dom_sid **user_sids) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; ADS_STRUCT *ads; const char *attrs[] = {"memberOf", NULL}; uint32_t num_groups = 0; struct dom_sid *group_sids = NULL; int i; char **strings = NULL; size_t num_strings = 0, num_sids = 0; DEBUG(3,("ads: lookup_usergroups_memberof\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("lookup_usergroups_memberof: No incoming trust for " "domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; return NT_STATUS_UNSUCCESSFUL; } rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, ADS_EXTENDED_DN_HEX_STRING, &strings, &num_strings); if (!ADS_ERR_OK(rc)) { DEBUG(1,("lookup_usergroups_memberof ads_search " "member=%s: %s\n", user_dn, ads_errstr(rc))); return ads_ntstatus(rc); } *user_sids = NULL; num_groups = 0; /* always add the primary group to the sid array */ status = add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1); if (!group_sids) { status = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i<num_strings; i++) { rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i], ADS_EXTENDED_DN_HEX_STRING, &(group_sids)[i]); if (!ADS_ERR_OK(rc)) { /* ignore members without SIDs */ if (NT_STATUS_EQUAL(ads_ntstatus(rc), NT_STATUS_NOT_FOUND)) { continue; } else { status = ads_ntstatus(rc); goto done; } } num_sids++; } if (i == 0) { DEBUG(1,("No memberOf for this user?!?\n")); status = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i<num_sids; i++) { /* ignore Builtin groups from ADS - Guenther */ if (sid_check_is_in_builtin(&group_sids[i])) { continue; } status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } } *p_num_groups = num_groups; status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn)); done: TALLOC_FREE(strings); TALLOC_FREE(group_sids); return status; }
NTSTATUS cell_connect(struct likewise_cell *c) { ADS_STRUCT *ads = NULL; ADS_STATUS ads_status; fstring dc_name; struct sockaddr_storage dcip; NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; /* have to at least have the AD domain name */ if (!c->dns_domain) { nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; BAIL_ON_NTSTATUS_ERROR(nt_status); } /* clear out any old information */ if (c->conn) { ads_destroy(&c->conn); c->conn = NULL; } /* now setup the new connection */ ads = ads_init(c->dns_domain, NULL, NULL); BAIL_ON_PTR_ERROR(ads, nt_status); ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); ads->auth.realm = SMB_STRDUP(lp_realm()); /* Make the connection. We should already have an initial TGT using the machine creds */ if (cell_flags(c) & LWCELL_FLAG_GC_CELL) { ads_status = ads_connect_gc(ads); } else { /* Set up server affinity for normal cells and the client site name cache */ if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) { nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; BAIL_ON_NTSTATUS_ERROR(nt_status); } ads_status = ads_connect(ads); } c->conn = ads; nt_status = ads_ntstatus(ads_status); done: if (!NT_STATUS_IS_OK(nt_status)) { ads_destroy(&ads); c->conn = NULL; } return nt_status; }
/* Lookup user information from a rid */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, struct wbint_userinfo *info) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "*", NULL }; ADS_STATUS rc; int count; LDAPMessage *msg = NULL; char *ldap_exp; char *sidstr; uint32 group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; struct netr_SamInfo3 *user = NULL; gid_t gid = -1; int ret; char *ads_name; DEBUG(3,("ads: query_user\n")); info->homedir = NULL; info->shell = NULL; /* try netsamlogon cache first */ if (winbindd_use_cache() && (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) { DEBUG(5,("query_user: Cache lookup succeeded for %s\n", sid_string_dbg(sid))); sid_compose(&info->user_sid, &domain->sid, user->base.rid); sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid); info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string); info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string); nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid ); info->primary_gid = gid; TALLOC_FREE(user); return NT_STATUS_OK; } if ( !winbindd_can_contact_domain(domain)) { DEBUG(8,("query_user: No incoming trust from domain %s\n", domain->name)); /* We still need to generate some basic information about the user even if we cannot contact the domain. Most of this stuff we can deduce. */ sid_copy( &info->user_sid, sid ); /* Assume "Domain Users" for the primary group */ sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS ); /* Try to fill in what the nss_info backend can do */ nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; return NT_STATUS_OK; } /* no cache...do the query */ if ( (ads = ads_cached_connection(domain)) == NULL ) { domain->last_status = NT_STATUS_SERVER_DISABLED; return NT_STATUS_SERVER_DISABLED; } sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid); ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr); TALLOC_FREE(sidstr); if (ret == -1) { return NT_STATUS_NO_MEMORY; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); SAFE_FREE(ldap_exp); if (!ADS_ERR_OK(rc) || !msg) { DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_string_dbg(sid), ads_errstr(rc))); return ads_ntstatus(rc); } count = ads_count_replies(ads, msg); if (count != 1) { DEBUG(1,("query_user(sid=%s): Not found\n", sid_string_dbg(sid))); ads_msgfree(ads, msg); return NT_STATUS_NO_SUCH_USER; } info->acct_name = ads_pull_username(ads, mem_ctx, msg); if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { DEBUG(1,("No primary group for %s !?\n", sid_string_dbg(sid))); ads_msgfree(ads, msg); return NT_STATUS_NO_SUCH_USER; } sid_copy(&info->user_sid, sid); sid_compose(&info->group_sid, &domain->sid, group_rid); /* * We have to fetch the "name" attribute before doing the * nss_get_info_cached call. nss_get_info_cached might destroy * the ads struct, potentially invalidating the ldap message. */ ads_name = ads_pull_string(ads, mem_ctx, msg, "name"); ads_msgfree(ads, msg); msg = NULL; status = nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("nss_get_info_cached failed: %s\n", nt_errstr(status))); return status; } if (info->full_name == NULL) { info->full_name = ads_name; } else { TALLOC_FREE(ads_name); } status = NT_STATUS_OK; DEBUG(3,("ads query_user gave %s\n", info->acct_name)); return NT_STATUS_OK; }
/* a wrapper around ldap_search_s that retries depending on the error code this is supposed to catch dropped connections and auto-reconnect */ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, const char **attrs, void *args, LDAPMessage **res) { ADS_STATUS status = ADS_SUCCESS; int count = 3; char *bp; *res = NULL; if (!ads->ldap.ld && time_mono(NULL) - ads->ldap.last_attempt < ADS_RECONNECT_TIME) { return ADS_ERROR(LDAP_SERVER_DOWN); } bp = SMB_STRDUP(bind_path); if (!bp) { return ADS_ERROR(LDAP_NO_MEMORY); } *res = NULL; /* when binding anonymously, we cannot use the paged search LDAP * control - Guenther */ if (ads->auth.flags & ADS_AUTH_ANON_BIND) { status = ads_do_search(ads, bp, scope, expr, attrs, res); } else { status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res); } if (ADS_ERR_OK(status)) { DEBUG(5,("Search for %s in <%s> gave %d replies\n", expr, bp, ads_count_replies(ads, *res))); SAFE_FREE(bp); return status; } while (--count) { if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) && ads->config.ldap_page_size >= 250) { int new_page_size = (ads->config.ldap_page_size / 2); DEBUG(1, ("Reducing LDAP page size from %d to %d due to IO_TIMEOUT\n", ads->config.ldap_page_size, new_page_size)); ads->config.ldap_page_size = new_page_size; } if (*res) ads_msgfree(ads, *res); *res = NULL; DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", ads->config.realm, ads_errstr(status))); ads_disconnect(ads); status = ads_connect(ads); if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n", ads_errstr(status))); ads_destroy(&ads); SAFE_FREE(bp); return status; } *res = NULL; /* when binding anonymously, we cannot use the paged search LDAP * control - Guenther */ if (ads->auth.flags & ADS_AUTH_ANON_BIND) { status = ads_do_search(ads, bp, scope, expr, attrs, res); } else { status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res); } if (ADS_ERR_OK(status)) { DEBUG(5,("Search for filter: %s, base: %s gave %d replies\n", expr, bp, ads_count_replies(ads, *res))); SAFE_FREE(bp); return status; } } SAFE_FREE(bp); if (!ADS_ERR_OK(status)) { DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(status))); } return status; }
static NTSTATUS add_primary_group_members( ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, char ***all_members, size_t *num_all_members) { char *filter; NTSTATUS status = NT_STATUS_NO_MEMORY; ADS_STATUS rc; const char *attrs[] = { "dn", NULL }; LDAPMessage *res = NULL; LDAPMessage *msg; char **members; size_t num_members; ads_control args; filter = talloc_asprintf( mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))", (unsigned)rid); if (filter == NULL) { goto done; } args.control = ADS_EXTENDED_DN_OID; args.val = ADS_EXTENDED_DN_HEX_STRING; args.critical = True; rc = ads_do_search_all_args(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE, filter, attrs, &args, &res); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc))); goto done; } if (res == NULL) { DEBUG(1,("%s: ads_search returned NULL res\n", __func__)); goto done; } num_members = ads_count_replies(ads, res); DEBUG(10, ("%s: Got %ju primary group members\n", __func__, (uintmax_t)num_members)); if (num_members == 0) { status = NT_STATUS_OK; goto done; } members = talloc_realloc(mem_ctx, *all_members, char *, *num_all_members + num_members); if (members == NULL) { DEBUG(1, ("%s: talloc_realloc failed\n", __func__)); goto done; } *all_members = members; for (msg = ads_first_entry(ads, res); msg != NULL; msg = ads_next_entry(ads, msg)) { char *dn; dn = ads_get_dn(ads, members, msg); if (dn == NULL) { DEBUG(1, ("%s: ads_get_dn failed\n", __func__)); continue; } members[*num_all_members] = dn; *num_all_members += 1; } status = NT_STATUS_OK; done: if (res != NULL) { ads_msgfree(ads, res); } TALLOC_FREE(filter); return status; }
/* list all domain groups */ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t *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)) { status = ads_ntstatus(rc); DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc))); goto done; } else if (!res) { DEBUG(1,("enum_dom_groups ads_search returned NULL res\n")); 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_t 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; }
/* Query display info for a realm. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t **prids) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "sAMAccountType", "objectSid", NULL }; int count; uint32_t *rids = NULL; ADS_STATUS rc; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; DEBUG(3,("ads: query_user_list\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("query_user_list: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); if (!ADS_ERR_OK(rc)) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); status = ads_ntstatus(rc); goto done; } else if (!res) { DEBUG(1,("query_user_list ads_search returned NULL res\n")); goto done; } count = ads_count_replies(ads, res); if (count == 0) { DEBUG(1,("query_user_list: No users found\n")); goto done; } rids = talloc_zero_array(mem_ctx, uint32_t, count); if (rids == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } count = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { struct dom_sid user_sid; uint32_t atype; bool ok; ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype); if (!ok) { DBG_INFO("Object lacks sAMAccountType attribute\n"); continue; } if (ds_atype_map(atype) != SID_NAME_USER) { DBG_INFO("Not a user account? atype=0x%x\n", atype); continue; } if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) { char *dn = ads_get_dn(ads, talloc_tos(), msg); DBG_INFO("No sid for %s !?\n", dn); TALLOC_FREE(dn); continue; } if (!dom_sid_in_domain(&domain->sid, &user_sid)) { fstring sidstr, domstr; DBG_WARNING("Got sid %s in domain %s\n", sid_to_fstring(sidstr, &user_sid), sid_to_fstring(domstr, &domain->sid)); continue; } sid_split_rid(&user_sid, &rids[count]); count += 1; } rids = talloc_realloc(mem_ctx, rids, uint32_t, count); if (prids != NULL) { *prids = rids; } status = NT_STATUS_OK; DBG_NOTICE("ads query_user_list gave %d entries\n", count); done: return status; }
static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, const int sockfd, const int pipe_index, const char *controller, struct cli_state **cli, BOOL *retry) { char *machine_password, *machine_krb5_principal; char *ipc_username, *ipc_domain, *ipc_password; BOOL got_mutex; BOOL add_failed_connection = True; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; struct sockaddr peeraddr; socklen_t peeraddr_len; struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr; machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { SAFE_FREE(machine_password); return NT_STATUS_NO_MEMORY; } cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); *retry = True; got_mutex = secrets_named_mutex(controller, WINBIND_SERVER_MUTEX_WAIT_TIME); if (!got_mutex) { DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", controller)); result = NT_STATUS_POSSIBLE_DEADLOCK; goto done; } if ((*cli = cli_initialise(NULL)) == NULL) { DEBUG(1, ("Could not cli_initialize\n")); result = NT_STATUS_NO_MEMORY; goto done; } (*cli)->timeout = 10000; /* 10 seconds */ (*cli)->fd = sockfd; fstrcpy((*cli)->desthost, controller); (*cli)->use_kerberos = True; peeraddr_len = sizeof(peeraddr); if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) || (peeraddr_len != sizeof(struct sockaddr_in)) || (peeraddr_in->sin_family != PF_INET)) { DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno))); goto done; } if (ntohs(peeraddr_in->sin_port) == 139) { struct nmb_name calling; struct nmb_name called; make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called, "*SMBSERVER", 0x20); if (!cli_session_request(*cli, &calling, &called)) { DEBUG(8, ("cli_session_request failed for %s\n", controller)); goto done; } } cli_setup_signing_state(*cli, Undefined); if (!cli_negprot(*cli)) { DEBUG(1, ("cli_negprot failed\n")); cli_shutdown(*cli); goto done; } /* Krb5 session */ if ((lp_security() == SEC_ADS) && ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY)) { ADS_STATUS ads_status; (*cli)->use_kerberos = True; DEBUG(5, ("connecting to %s from %s with kerberos principal " "[%s]\n", controller, global_myname(), machine_krb5_principal)); ads_status = cli_session_setup_spnego(*cli, machine_krb5_principal, machine_password, lp_workgroup()); if (!ADS_ERR_OK(ads_status)) DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status))); result = ads_ntstatus(ads_status); } if (NT_STATUS_IS_OK(result)) goto session_setup_done; /* Fall back to non-kerberos session setup */ (*cli)->use_kerberos = False; if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) && (strlen(ipc_username) > 0)) { /* Only try authenticated if we have a username */ DEBUG(5, ("connecting to %s from %s with username " "[%s]\\[%s]\n", controller, global_myname(), ipc_domain, ipc_username)); if (cli_session_setup(*cli, ipc_username, ipc_password, strlen(ipc_password)+1, ipc_password, strlen(ipc_password)+1, ipc_domain)) { DEBUG(5, ("authenticated session setup failed\n")); goto session_setup_done; } } /* Fall back to anonymous connection, this might fail later */ if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) { DEBUG(5, ("Connected anonymously\n")); goto session_setup_done; } result = cli_nt_error(*cli); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; /* We can't session setup */ goto done; session_setup_done: if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) { result = cli_nt_error(*cli); DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result))); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; cli_shutdown(*cli); goto done; } secrets_named_mutex_release(controller); got_mutex = False; *retry = False; /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel. Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call. So just drop it on the lsarpc pipe */ if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) { NTSTATUS status = setup_schannel( *cli, domain->name ); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("schannel refused - continuing without " "schannel (%s)\n", nt_errstr(status))); } } /* set the domain if empty; needed for schannel connections */ if ( !*(*cli)->domain ) fstrcpy( (*cli)->domain, domain->name ); if ( !cli_nt_session_open (*cli, pipe_index) ) { result = NT_STATUS_PIPE_NOT_AVAILABLE; /* This might be a NT4 DC */ if ( is_win2k_pipe(pipe_index) ) add_failed_connection = False; cli_shutdown(*cli); goto done; } result = NT_STATUS_OK; add_failed_connection = False; done: if (got_mutex) secrets_named_mutex_release(controller); SAFE_FREE(machine_password); SAFE_FREE(machine_krb5_principal); SAFE_FREE(ipc_username); SAFE_FREE(ipc_domain); SAFE_FREE(ipc_password); if (add_failed_connection) add_failed_connection_entry(domain->name, controller, result); return result; }