LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_ads.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 0 688 0.0 %
Date: 2024-05-31 13:13:24 Functions: 0 21 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Winbind ADS backend functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2001
       7             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
       8             :    Copyright (C) Gerald (Jerry) Carter 2004
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "winbindd.h"
      26             : #include "winbindd_ads.h"
      27             : #include "libsmb/namequery.h"
      28             : #include "rpc_client/rpc_client.h"
      29             : #include "../librpc/gen_ndr/ndr_netlogon_c.h"
      30             : #include "../libds/common/flags.h"
      31             : #include "ads.h"
      32             : #include "../libcli/ldap/ldap_ndr.h"
      33             : #include "../libcli/security/security.h"
      34             : #include "../libds/common/flag_mapping.h"
      35             : #include "libsmb/samlogon_cache.h"
      36             : #include "passdb.h"
      37             : #include "auth/credentials/credentials.h"
      38             : 
      39             : #ifdef HAVE_ADS
      40             : 
      41             : #undef DBGC_CLASS
      42             : #define DBGC_CLASS DBGC_WINBIND
      43             : 
      44             : extern struct winbindd_methods reconnect_methods;
      45             : extern struct winbindd_methods msrpc_methods;
      46             : 
      47             : /**
      48             :  * Check if cached connection can be reused. If the connection cannot
      49             :  * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
      50             :  */
      51           0 : static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
      52             : {
      53             : 
      54           0 :         ADS_STRUCT *ads = *adsp;
      55             : 
      56           0 :         if (ads != NULL) {
      57           0 :                 time_t expire;
      58           0 :                 time_t now = time(NULL);
      59             : 
      60           0 :                 expire = nt_time_to_unix(ads->auth.expire_time);
      61             : 
      62           0 :                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
      63             :                           "is now %d)\n", (uint32_t)expire - (uint32_t)now,
      64             :                           (uint32_t) expire, (uint32_t) now));
      65             : 
      66           0 :                 if ( ads->config.realm && (expire > now)) {
      67           0 :                         return;
      68             :                 } else {
      69             :                         /* we own this ADS_STRUCT so make sure it goes away */
      70           0 :                         DEBUG(7,("Deleting expired ads struct\n"));
      71           0 :                         TALLOC_FREE(ads);
      72           0 :                         *adsp = NULL;
      73             :                 }
      74             :         }
      75             : }
      76             : 
      77             : 
      78           0 : static NTSTATUS ads_cached_connection_reconnect_creds(struct ads_struct *ads,
      79             :                                                       void *private_data,
      80             :                                                       TALLOC_CTX *mem_ctx,
      81             :                                                       struct cli_credentials **creds)
      82             : {
      83           0 :         struct winbindd_domain *target_domain = NULL;
      84             : 
      85           0 :         if (ads->server.realm != NULL) {
      86           0 :                 target_domain = find_domain_from_name_noinit(ads->server.realm);
      87             :         }
      88           0 :         if (target_domain == NULL && ads->server.workgroup != NULL) {
      89           0 :                 target_domain = find_domain_from_name_noinit(ads->server.workgroup);
      90             :         }
      91             : 
      92           0 :         if (target_domain == NULL) {
      93           0 :                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
      94             :         }
      95             : 
      96           0 :         return winbindd_get_trust_credentials(target_domain,
      97             :                                               mem_ctx,
      98             :                                               false, /* netlogon */
      99             :                                               false, /* ipc_fallback */
     100             :                                               creds);
     101             : }
     102             : 
     103             : /**
     104             :  * @brief Establish a connection to a DC
     105             :  *
     106             :  * @param[out]   adsp             ADS_STRUCT that will be created
     107             :  * @param[in]    target_domain    target domain
     108             :  * @param[in]    ldap_server      DNS name of server to connect to
     109             :  * @param[in]    creds            credentials to use
     110             :  * @param[in]    auth_realm       Realm of local domain for creating krb token
     111             :  *
     112             :  * @return ADS_STATUS
     113             :  */
     114           0 : static ADS_STATUS ads_cached_connection_connect(struct winbindd_domain *target_domain,
     115             :                                                 const char *ldap_server,
     116             :                                                 TALLOC_CTX *mem_ctx,
     117             :                                                 ADS_STRUCT **adsp)
     118             : {
     119           0 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
     120           0 :         const char *target_realm = target_domain->alt_name;
     121           0 :         const char *target_dom_name = target_domain->name;
     122           0 :         struct cli_credentials *creds = NULL;
     123           0 :         ADS_STRUCT *ads;
     124           0 :         ADS_STATUS status;
     125           0 :         NTSTATUS ntstatus;
     126           0 :         struct sockaddr_storage dc_ss;
     127           0 :         fstring dc_name;
     128             : 
     129             :         /* the machine acct password might have change - fetch it every time */
     130             : 
     131           0 :         ntstatus = winbindd_get_trust_credentials(target_domain,
     132             :                                                   tmp_ctx,
     133             :                                                   false, /* netlogon */
     134             :                                                   false, /* ipc_fallback */
     135             :                                                   &creds);
     136           0 :         if (!NT_STATUS_IS_OK(ntstatus)) {
     137           0 :                 status = ADS_ERROR_NT(ntstatus);
     138           0 :                 goto out;
     139             :         }
     140             : 
     141           0 :         ads = ads_init(tmp_ctx,
     142             :                        target_realm,
     143             :                        target_dom_name,
     144             :                        ldap_server,
     145             :                        ADS_SASL_SEAL);
     146           0 :         if (!ads) {
     147           0 :                 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
     148           0 :                 status = ADS_ERROR(LDAP_NO_MEMORY);
     149           0 :                 goto out;
     150             :         }
     151             : 
     152           0 :         ads_set_reconnect_fn(ads, ads_cached_connection_reconnect_creds, NULL);
     153             : 
     154             :         /* Setup the server affinity cache.  We don't reaally care
     155             :            about the name.  Just setup affinity and the KRB5_CONFIG
     156             :            file. */
     157           0 :         get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
     158             : 
     159           0 :         status = ads_connect_creds(ads, creds);
     160           0 :         if (!ADS_ERR_OK(status)) {
     161           0 :                 DEBUG(1,("ads_connect for domain %s failed: %s\n",
     162             :                          target_dom_name, ads_errstr(status)));
     163           0 :                 goto out;
     164             :         }
     165             : 
     166           0 :         *adsp = talloc_move(mem_ctx, &ads);
     167           0 : out:
     168           0 :         TALLOC_FREE(tmp_ctx);
     169           0 :         return status;
     170             : }
     171             : 
     172           0 : ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
     173             :                                        TALLOC_CTX *mem_ctx,
     174             :                                        ADS_STRUCT **adsp)
     175             : {
     176           0 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
     177           0 :         char *ldap_server = NULL;
     178           0 :         struct winbindd_domain *wb_dom = NULL;
     179           0 :         ADS_STATUS status;
     180             : 
     181           0 :         if (IS_AD_DC) {
     182             :                 /*
     183             :                  * Make sure we never try to use LDAP against
     184             :                  * a trusted domain as AD DC.
     185             :                  */
     186           0 :                 TALLOC_FREE(tmp_ctx);
     187           0 :                 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
     188             :         }
     189             : 
     190           0 :         ads_cached_connection_reuse(adsp);
     191           0 :         if (*adsp != NULL) {
     192           0 :                 TALLOC_FREE(tmp_ctx);
     193           0 :                 return ADS_SUCCESS;
     194             :         }
     195             : 
     196             :         /*
     197             :          * At this point we only have the NetBIOS domain name.
     198             :          * Check if we can get server name and realm from SAF cache
     199             :          * and the domain list.
     200             :          */
     201           0 :         ldap_server = saf_fetch(tmp_ctx, dom_name);
     202             : 
     203           0 :         DBG_DEBUG("ldap_server from saf cache: '%s'\n",
     204             :                    ldap_server ? ldap_server : "");
     205             : 
     206           0 :         wb_dom = find_domain_from_name(dom_name);
     207           0 :         if (wb_dom == NULL) {
     208           0 :                 DBG_DEBUG("could not find domain '%s'\n", dom_name);
     209           0 :                 TALLOC_FREE(tmp_ctx);
     210           0 :                 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
     211             :         }
     212             : 
     213           0 :         DBG_DEBUG("find_domain_from_name found realm '%s' for "
     214             :                   " domain '%s'\n", wb_dom->alt_name, dom_name);
     215             : 
     216           0 :         status = ads_cached_connection_connect(
     217             :                 wb_dom,
     218             :                 ldap_server,            /* DNS name to connect to. */
     219             :                 mem_ctx,                /* memory context for ads struct */
     220             :                 adsp);                  /* Returns ads struct. */
     221             : 
     222           0 :         TALLOC_FREE(tmp_ctx);
     223             : 
     224           0 :         return status;
     225             : }
     226             : 
     227             : /*
     228             :   return our ads connections structure for a domain. We keep the connection
     229             :   open to make things faster
     230             : */
     231           0 : static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
     232             :                                         ADS_STRUCT **adsp)
     233             : {
     234           0 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
     235           0 :         ADS_STATUS status;
     236             : 
     237           0 :         if (IS_AD_DC) {
     238             :                 /*
     239             :                  * Make sure we never try to use LDAP against
     240             :                  * a trusted domain as AD DC.
     241             :                  */
     242           0 :                 TALLOC_FREE(tmp_ctx);
     243           0 :                 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
     244             :         }
     245             : 
     246           0 :         DBG_DEBUG("ads_cached_connection\n");
     247             : 
     248           0 :         ads_cached_connection_reuse(&domain->backend_data.ads_conn);
     249           0 :         if (domain->backend_data.ads_conn != NULL) {
     250           0 :                 *adsp = domain->backend_data.ads_conn;
     251           0 :                 TALLOC_FREE(tmp_ctx);
     252           0 :                 return ADS_SUCCESS;
     253             :         }
     254             : 
     255           0 :         status = ads_cached_connection_connect(
     256             :                                         domain,
     257             :                                         NULL,
     258             :                                         domain,
     259           0 :                                         &domain->backend_data.ads_conn);
     260           0 :         if (!ADS_ERR_OK(status)) {
     261             :                 /* if we get ECONNREFUSED then it might be a NT4
     262             :                    server, fall back to MSRPC */
     263           0 :                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
     264           0 :                     status.err.rc == ECONNREFUSED) {
     265             :                         /* 'reconnect_methods' is the MS-RPC backend. */
     266           0 :                         DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
     267             :                                    domain->name);
     268           0 :                         domain->backend = &reconnect_methods;
     269             :                 }
     270           0 :                 TALLOC_FREE(tmp_ctx);
     271           0 :                 return status;
     272             :         }
     273             : 
     274           0 :         *adsp = domain->backend_data.ads_conn;
     275           0 :         TALLOC_FREE(tmp_ctx);
     276           0 :         return ADS_SUCCESS;
     277             : }
     278             : 
     279             : /* Query display info for a realm. This is the basic user list fn */
     280           0 : static NTSTATUS query_user_list(struct winbindd_domain *domain,
     281             :                                TALLOC_CTX *mem_ctx,
     282             :                                uint32_t **prids)
     283             : {
     284           0 :         ADS_STRUCT *ads = NULL;
     285           0 :         const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
     286           0 :         int count;
     287           0 :         uint32_t *rids = NULL;
     288           0 :         ADS_STATUS rc;
     289           0 :         LDAPMessage *res = NULL;
     290           0 :         LDAPMessage *msg = NULL;
     291           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     292             : 
     293           0 :         DEBUG(3,("ads: query_user_list\n"));
     294             : 
     295           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     296           0 :                 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
     297             :                           domain->name));
     298           0 :                 return NT_STATUS_OK;
     299             :         }
     300             : 
     301           0 :         rc = ads_cached_connection(domain, &ads);
     302           0 :         if (!ADS_ERR_OK(rc)) {
     303           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
     304           0 :                 goto done;
     305             :         }
     306             : 
     307           0 :         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
     308           0 :         if (!ADS_ERR_OK(rc)) {
     309           0 :                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
     310           0 :                 status = ads_ntstatus(rc);
     311           0 :                 goto done;
     312           0 :         } else if (!res) {
     313           0 :                 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
     314           0 :                 goto done;
     315             :         }
     316             : 
     317           0 :         count = ads_count_replies(ads, res);
     318           0 :         if (count == 0) {
     319           0 :                 DEBUG(1,("query_user_list: No users found\n"));
     320           0 :                 goto done;
     321             :         }
     322             : 
     323           0 :         rids = talloc_zero_array(mem_ctx, uint32_t, count);
     324           0 :         if (rids == NULL) {
     325           0 :                 status = NT_STATUS_NO_MEMORY;
     326           0 :                 goto done;
     327             :         }
     328             : 
     329           0 :         count = 0;
     330             : 
     331           0 :         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
     332           0 :                 struct dom_sid user_sid;
     333           0 :                 uint32_t atype;
     334           0 :                 bool ok;
     335             : 
     336           0 :                 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
     337           0 :                 if (!ok) {
     338           0 :                         DBG_INFO("Object lacks sAMAccountType attribute\n");
     339           0 :                         continue;
     340             :                 }
     341           0 :                 if (ds_atype_map(atype) != SID_NAME_USER) {
     342           0 :                         DBG_INFO("Not a user account? atype=0x%x\n", atype);
     343           0 :                         continue;
     344             :                 }
     345             : 
     346           0 :                 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
     347           0 :                         char *dn = ads_get_dn(ads, talloc_tos(), msg);
     348           0 :                         DBG_INFO("No sid for %s !?\n", dn);
     349           0 :                         TALLOC_FREE(dn);
     350           0 :                         continue;
     351             :                 }
     352             : 
     353           0 :                 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
     354           0 :                         struct dom_sid_buf sidstr, domstr;
     355           0 :                         DBG_WARNING("Got sid %s in domain %s\n",
     356             :                                     dom_sid_str_buf(&user_sid, &sidstr),
     357             :                                     dom_sid_str_buf(&domain->sid, &domstr));
     358           0 :                         continue;
     359             :                 }
     360             : 
     361           0 :                 sid_split_rid(&user_sid, &rids[count]);
     362           0 :                 count += 1;
     363             :         }
     364             : 
     365           0 :         rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
     366           0 :         if (prids != NULL) {
     367           0 :                 *prids = rids;
     368             :         } else {
     369           0 :                 TALLOC_FREE(rids);
     370             :         }
     371             : 
     372           0 :         status = NT_STATUS_OK;
     373             : 
     374           0 :         DBG_NOTICE("ads query_user_list gave %d entries\n", count);
     375             : 
     376           0 : done:
     377           0 :         ads_msgfree(ads, res);
     378           0 :         return status;
     379             : }
     380             : 
     381             : /* list all domain groups */
     382           0 : static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
     383             :                                 TALLOC_CTX *mem_ctx,
     384             :                                 uint32_t *num_entries,
     385             :                                 struct wb_acct_info **info)
     386             : {
     387           0 :         ADS_STRUCT *ads = NULL;
     388           0 :         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
     389             :                                "name", "objectSid", NULL};
     390           0 :         int i, count;
     391           0 :         ADS_STATUS rc;
     392           0 :         LDAPMessage *res = NULL;
     393           0 :         LDAPMessage *msg = NULL;
     394           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     395           0 :         const char *filter;
     396           0 :         bool enum_dom_local_groups = False;
     397             : 
     398           0 :         *num_entries = 0;
     399             : 
     400           0 :         DEBUG(3,("ads: enum_dom_groups\n"));
     401             : 
     402           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     403           0 :                 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
     404             :                           domain->name));
     405           0 :                 return NT_STATUS_OK;
     406             :         }
     407             : 
     408             :         /* only grab domain local groups for our domain */
     409           0 :         if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
     410           0 :                 enum_dom_local_groups = True;
     411             :         }
     412             : 
     413             :         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
     414             :          * rollup-fixes:
     415             :          *
     416             :          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
     417             :          * default value, it MUST be absent. In case of extensible matching the
     418             :          * "dnattr" boolean defaults to FALSE and so it must be only be present
     419             :          * when set to TRUE.
     420             :          *
     421             :          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
     422             :          * filter using bitwise matching rule then the buggy AD fails to decode
     423             :          * the extensible match. As a workaround set it to TRUE and thereby add
     424             :          * the dnAttributes "dn" field to cope with those older AD versions.
     425             :          * It should not harm and won't put any additional load on the AD since
     426             :          * none of the dn components have a bitmask-attribute.
     427             :          *
     428             :          * Thanks to Ralf Haferkamp for input and testing - Guenther */
     429             : 
     430           0 :         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
     431             :                                  "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
     432             :                                  "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
     433             :                                 GROUP_TYPE_SECURITY_ENABLED,
     434             :                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
     435             : 
     436           0 :         if (filter == NULL) {
     437           0 :                 status = NT_STATUS_NO_MEMORY;
     438           0 :                 goto done;
     439             :         }
     440             : 
     441           0 :         rc = ads_cached_connection(domain, &ads);
     442           0 :         if (!ADS_ERR_OK(rc)) {
     443           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
     444           0 :                 goto done;
     445             :         }
     446             : 
     447           0 :         rc = ads_search_retry(ads, &res, filter, attrs);
     448           0 :         if (!ADS_ERR_OK(rc)) {
     449           0 :                 status = ads_ntstatus(rc);
     450           0 :                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
     451           0 :                 goto done;
     452           0 :         } else if (!res) {
     453           0 :                 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
     454           0 :                 goto done;
     455             :         }
     456             : 
     457           0 :         count = ads_count_replies(ads, res);
     458           0 :         if (count == 0) {
     459           0 :                 DEBUG(1,("enum_dom_groups: No groups found\n"));
     460           0 :                 goto done;
     461             :         }
     462             : 
     463           0 :         (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
     464           0 :         if (!*info) {
     465           0 :                 status = NT_STATUS_NO_MEMORY;
     466           0 :                 goto done;
     467             :         }
     468             : 
     469           0 :         i = 0;
     470             : 
     471           0 :         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
     472           0 :                 char *name, *gecos;
     473           0 :                 struct dom_sid sid;
     474           0 :                 uint32_t rid;
     475             : 
     476           0 :                 name = ads_pull_username(ads, (*info), msg);
     477           0 :                 gecos = ads_pull_string(ads, (*info), msg, "name");
     478           0 :                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
     479           0 :                         DEBUG(1,("No sid for %s !?\n", name));
     480           0 :                         continue;
     481             :                 }
     482             : 
     483           0 :                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
     484           0 :                         DEBUG(1,("No rid for %s !?\n", name));
     485           0 :                         continue;
     486             :                 }
     487             : 
     488           0 :                 (*info)[i].acct_name = name;
     489           0 :                 (*info)[i].acct_desc = gecos;
     490           0 :                 (*info)[i].rid = rid;
     491           0 :                 i++;
     492             :         }
     493             : 
     494           0 :         (*num_entries) = i;
     495             : 
     496           0 :         status = NT_STATUS_OK;
     497             : 
     498           0 :         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
     499             : 
     500           0 : done:
     501           0 :         if (res)
     502           0 :                 ads_msgfree(ads, res);
     503             : 
     504           0 :         return status;
     505             : }
     506             : 
     507             : /* list all domain local groups */
     508           0 : static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
     509             :                                 TALLOC_CTX *mem_ctx,
     510             :                                 uint32_t *num_entries,
     511             :                                 struct wb_acct_info **info)
     512             : {
     513             :         /*
     514             :          * This is a stub function only as we returned the domain
     515             :          * local groups in enum_dom_groups() if the domain->native field
     516             :          * was true.  This is a simple performance optimization when
     517             :          * using LDAP.
     518             :          *
     519             :          * if we ever need to enumerate domain local groups separately,
     520             :          * then this optimization in enum_dom_groups() will need
     521             :          * to be split out
     522             :          */
     523           0 :         *num_entries = 0;
     524             : 
     525           0 :         return NT_STATUS_OK;
     526             : }
     527             : 
     528             : /* convert a single name to a sid in a domain - use rpc methods */
     529           0 : static NTSTATUS name_to_sid(struct winbindd_domain *domain,
     530             :                             TALLOC_CTX *mem_ctx,
     531             :                             const char *domain_name,
     532             :                             const char *name,
     533             :                             uint32_t flags,
     534             :                             const char **pdom_name,
     535             :                             struct dom_sid *sid,
     536             :                             enum lsa_SidType *type)
     537             : {
     538           0 :         return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
     539             :                                          flags, pdom_name, sid, type);
     540             : }
     541             : 
     542             : /* convert a domain SID to a user or group name - use rpc methods */
     543           0 : static NTSTATUS sid_to_name(struct winbindd_domain *domain,
     544             :                             TALLOC_CTX *mem_ctx,
     545             :                             const struct dom_sid *sid,
     546             :                             char **domain_name,
     547             :                             char **name,
     548             :                             enum lsa_SidType *type)
     549             : {
     550           0 :         return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
     551             :                                          domain_name, name, type);
     552             : }
     553             : 
     554             : /* convert a list of rids to names - use rpc methods */
     555           0 : static NTSTATUS rids_to_names(struct winbindd_domain *domain,
     556             :                               TALLOC_CTX *mem_ctx,
     557             :                               const struct dom_sid *sid,
     558             :                               uint32_t *rids,
     559             :                               size_t num_rids,
     560             :                               char **domain_name,
     561             :                               char ***names,
     562             :                               enum lsa_SidType **types)
     563             : {
     564           0 :         return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
     565             :                                            rids, num_rids,
     566             :                                            domain_name, names, types);
     567             : }
     568             : 
     569             : /* Lookup groups a user is a member of - alternate method, for when
     570             :    tokenGroups are not available. */
     571           0 : static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
     572             :                                          TALLOC_CTX *mem_ctx,
     573             :                                          const char *user_dn,
     574             :                                          struct dom_sid *primary_group,
     575             :                                          uint32_t *p_num_groups, struct dom_sid **user_sids)
     576             : {
     577           0 :         ADS_STATUS rc;
     578           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     579           0 :         int count;
     580           0 :         LDAPMessage *res = NULL;
     581           0 :         LDAPMessage *msg = NULL;
     582           0 :         char *ldap_exp;
     583           0 :         ADS_STRUCT *ads = NULL;
     584           0 :         const char *group_attrs[] = {"objectSid", NULL};
     585           0 :         char *escaped_dn;
     586           0 :         uint32_t num_groups = 0;
     587             : 
     588           0 :         DEBUG(3,("ads: lookup_usergroups_member\n"));
     589             : 
     590           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     591           0 :                 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
     592             :                           domain->name));
     593           0 :                 return NT_STATUS_OK;
     594             :         }
     595             : 
     596           0 :         rc = ads_cached_connection(domain, &ads);
     597           0 :         if (!ADS_ERR_OK(rc)) {
     598           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
     599           0 :                 goto done;
     600             :         }
     601             : 
     602           0 :         if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
     603           0 :                 status = NT_STATUS_NO_MEMORY;
     604           0 :                 goto done;
     605             :         }
     606             : 
     607           0 :         ldap_exp = talloc_asprintf(mem_ctx,
     608             :                 "(&(member=%s)(objectCategory=group)"
     609             :                 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
     610             :                 escaped_dn,
     611             :                 GROUP_TYPE_SECURITY_ENABLED);
     612           0 :         if (!ldap_exp) {
     613           0 :                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
     614           0 :                 TALLOC_FREE(escaped_dn);
     615           0 :                 status = NT_STATUS_NO_MEMORY;
     616           0 :                 goto done;
     617             :         }
     618             : 
     619           0 :         TALLOC_FREE(escaped_dn);
     620             : 
     621           0 :         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
     622             : 
     623           0 :         if (!ADS_ERR_OK(rc)) {
     624           0 :                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
     625           0 :                 return ads_ntstatus(rc);
     626           0 :         } else if (!res) {
     627           0 :                 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
     628           0 :                 return NT_STATUS_INTERNAL_ERROR;
     629             :         }
     630             : 
     631             : 
     632           0 :         count = ads_count_replies(ads, res);
     633             : 
     634           0 :         *user_sids = NULL;
     635           0 :         num_groups = 0;
     636             : 
     637             :         /* always add the primary group to the sid array */
     638           0 :         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
     639             :                                   &num_groups);
     640           0 :         if (!NT_STATUS_IS_OK(status)) {
     641           0 :                 goto done;
     642             :         }
     643             : 
     644           0 :         if (count > 0) {
     645           0 :                 for (msg = ads_first_entry(ads, res); msg;
     646           0 :                      msg = ads_next_entry(ads, msg)) {
     647           0 :                         struct dom_sid group_sid;
     648             : 
     649           0 :                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
     650           0 :                                 DEBUG(1,("No sid for this group ?!?\n"));
     651           0 :                                 continue;
     652             :                         }
     653             : 
     654             :                         /* ignore Builtin groups from ADS - Guenther */
     655           0 :                         if (sid_check_is_in_builtin(&group_sid)) {
     656           0 :                                 continue;
     657             :                         }
     658             : 
     659           0 :                         status = add_sid_to_array(mem_ctx, &group_sid,
     660             :                                                   user_sids, &num_groups);
     661           0 :                         if (!NT_STATUS_IS_OK(status)) {
     662           0 :                                 goto done;
     663             :                         }
     664             :                 }
     665             : 
     666             :         }
     667             : 
     668           0 :         *p_num_groups = num_groups;
     669           0 :         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
     670             : 
     671           0 :         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
     672           0 : done:
     673           0 :         if (res)
     674           0 :                 ads_msgfree(ads, res);
     675             : 
     676           0 :         return status;
     677             : }
     678             : 
     679             : /* Lookup groups a user is a member of - alternate method, for when
     680             :    tokenGroups are not available. */
     681           0 : static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
     682             :                                            TALLOC_CTX *mem_ctx,
     683             :                                            const char *user_dn,
     684             :                                            struct dom_sid *primary_group,
     685             :                                            uint32_t *p_num_groups,
     686             :                                            struct dom_sid **user_sids)
     687             : {
     688           0 :         ADS_STATUS rc;
     689           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     690           0 :         ADS_STRUCT *ads = NULL;
     691           0 :         const char *attrs[] = {"memberOf", NULL};
     692           0 :         uint32_t num_groups = 0;
     693           0 :         struct dom_sid *group_sids = NULL;
     694           0 :         size_t i;
     695           0 :         char **strings = NULL;
     696           0 :         size_t num_strings = 0, num_sids = 0;
     697             : 
     698             : 
     699           0 :         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
     700             : 
     701           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     702           0 :                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
     703             :                           "domain %s\n", domain->name));
     704           0 :                 return NT_STATUS_OK;
     705             :         }
     706             : 
     707           0 :         rc = ads_cached_connection(domain, &ads);
     708           0 :         if (!ADS_ERR_OK(rc)) {
     709           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
     710           0 :                 return NT_STATUS_UNSUCCESSFUL;
     711             :         }
     712             : 
     713           0 :         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
     714             :                                                  ADS_EXTENDED_DN_HEX_STRING,
     715             :                                                  &strings, &num_strings);
     716             : 
     717           0 :         if (!ADS_ERR_OK(rc)) {
     718           0 :                 DEBUG(1,("lookup_usergroups_memberof ads_search "
     719             :                         "member=%s: %s\n", user_dn, ads_errstr(rc)));
     720           0 :                 return ads_ntstatus(rc);
     721             :         }
     722             : 
     723           0 :         *user_sids = NULL;
     724           0 :         num_groups = 0;
     725             : 
     726             :         /* always add the primary group to the sid array */
     727           0 :         status = add_sid_to_array(mem_ctx, primary_group, user_sids,
     728             :                                   &num_groups);
     729           0 :         if (!NT_STATUS_IS_OK(status)) {
     730           0 :                 goto done;
     731             :         }
     732             : 
     733           0 :         group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
     734           0 :         if (!group_sids) {
     735           0 :                 status = NT_STATUS_NO_MEMORY;
     736           0 :                 goto done;
     737             :         }
     738             : 
     739           0 :         for (i=0; i<num_strings; i++) {
     740           0 :                 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
     741             :                                                   ADS_EXTENDED_DN_HEX_STRING,
     742           0 :                                                   &(group_sids)[i]);
     743           0 :                 if (!ADS_ERR_OK(rc)) {
     744             :                         /* ignore members without SIDs */
     745           0 :                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
     746             :                             NT_STATUS_NOT_FOUND)) {
     747           0 :                                 continue;
     748             :                         }
     749             :                         else {
     750           0 :                                 status = ads_ntstatus(rc);
     751           0 :                                 goto done;
     752             :                         }
     753             :                 }
     754           0 :                 num_sids++;
     755             :         }
     756             : 
     757           0 :         if (i == 0) {
     758           0 :                 DEBUG(1,("No memberOf for this user?!?\n"));
     759           0 :                 status = NT_STATUS_NO_MEMORY;
     760           0 :                 goto done;
     761             :         }
     762             : 
     763           0 :         for (i=0; i<num_sids; i++) {
     764             : 
     765             :                 /* ignore Builtin groups from ADS - Guenther */
     766           0 :                 if (sid_check_is_in_builtin(&group_sids[i])) {
     767           0 :                         continue;
     768             :                 }
     769             : 
     770           0 :                 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
     771             :                                           &num_groups);
     772           0 :                 if (!NT_STATUS_IS_OK(status)) {
     773           0 :                         goto done;
     774             :                 }
     775             : 
     776             :         }
     777             : 
     778           0 :         *p_num_groups = num_groups;
     779           0 :         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
     780             : 
     781           0 :         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
     782             :                 user_dn));
     783             : 
     784           0 : done:
     785           0 :         TALLOC_FREE(strings);
     786           0 :         TALLOC_FREE(group_sids);
     787             : 
     788           0 :         return status;
     789             : }
     790             : 
     791             : 
     792             : /* Lookup groups a user is a member of. */
     793           0 : static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
     794             :                                   TALLOC_CTX *mem_ctx,
     795             :                                   const struct dom_sid *sid,
     796             :                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
     797             : {
     798           0 :         ADS_STRUCT *ads = NULL;
     799           0 :         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
     800           0 :         ADS_STATUS rc;
     801           0 :         int count;
     802           0 :         LDAPMessage *msg = NULL;
     803           0 :         char *user_dn = NULL;
     804           0 :         struct dom_sid *sids;
     805           0 :         int i;
     806           0 :         struct dom_sid primary_group;
     807           0 :         uint32_t primary_group_rid;
     808           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     809           0 :         uint32_t num_groups = 0;
     810           0 :         struct dom_sid_buf buf;
     811             : 
     812           0 :         DEBUG(3,("ads: lookup_usergroups\n"));
     813           0 :         *p_num_groups = 0;
     814             : 
     815           0 :         status = lookup_usergroups_cached(mem_ctx, sid,
     816             :                                           p_num_groups, user_sids);
     817           0 :         if (NT_STATUS_IS_OK(status)) {
     818           0 :                 return NT_STATUS_OK;
     819             :         }
     820             : 
     821           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     822           0 :                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
     823             :                           domain->name));
     824             : 
     825             :                 /* Tell the cache manager not to remember this one */
     826             : 
     827           0 :                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
     828             :         }
     829             : 
     830           0 :         rc = ads_cached_connection(domain, &ads);
     831           0 :         if (!ADS_ERR_OK(rc)) {
     832           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
     833           0 :                 status = NT_STATUS_SERVER_DISABLED;
     834           0 :                 goto done;
     835             :         }
     836             : 
     837           0 :         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
     838             : 
     839           0 :         if (!ADS_ERR_OK(rc)) {
     840           0 :                 status = ads_ntstatus(rc);
     841           0 :                 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
     842             :                           "%s\n",
     843             :                           dom_sid_str_buf(sid, &buf),
     844             :                           ads_errstr(rc)));
     845           0 :                 goto done;
     846             :         }
     847             : 
     848           0 :         count = ads_count_replies(ads, msg);
     849           0 :         if (count != 1) {
     850           0 :                 status = NT_STATUS_UNSUCCESSFUL;
     851           0 :                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
     852             :                          "invalid number of results (count=%d)\n",
     853             :                          dom_sid_str_buf(sid, &buf),
     854             :                          count));
     855           0 :                 goto done;
     856             :         }
     857             : 
     858           0 :         if (!msg) {
     859           0 :                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
     860             :                          dom_sid_str_buf(sid, &buf)));
     861           0 :                 status = NT_STATUS_UNSUCCESSFUL;
     862           0 :                 goto done;
     863             :         }
     864             : 
     865           0 :         user_dn = ads_get_dn(ads, mem_ctx, msg);
     866           0 :         if (user_dn == NULL) {
     867           0 :                 status = NT_STATUS_NO_MEMORY;
     868           0 :                 goto done;
     869             :         }
     870             : 
     871           0 :         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
     872           0 :                 DEBUG(1,("%s: No primary group for sid=%s !?\n",
     873             :                          domain->name,
     874             :                          dom_sid_str_buf(sid, &buf)));
     875           0 :                 goto done;
     876             :         }
     877             : 
     878           0 :         sid_compose(&primary_group, &domain->sid, primary_group_rid);
     879             : 
     880           0 :         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
     881             : 
     882             :         /* there must always be at least one group in the token,
     883             :            unless we are talking to a buggy Win2k server */
     884             : 
     885             :         /* actually this only happens when the machine account has no read
     886             :          * permissions on the tokenGroup attribute - gd */
     887             : 
     888           0 :         if (count == 0) {
     889             : 
     890             :                 /* no tokenGroups */
     891             : 
     892             :                 /* lookup what groups this user is a member of by DN search on
     893             :                  * "memberOf" */
     894             : 
     895           0 :                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
     896             :                                                     &primary_group,
     897             :                                                     &num_groups, user_sids);
     898           0 :                 *p_num_groups = num_groups;
     899           0 :                 if (NT_STATUS_IS_OK(status)) {
     900           0 :                         goto done;
     901             :                 }
     902             : 
     903             :                 /* lookup what groups this user is a member of by DN search on
     904             :                  * "member" */
     905             : 
     906           0 :                 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
     907             :                                                   &primary_group,
     908             :                                                   &num_groups, user_sids);
     909           0 :                 *p_num_groups = num_groups;
     910           0 :                 goto done;
     911             :         }
     912             : 
     913           0 :         *user_sids = NULL;
     914           0 :         num_groups = 0;
     915             : 
     916           0 :         status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
     917             :                                   &num_groups);
     918           0 :         if (!NT_STATUS_IS_OK(status)) {
     919           0 :                 goto done;
     920             :         }
     921             : 
     922           0 :         for (i=0;i<count;i++) {
     923             : 
     924             :                 /* ignore Builtin groups from ADS - Guenther */
     925           0 :                 if (sid_check_is_in_builtin(&sids[i])) {
     926           0 :                         continue;
     927             :                 }
     928             : 
     929           0 :                 status = add_sid_to_array_unique(mem_ctx, &sids[i],
     930             :                                                  user_sids, &num_groups);
     931           0 :                 if (!NT_STATUS_IS_OK(status)) {
     932           0 :                         goto done;
     933             :                 }
     934             :         }
     935             : 
     936           0 :         *p_num_groups = (uint32_t)num_groups;
     937           0 :         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
     938             : 
     939           0 :         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
     940             :                  dom_sid_str_buf(sid, &buf)));
     941           0 : done:
     942           0 :         TALLOC_FREE(user_dn);
     943           0 :         ads_msgfree(ads, msg);
     944           0 :         return status;
     945             : }
     946             : 
     947             : /* Lookup aliases a user is member of - use rpc methods */
     948           0 : static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
     949             :                                    TALLOC_CTX *mem_ctx,
     950             :                                    uint32_t num_sids, const struct dom_sid *sids,
     951             :                                    uint32_t *num_aliases, uint32_t **alias_rids)
     952             : {
     953           0 :         return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
     954             :                                                 num_aliases, alias_rids);
     955             : }
     956             : 
     957           0 : static NTSTATUS add_primary_group_members(
     958             :         ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
     959             :         char ***all_members, size_t *num_all_members)
     960             : {
     961           0 :         char *filter;
     962           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     963           0 :         ADS_STATUS rc;
     964           0 :         const char *attrs[] = { "dn", NULL };
     965           0 :         LDAPMessage *res = NULL;
     966           0 :         LDAPMessage *msg;
     967           0 :         char **members;
     968           0 :         size_t num_members;
     969           0 :         ads_control args;
     970           0 :         bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
     971             : 
     972           0 :         filter = talloc_asprintf(
     973             :                 mem_ctx,
     974             :                 "(&(objectCategory=user)(primaryGroupID=%u)%s)",
     975             :                 (unsigned)rid,
     976             :                 all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
     977           0 :         if (filter == NULL) {
     978           0 :                 goto done;
     979             :         }
     980             : 
     981           0 :         args.control = ADS_EXTENDED_DN_OID;
     982           0 :         args.val = ADS_EXTENDED_DN_HEX_STRING;
     983           0 :         args.critical = True;
     984             : 
     985           0 :         rc = ads_do_search_all_args(ads, ads->config.bind_path,
     986             :                                     LDAP_SCOPE_SUBTREE, filter, attrs, &args,
     987             :                                     &res);
     988             : 
     989           0 :         if (!ADS_ERR_OK(rc)) {
     990           0 :                 status = ads_ntstatus(rc);
     991           0 :                 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
     992           0 :                 goto done;
     993             :         }
     994           0 :         if (res == NULL) {
     995           0 :                 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
     996           0 :                 goto done;
     997             :         }
     998             : 
     999           0 :         num_members = ads_count_replies(ads, res);
    1000             : 
    1001           0 :         DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
    1002             :                    (uintmax_t)num_members));
    1003             : 
    1004           0 :         if (num_members == 0) {
    1005           0 :                 status = NT_STATUS_OK;
    1006           0 :                 goto done;
    1007             :         }
    1008             : 
    1009           0 :         members = talloc_realloc(mem_ctx, *all_members, char *,
    1010             :                                  *num_all_members + num_members);
    1011           0 :         if (members == NULL) {
    1012           0 :                 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
    1013           0 :                 goto done;
    1014             :         }
    1015           0 :         *all_members = members;
    1016             : 
    1017           0 :         for (msg = ads_first_entry(ads, res); msg != NULL;
    1018           0 :              msg = ads_next_entry(ads, msg)) {
    1019           0 :                 char *dn;
    1020             : 
    1021           0 :                 dn = ads_get_dn(ads, members, msg);
    1022           0 :                 if (dn == NULL) {
    1023           0 :                         DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
    1024           0 :                         continue;
    1025             :                 }
    1026             : 
    1027           0 :                 members[*num_all_members] = dn;
    1028           0 :                 *num_all_members += 1;
    1029             :         }
    1030             : 
    1031           0 :         status = NT_STATUS_OK;
    1032           0 : done:
    1033           0 :         if (res != NULL) {
    1034           0 :                 ads_msgfree(ads, res);
    1035             :         }
    1036           0 :         TALLOC_FREE(filter);
    1037           0 :         return status;
    1038             : }
    1039             : 
    1040             : /*
    1041             :   find the members of a group, given a group rid and domain
    1042             :  */
    1043           0 : static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
    1044             :                                 TALLOC_CTX *mem_ctx,
    1045             :                                 const struct dom_sid *group_sid,
    1046             :                                 enum lsa_SidType type,
    1047             :                                 uint32_t *num_names,
    1048             :                                 struct dom_sid **sid_mem, char ***names,
    1049             :                                 uint32_t **name_types)
    1050             : {
    1051           0 :         ADS_STATUS rc;
    1052           0 :         ADS_STRUCT *ads = NULL;
    1053           0 :         char *ldap_exp;
    1054           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
    1055           0 :         char *sidbinstr;
    1056           0 :         char **members = NULL;
    1057           0 :         size_t i;
    1058           0 :         size_t num_members = 0;
    1059           0 :         ads_control args;
    1060           0 :         struct dom_sid *sid_mem_nocache = NULL;
    1061           0 :         char **names_nocache = NULL;
    1062           0 :         enum lsa_SidType *name_types_nocache = NULL;
    1063           0 :         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
    1064           0 :         uint32_t num_nocache = 0;
    1065           0 :         TALLOC_CTX *tmp_ctx = NULL;
    1066           0 :         uint32_t rid;
    1067           0 :         struct dom_sid_buf buf;
    1068             : 
    1069           0 :         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
    1070             :                   dom_sid_str_buf(group_sid, &buf)));
    1071             : 
    1072           0 :         *num_names = 0;
    1073             : 
    1074           0 :         tmp_ctx = talloc_new(mem_ctx);
    1075           0 :         if (!tmp_ctx) {
    1076           0 :                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
    1077           0 :                 status = NT_STATUS_NO_MEMORY;
    1078           0 :                 goto done;
    1079             :         }
    1080             : 
    1081           0 :         if (!sid_peek_rid(group_sid, &rid)) {
    1082           0 :                 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
    1083           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1084           0 :                 goto done;
    1085             :         }
    1086             : 
    1087           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
    1088           0 :                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
    1089             :                           domain->name));
    1090           0 :                 return NT_STATUS_OK;
    1091             :         }
    1092             : 
    1093           0 :         rc = ads_cached_connection(domain, &ads);
    1094           0 :         if (!ADS_ERR_OK(rc)) {
    1095           0 :                 domain->last_status = NT_STATUS_SERVER_DISABLED;
    1096           0 :                 goto done;
    1097             :         }
    1098             : 
    1099           0 :         if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
    1100           0 :                 status = NT_STATUS_NO_MEMORY;
    1101           0 :                 goto done;
    1102             :         }
    1103             : 
    1104             :         /* search for all members of the group */
    1105           0 :         ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
    1106           0 :         TALLOC_FREE(sidbinstr);
    1107           0 :         if (ldap_exp == NULL) {
    1108           0 :                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
    1109           0 :                 status = NT_STATUS_NO_MEMORY;
    1110           0 :                 goto done;
    1111             :         }
    1112             : 
    1113           0 :         args.control = ADS_EXTENDED_DN_OID;
    1114           0 :         args.val = ADS_EXTENDED_DN_HEX_STRING;
    1115           0 :         args.critical = True;
    1116             : 
    1117           0 :         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
    1118             :                                ldap_exp, &args, "member", &members, &num_members);
    1119             : 
    1120           0 :         if (!ADS_ERR_OK(rc)) {
    1121           0 :                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
    1122           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1123           0 :                 goto done;
    1124             :         }
    1125             : 
    1126           0 :         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
    1127             : 
    1128           0 :         status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
    1129             :                                            &members, &num_members);
    1130           0 :         if (!NT_STATUS_IS_OK(status)) {
    1131           0 :                 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
    1132             :                            __func__, nt_errstr(status)));
    1133           0 :                 goto done;
    1134             :         }
    1135             : 
    1136           0 :         DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
    1137             :                    __func__, (int)num_members));
    1138             : 
    1139             :         /* Now that we have a list of sids, we need to get the
    1140             :          * lists of names and name_types belonging to these sids.
    1141             :          * even though conceptually not quite clean,  we use the
    1142             :          * RPC call lsa_lookup_sids for this since it can handle a
    1143             :          * list of sids. ldap calls can just resolve one sid at a time.
    1144             :          *
    1145             :          * At this stage, the sids are still hidden in the exetended dn
    1146             :          * member output format. We actually do a little better than
    1147             :          * stated above: In extracting the sids from the member strings,
    1148             :          * we try to resolve as many sids as possible from the
    1149             :          * cache. Only the rest is passed to the lsa_lookup_sids call. */
    1150             : 
    1151           0 :         if (num_members) {
    1152           0 :                 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
    1153           0 :                 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
    1154           0 :                 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
    1155           0 :                 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
    1156             : 
    1157           0 :                 if ((members == NULL) || (*sid_mem == NULL) ||
    1158           0 :                     (*names == NULL) || (*name_types == NULL) ||
    1159             :                     (sid_mem_nocache == NULL))
    1160             :                 {
    1161           0 :                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
    1162           0 :                         status = NT_STATUS_NO_MEMORY;
    1163           0 :                         goto done;
    1164             :                 }
    1165             :         }
    1166             :         else {
    1167           0 :                 (*sid_mem) = NULL;
    1168           0 :                 (*names) = NULL;
    1169           0 :                 (*name_types) = NULL;
    1170             :         }
    1171             : 
    1172           0 :         for (i=0; i<num_members; i++) {
    1173           0 :                 enum lsa_SidType name_type;
    1174           0 :                 char *name, *domain_name;
    1175           0 :                 struct dom_sid sid;
    1176             : 
    1177           0 :                 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
    1178             :                     &sid);
    1179           0 :                 if (!ADS_ERR_OK(rc)) {
    1180           0 :                         if (NT_STATUS_EQUAL(ads_ntstatus(rc),
    1181             :                             NT_STATUS_NOT_FOUND)) {
    1182             :                                 /* Group members can be objects, like Exchange
    1183             :                                  * Public Folders, that don't have a SID.  Skip
    1184             :                                  * them. */
    1185           0 :                                 continue;
    1186             :                         }
    1187             :                         else {
    1188           0 :                                 status = ads_ntstatus(rc);
    1189           0 :                                 goto done;
    1190             :                         }
    1191             :                 }
    1192           0 :                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
    1193             :                     &name_type)) {
    1194           0 :                         DEBUG(10,("ads: lookup_groupmem: got sid %s from "
    1195             :                                   "cache\n",
    1196             :                                   dom_sid_str_buf(&sid, &buf)));
    1197           0 :                         sid_copy(&(*sid_mem)[*num_names], &sid);
    1198           0 :                         (*names)[*num_names] = fill_domain_username_talloc(
    1199             :                                                         *names,
    1200             :                                                         domain_name,
    1201             :                                                         name,
    1202             :                                                         true);
    1203             : 
    1204           0 :                         (*name_types)[*num_names] = name_type;
    1205           0 :                         (*num_names)++;
    1206             :                 }
    1207             :                 else {
    1208           0 :                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
    1209             :                                    "cache\n",
    1210             :                                    dom_sid_str_buf(&sid, &buf)));
    1211           0 :                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
    1212           0 :                         num_nocache++;
    1213             :                 }
    1214             :         }
    1215             : 
    1216           0 :         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
    1217             :                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
    1218             : 
    1219             :         /* handle sids not resolved from cache by lsa_lookup_sids */
    1220           0 :         if (num_nocache > 0) {
    1221             : 
    1222           0 :                 status = winbindd_lookup_sids(tmp_ctx,
    1223             :                                               domain,
    1224             :                                               num_nocache,
    1225             :                                               sid_mem_nocache,
    1226             :                                               &domains_nocache,
    1227             :                                               &names_nocache,
    1228             :                                               &name_types_nocache);
    1229             : 
    1230           0 :                 if (!(NT_STATUS_IS_OK(status) ||
    1231           0 :                       NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
    1232           0 :                       NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
    1233             :                 {
    1234           0 :                         DEBUG(1, ("lsa_lookupsids call failed with %s "
    1235             :                                   "- retrying...\n", nt_errstr(status)));
    1236             : 
    1237           0 :                         status = winbindd_lookup_sids(tmp_ctx,
    1238             :                                                       domain,
    1239             :                                                       num_nocache,
    1240             :                                                       sid_mem_nocache,
    1241             :                                                       &domains_nocache,
    1242             :                                                       &names_nocache,
    1243             :                                                       &name_types_nocache);
    1244             :                 }
    1245             : 
    1246           0 :                 if (NT_STATUS_IS_OK(status) ||
    1247           0 :                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
    1248             :                 {
    1249             :                         /* Copy the entries over from the "_nocache" arrays
    1250             :                          * to the result arrays, skipping the gaps the
    1251             :                          * lookup_sids call left. */
    1252           0 :                         for (i=0; i < num_nocache; i++) {
    1253           0 :                                 if (((names_nocache)[i] != NULL) &&
    1254           0 :                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
    1255             :                                 {
    1256           0 :                                         sid_copy(&(*sid_mem)[*num_names],
    1257           0 :                                                  &sid_mem_nocache[i]);
    1258           0 :                                         (*names)[*num_names] =
    1259           0 :                                                 fill_domain_username_talloc(
    1260             :                                                         *names,
    1261           0 :                                                         domains_nocache[i],
    1262           0 :                                                         names_nocache[i],
    1263             :                                                         true);
    1264           0 :                                         (*name_types)[*num_names] = name_types_nocache[i];
    1265           0 :                                         (*num_names)++;
    1266             :                                 }
    1267             :                         }
    1268             :                 }
    1269           0 :                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
    1270           0 :                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
    1271             :                                    "not map any SIDs at all.\n"));
    1272             :                         /* Don't handle this as an error here.
    1273             :                          * There is nothing left to do with respect to the
    1274             :                          * overall result... */
    1275             :                 }
    1276           0 :                 else if (!NT_STATUS_IS_OK(status)) {
    1277           0 :                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
    1278             :                                    "sids via rpc_lsa_lookup_sids: %s\n",
    1279             :                                    (int)num_members, nt_errstr(status)));
    1280           0 :                         goto done;
    1281             :                 }
    1282             :         }
    1283             : 
    1284           0 :         status = NT_STATUS_OK;
    1285           0 :         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
    1286             :                  dom_sid_str_buf(group_sid, &buf)));
    1287             : 
    1288           0 : done:
    1289             : 
    1290           0 :         TALLOC_FREE(tmp_ctx);
    1291             : 
    1292           0 :         return status;
    1293             : }
    1294             : 
    1295           0 : static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
    1296             :                                 TALLOC_CTX *mem_ctx,
    1297             :                                 const struct dom_sid *sid,
    1298             :                                 enum lsa_SidType type,
    1299             :                                 uint32_t *num_sids,
    1300             :                                 struct dom_sid **sids)
    1301             : {
    1302           0 :         char **names = NULL;
    1303           0 :         uint32_t *name_types = NULL;
    1304           0 :         struct dom_sid_buf buf;
    1305             : 
    1306           0 :         DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
    1307             :                   domain->name,
    1308             :                   dom_sid_str_buf(sid, &buf));
    1309             :         /* Search for alias and group membership uses the same LDAP command. */
    1310           0 :         return lookup_groupmem(domain,
    1311             :                                mem_ctx,
    1312             :                                sid,
    1313             :                                type,
    1314             :                                num_sids,
    1315             :                                sids,
    1316             :                                &names,
    1317             :                                &name_types);
    1318             : }
    1319             : 
    1320             : /* find the lockout policy of a domain - use rpc methods */
    1321           0 : static NTSTATUS lockout_policy(struct winbindd_domain *domain,
    1322             :                                TALLOC_CTX *mem_ctx,
    1323             :                                struct samr_DomInfo12 *policy)
    1324             : {
    1325           0 :         return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
    1326             : }
    1327             : 
    1328             : /* find the password policy of a domain - use rpc methods */
    1329           0 : static NTSTATUS password_policy(struct winbindd_domain *domain,
    1330             :                                 TALLOC_CTX *mem_ctx,
    1331             :                                 struct samr_DomInfo1 *policy)
    1332             : {
    1333           0 :         return msrpc_methods.password_policy(domain, mem_ctx, policy);
    1334             : }
    1335             : 
    1336             : /* get a list of trusted domains */
    1337           0 : static NTSTATUS trusted_domains(struct winbindd_domain *domain,
    1338             :                                 TALLOC_CTX *mem_ctx,
    1339             :                                 struct netr_DomainTrustList *trusts)
    1340             : {
    1341           0 :         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
    1342           0 :         WERROR werr;
    1343           0 :         uint32_t                i;
    1344           0 :         uint32_t                flags;
    1345           0 :         struct rpc_pipe_client *cli;
    1346           0 :         struct dcerpc_binding_handle *b;
    1347             : 
    1348           0 :         DEBUG(3,("ads: trusted_domains\n"));
    1349             : 
    1350           0 :         ZERO_STRUCTP(trusts);
    1351             : 
    1352             :         /* If this is our primary domain or a root in our forest,
    1353             :            query for all trusts.  If not, then just look for domain
    1354             :            trusts in the target forest */
    1355             : 
    1356           0 :         if (domain->primary || domain_is_forest_root(domain)) {
    1357           0 :                 flags = NETR_TRUST_FLAG_OUTBOUND |
    1358             :                         NETR_TRUST_FLAG_INBOUND |
    1359             :                         NETR_TRUST_FLAG_IN_FOREST;
    1360             :         } else {
    1361           0 :                 flags = NETR_TRUST_FLAG_IN_FOREST;
    1362             :         }
    1363             : 
    1364           0 :         result = cm_connect_netlogon(domain, &cli);
    1365             : 
    1366           0 :         if (!NT_STATUS_IS_OK(result)) {
    1367           0 :                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
    1368             :                           "for PIPE_NETLOGON (%s)\n",
    1369             :                           domain->name, nt_errstr(result)));
    1370           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1371             :         }
    1372             : 
    1373           0 :         b = cli->binding_handle;
    1374             : 
    1375           0 :         result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
    1376           0 :                                                       cli->desthost,
    1377             :                                                       flags,
    1378             :                                                       trusts,
    1379             :                                                       &werr);
    1380           0 :         if (!NT_STATUS_IS_OK(result)) {
    1381           0 :                 return result;
    1382             :         }
    1383             : 
    1384           0 :         if (!W_ERROR_IS_OK(werr)) {
    1385           0 :                 return werror_to_ntstatus(werr);
    1386             :         }
    1387           0 :         if (trusts->count == 0) {
    1388           0 :                 return NT_STATUS_OK;
    1389             :         }
    1390             : 
    1391             :         /* Copy across names and sids */
    1392             : 
    1393           0 :         for (i = 0; i < trusts->count; i++) {
    1394           0 :                 struct netr_DomainTrust *trust = &trusts->array[i];
    1395           0 :                 struct winbindd_domain d;
    1396             : 
    1397           0 :                 ZERO_STRUCT(d);
    1398             : 
    1399             :                 /*
    1400             :                  * drop external trusts if this is not our primary
    1401             :                  * domain.  This means that the returned number of
    1402             :                  * domains may be less that the ones actually trusted
    1403             :                  * by the DC.
    1404             :                  */
    1405             : 
    1406           0 :                 if ((trust->trust_attributes
    1407           0 :                      & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
    1408           0 :                     !domain->primary )
    1409             :                 {
    1410           0 :                         DEBUG(10,("trusted_domains: Skipping external trusted "
    1411             :                                   "domain %s because it is outside of our "
    1412             :                                   "primary domain\n",
    1413             :                                   trust->netbios_name));
    1414           0 :                         continue;
    1415             :                 }
    1416             : 
    1417             :                 /* add to the trusted domain cache */
    1418             : 
    1419           0 :                 d.name = discard_const_p(char, trust->netbios_name);
    1420           0 :                 d.alt_name = discard_const_p(char, trust->dns_name);
    1421             : 
    1422           0 :                 if (trust->sid) {
    1423           0 :                         sid_copy(&d.sid, trust->sid);
    1424             :                 } else {
    1425           0 :                         sid_copy(&d.sid, &global_sid_NULL);
    1426             :                 }
    1427             : 
    1428           0 :                 if ( domain->primary ) {
    1429           0 :                         DEBUG(10,("trusted_domains(ads):  Searching "
    1430             :                                   "trusted domain list of %s and storing "
    1431             :                                   "trust flags for domain %s\n",
    1432             :                                   domain->name, d.alt_name));
    1433             : 
    1434           0 :                         d.domain_flags = trust->trust_flags;
    1435           0 :                         d.domain_type = trust->trust_type;
    1436           0 :                         d.domain_trust_attribs = trust->trust_attributes;
    1437             : 
    1438           0 :                         wcache_tdc_add_domain( &d );
    1439           0 :                 } else if (domain_is_forest_root(domain)) {
    1440             :                         /* Check if we already have this record. If
    1441             :                          * we are following our forest root that is not
    1442             :                          * our primary domain, we want to keep trust
    1443             :                          * flags from the perspective of our primary
    1444             :                          * domain not our forest root. */
    1445           0 :                         struct winbindd_tdc_domain *exist = NULL;
    1446             : 
    1447           0 :                         exist = wcache_tdc_fetch_domain(
    1448             :                                 talloc_tos(), trust->netbios_name);
    1449           0 :                         if (!exist) {
    1450           0 :                                 DEBUG(10,("trusted_domains(ads):  Searching "
    1451             :                                           "trusted domain list of %s and "
    1452             :                                           "storing trust flags for domain "
    1453             :                                           "%s\n", domain->name, d.alt_name));
    1454           0 :                                 d.domain_flags = trust->trust_flags;
    1455           0 :                                 d.domain_type = trust->trust_type;
    1456           0 :                                 d.domain_trust_attribs =
    1457           0 :                                         trust->trust_attributes;
    1458             : 
    1459           0 :                                 wcache_tdc_add_domain( &d );
    1460             :                         }
    1461           0 :                         TALLOC_FREE(exist);
    1462             :                 } else {
    1463             :                         /* This gets a little tricky.  If we are
    1464             :                            following a transitive forest trust, then
    1465             :                            innerit the flags, type, and attribs from
    1466             :                            the domain we queried to make sure we don't
    1467             :                            record the view of the trust from the wrong
    1468             :                            side.  Always view it from the side of our
    1469             :                            primary domain.   --jerry */
    1470           0 :                         struct winbindd_tdc_domain *parent = NULL;
    1471             : 
    1472           0 :                         DEBUG(10,("trusted_domains(ads):  Searching "
    1473             :                                   "trusted domain list of %s and inheriting "
    1474             :                                   "trust flags for domain %s\n",
    1475             :                                   domain->name, d.alt_name));
    1476             : 
    1477           0 :                         parent = wcache_tdc_fetch_domain(talloc_tos(),
    1478           0 :                                                          domain->name);
    1479           0 :                         if (parent) {
    1480           0 :                                 d.domain_flags = parent->trust_flags;
    1481           0 :                                 d.domain_type  = parent->trust_type;
    1482           0 :                                 d.domain_trust_attribs = parent->trust_attribs;
    1483             :                         } else {
    1484           0 :                                 d.domain_flags = domain->domain_flags;
    1485           0 :                                 d.domain_type  = domain->domain_type;
    1486           0 :                                 d.domain_trust_attribs =
    1487           0 :                                         domain->domain_trust_attribs;
    1488             :                         }
    1489           0 :                         TALLOC_FREE(parent);
    1490             : 
    1491             :                         /*
    1492             :                          * We need to pass the modified properties
    1493             :                          * to the caller.
    1494             :                          */
    1495           0 :                         trust->trust_flags = d.domain_flags;
    1496           0 :                         trust->trust_type = d.domain_type;
    1497           0 :                         trust->trust_attributes = d.domain_trust_attribs;
    1498             : 
    1499           0 :                         wcache_tdc_add_domain( &d );
    1500             :                 }
    1501             :         }
    1502           0 :         return result;
    1503             : }
    1504             : 
    1505             : /* the ADS backend methods are exposed via this structure */
    1506             : struct winbindd_methods ads_methods = {
    1507             :         True,
    1508             :         query_user_list,
    1509             :         enum_dom_groups,
    1510             :         enum_local_groups,
    1511             :         name_to_sid,
    1512             :         sid_to_name,
    1513             :         rids_to_names,
    1514             :         lookup_usergroups,
    1515             :         lookup_useraliases,
    1516             :         lookup_groupmem,
    1517             :         lookup_aliasmem,
    1518             :         lockout_policy,
    1519             :         password_policy,
    1520             :         trusted_domains,
    1521             : };
    1522             : 
    1523             : #endif

Generated by: LCOV version 1.14