nsswitch/winbindd_ads.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind ADS backend functions
00005 
00006    Copyright (C) Andrew Tridgell 2001
00007    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
00008    Copyright (C) Gerald (Jerry) Carter 2004
00009    
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014    
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019    
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023 */
00024 
00025 #include "includes.h"
00026 #include "winbindd.h"
00027 
00028 #ifdef HAVE_ADS
00029 
00030 #undef DBGC_CLASS
00031 #define DBGC_CLASS DBGC_WINBIND
00032 
00033 extern struct winbindd_methods reconnect_methods;
00034 
00035 /*
00036   return our ads connections structure for a domain. We keep the connection
00037   open to make things faster
00038 */
00039 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
00040 {
00041         ADS_STRUCT *ads;
00042         ADS_STATUS status;
00043         fstring dc_name;
00044         struct in_addr dc_ip;   
00045 
00046         DEBUG(10,("ads_cached_connection\n"));
00047 
00048         if (domain->private_data) {
00049 
00050                 time_t expire;
00051                 time_t now = time(NULL);
00052 
00053                 /* check for a valid structure */
00054                 ads = (ADS_STRUCT *)domain->private_data;
00055 
00056                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
00057 
00058                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
00059                           (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
00060 
00061                 if ( ads->config.realm && (expire > now)) {
00062                         return ads;
00063                 } else {
00064                         /* we own this ADS_STRUCT so make sure it goes away */
00065                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
00066                         ads->is_mine = True;
00067                         ads_destroy( &ads );
00068                         ads_kdestroy("MEMORY:winbind_ccache");
00069                         domain->private_data = NULL;
00070                 }       
00071         }
00072 
00073         /* we don't want this to affect the users ccache */
00074         setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
00075 
00076         ads = ads_init(domain->alt_name, domain->name, NULL);
00077         if (!ads) {
00078                 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
00079                 return NULL;
00080         }
00081 
00082         /* the machine acct password might have change - fetch it every time */
00083 
00084         SAFE_FREE(ads->auth.password);
00085         SAFE_FREE(ads->auth.realm);
00086 
00087         if ( IS_DC ) {
00088                 DOM_SID sid;
00089                 time_t last_set_time;
00090 
00091                 if ( !secrets_fetch_trusted_domain_password( domain->name, &ads->auth.password, &sid, &last_set_time ) ) {
00092                         ads_destroy( &ads );
00093                         return NULL;
00094                 }
00095                 ads->auth.realm = SMB_STRDUP( ads->server.realm );
00096                 strupper_m( ads->auth.realm );
00097         }
00098         else {
00099                 struct winbindd_domain *our_domain = domain;
00100 
00101                 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
00102 
00103                 /* always give preference to the alt_name in our 
00104                    primary domain if possible */
00105 
00106                 if ( !domain->primary )
00107                         our_domain = find_our_domain();
00108 
00109                 if ( our_domain->alt_name[0] != '\0' ) {
00110                         ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
00111                         strupper_m( ads->auth.realm );
00112                 }
00113                 else
00114                         ads->auth.realm = SMB_STRDUP( lp_realm() );
00115         }
00116 
00117         ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
00118 
00119         /* Setup the server affinity cache.  We don't reaally care
00120            about the name.  Just setup affinity and the KRB5_CONFIG 
00121            file. */
00122 
00123         get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ip );
00124         
00125         status = ads_connect(ads);
00126         if (!ADS_ERR_OK(status) || !ads->config.realm) {
00127                 DEBUG(1,("ads_connect for domain %s failed: %s\n", 
00128                          domain->name, ads_errstr(status)));
00129                 ads_destroy(&ads);
00130 
00131                 /* if we get ECONNREFUSED then it might be a NT4
00132                    server, fall back to MSRPC */
00133                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
00134                     status.err.rc == ECONNREFUSED) {
00135                         /* 'reconnect_methods' is the MS-RPC backend. */
00136                         DEBUG(1,("Trying MSRPC methods\n"));
00137                         domain->backend = &reconnect_methods;
00138                 }
00139                 return NULL;
00140         }
00141 
00142         /* set the flag that says we don't own the memory even 
00143            though we do so that ads_destroy() won't destroy the 
00144            structure we pass back by reference */
00145 
00146         ads->is_mine = False;
00147 
00148         domain->private_data = (void *)ads;
00149         return ads;
00150 }
00151 
00152 
00153 /* Query display info for a realm. This is the basic user list fn */
00154 static NTSTATUS query_user_list(struct winbindd_domain *domain,
00155                                TALLOC_CTX *mem_ctx,
00156                                uint32 *num_entries, 
00157                                WINBIND_USERINFO **info)
00158 {
00159         ADS_STRUCT *ads = NULL;
00160         const char *attrs[] = { "*", NULL };
00161         int i, count;
00162         ADS_STATUS rc;
00163         LDAPMessage *res = NULL;
00164         LDAPMessage *msg = NULL;
00165         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00166 
00167         *num_entries = 0;
00168 
00169         DEBUG(3,("ads: query_user_list\n"));
00170 
00171         ads = ads_cached_connection(domain);
00172         
00173         if (!ads) {
00174                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00175                 goto done;
00176         }
00177 
00178         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
00179         if (!ADS_ERR_OK(rc) || !res) {
00180                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
00181                 goto done;
00182         }
00183 
00184         count = ads_count_replies(ads, res);
00185         if (count == 0) {
00186                 DEBUG(1,("query_user_list: No users found\n"));
00187                 goto done;
00188         }
00189 
00190         (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count);
00191         if (!*info) {
00192                 status = NT_STATUS_NO_MEMORY;
00193                 goto done;
00194         }
00195 
00196         i = 0;
00197 
00198         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
00199                 char *name, *gecos = NULL;
00200                 char *homedir = NULL;
00201                 char *shell = NULL;
00202                 uint32 group;
00203                 uint32 atype;
00204                 DOM_SID user_sid;
00205                 gid_t primary_gid = (gid_t)-1;
00206 
00207                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
00208                     ads_atype_map(atype) != SID_NAME_USER) {
00209                         DEBUG(1,("Not a user account? atype=0x%x\n", atype));
00210                         continue;
00211                 }
00212 
00213                 name = ads_pull_username(ads, mem_ctx, msg);
00214 
00215                 if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
00216                         status = nss_get_info( domain->name, &user_sid, mem_ctx, 
00217                                                ads, msg, &homedir, &shell, &gecos,
00218                                                &primary_gid );
00219                 }
00220 
00221                 if (gecos == NULL) {
00222                         gecos = ads_pull_string(ads, mem_ctx, msg, "name");
00223                 }
00224         
00225                 if (!ads_pull_sid(ads, msg, "objectSid",
00226                                   &(*info)[i].user_sid)) {
00227                         DEBUG(1,("No sid for %s !?\n", name));
00228                         continue;
00229                 }
00230                 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
00231                         DEBUG(1,("No primary group for %s !?\n", name));
00232                         continue;
00233                 }
00234 
00235                 (*info)[i].acct_name = name;
00236                 (*info)[i].full_name = gecos;
00237                 (*info)[i].homedir = homedir;
00238                 (*info)[i].shell = shell;
00239                 (*info)[i].primary_gid = primary_gid;
00240                 sid_compose(&(*info)[i].group_sid, &domain->sid, group);
00241                 i++;
00242         }
00243 
00244         (*num_entries) = i;
00245         status = NT_STATUS_OK;
00246 
00247         DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
00248 
00249 done:
00250         if (res) 
00251                 ads_msgfree(ads, res);
00252 
00253         return status;
00254 }
00255 
00256 /* list all domain groups */
00257 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
00258                                 TALLOC_CTX *mem_ctx,
00259                                 uint32 *num_entries, 
00260                                 struct acct_info **info)
00261 {
00262         ADS_STRUCT *ads = NULL;
00263         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
00264                                "name", "objectSid", NULL};
00265         int i, count;
00266         ADS_STATUS rc;
00267         LDAPMessage *res = NULL;
00268         LDAPMessage *msg = NULL;
00269         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00270         const char *filter;
00271         BOOL enum_dom_local_groups = False;
00272 
00273         *num_entries = 0;
00274 
00275         DEBUG(3,("ads: enum_dom_groups\n"));
00276 
00277         /* only grab domain local groups for our domain */
00278         if ( domain->native_mode && strequal(lp_realm(), domain->alt_name)  ) {
00279                 enum_dom_local_groups = True;
00280         }
00281 
00282         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
00283          * rollup-fixes:
00284          *
00285          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
00286          * default value, it MUST be absent. In case of extensible matching the
00287          * "dnattr" boolean defaults to FALSE and so it must be only be present
00288          * when set to TRUE. 
00289          *
00290          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
00291          * filter using bitwise matching rule then the buggy AD fails to decode
00292          * the extensible match. As a workaround set it to TRUE and thereby add
00293          * the dnAttributes "dn" field to cope with those older AD versions.
00294          * It should not harm and won't put any additional load on the AD since
00295          * none of the dn components have a bitmask-attribute.
00296          *
00297          * Thanks to Ralf Haferkamp for input and testing - Guenther */
00298 
00299         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
00300                                  ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
00301                                  ADS_LDAP_MATCHING_RULE_BIT_AND, 
00302                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
00303 
00304         if (filter == NULL) {
00305                 status = NT_STATUS_NO_MEMORY;
00306                 goto done;
00307         }
00308 
00309         ads = ads_cached_connection(domain);
00310 
00311         if (!ads) {
00312                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00313                 goto done;
00314         }
00315 
00316         rc = ads_search_retry(ads, &res, filter, attrs);
00317         if (!ADS_ERR_OK(rc) || !res) {
00318                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
00319                 goto done;
00320         }
00321 
00322         count = ads_count_replies(ads, res);
00323         if (count == 0) {
00324                 DEBUG(1,("enum_dom_groups: No groups found\n"));
00325                 goto done;
00326         }
00327 
00328         (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
00329         if (!*info) {
00330                 status = NT_STATUS_NO_MEMORY;
00331                 goto done;
00332         }
00333 
00334         i = 0;
00335         
00336         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
00337                 char *name, *gecos;
00338                 DOM_SID sid;
00339                 uint32 rid;
00340 
00341                 name = ads_pull_username(ads, mem_ctx, msg);
00342                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
00343                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
00344                         DEBUG(1,("No sid for %s !?\n", name));
00345                         continue;
00346                 }
00347 
00348                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
00349                         DEBUG(1,("No rid for %s !?\n", name));
00350                         continue;
00351                 }
00352 
00353                 fstrcpy((*info)[i].acct_name, name);
00354                 fstrcpy((*info)[i].acct_desc, gecos);
00355                 (*info)[i].rid = rid;
00356                 i++;
00357         }
00358 
00359         (*num_entries) = i;
00360 
00361         status = NT_STATUS_OK;
00362 
00363         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
00364 
00365 done:
00366         if (res) 
00367                 ads_msgfree(ads, res);
00368 
00369         return status;
00370 }
00371 
00372 /* list all domain local groups */
00373 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
00374                                 TALLOC_CTX *mem_ctx,
00375                                 uint32 *num_entries, 
00376                                 struct acct_info **info)
00377 {
00378         /*
00379          * This is a stub function only as we returned the domain 
00380          * local groups in enum_dom_groups() if the domain->native field
00381          * was true.  This is a simple performance optimization when
00382          * using LDAP.
00383          *
00384          * if we ever need to enumerate domain local groups separately, 
00385          * then this the optimization in enum_dom_groups() will need 
00386          * to be split out
00387          */
00388         *num_entries = 0;
00389         
00390         return NT_STATUS_OK;
00391 }
00392 
00393 /* convert a DN to a name, SID and name type 
00394    this might become a major speed bottleneck if groups have
00395    lots of users, in which case we could cache the results
00396 */
00397 static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
00398                       const char *dn,
00399                       char **name, uint32 *name_type, DOM_SID *sid)
00400 {
00401         LDAPMessage *res = NULL;
00402         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
00403                                "objectSid", "sAMAccountType", NULL};
00404         ADS_STATUS rc;
00405         uint32 atype;
00406         DEBUG(3,("ads: dn_lookup\n"));
00407 
00408         rc = ads_search_retry_dn(ads, &res, dn, attrs);
00409 
00410         if (!ADS_ERR_OK(rc) || !res) {
00411                 goto failed;
00412         }
00413 
00414         (*name) = ads_pull_username(ads, mem_ctx, res);
00415 
00416         if (!ads_pull_uint32(ads, res, "sAMAccountType", &atype)) {
00417                 goto failed;
00418         }
00419         (*name_type) = ads_atype_map(atype);
00420 
00421         if (!ads_pull_sid(ads, res, "objectSid", sid)) {
00422                 goto failed;
00423         }
00424 
00425         if (res) 
00426                 ads_msgfree(ads, res);
00427 
00428         return True;
00429 
00430 failed:
00431         if (res) 
00432                 ads_msgfree(ads, res);
00433 
00434         return False;
00435 }
00436 
00437 /* Lookup user information from a rid */
00438 static NTSTATUS query_user(struct winbindd_domain *domain, 
00439                            TALLOC_CTX *mem_ctx, 
00440                            const DOM_SID *sid, 
00441                            WINBIND_USERINFO *info)
00442 {
00443         ADS_STRUCT *ads = NULL;
00444         const char *attrs[] = { "*", NULL };
00445         ADS_STATUS rc;
00446         int count;
00447         LDAPMessage *msg = NULL;
00448         char *ldap_exp;
00449         char *sidstr;
00450         uint32 group_rid;
00451         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00452 
00453         DEBUG(3,("ads: query_user\n"));
00454 
00455         if ( (ads = ads_cached_connection(domain)) == NULL ) {
00456                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00457                 goto done;
00458         }
00459 
00460         sidstr = sid_binstring(sid);
00461         asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
00462         rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
00463         free(ldap_exp);
00464         free(sidstr);
00465         if (!ADS_ERR_OK(rc) || !msg) {
00466                 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
00467                          sid_string_static(sid), ads_errstr(rc)));
00468                 goto done;
00469         }
00470 
00471         count = ads_count_replies(ads, msg);
00472         if (count != 1) {
00473                 DEBUG(1,("query_user(sid=%s): Not found\n",
00474                          sid_string_static(sid)));
00475                 goto done;
00476         }
00477 
00478         info->acct_name = ads_pull_username(ads, mem_ctx, msg);
00479 
00480         info->primary_gid = (gid_t)-1;  
00481         nss_get_info( domain->name, sid, mem_ctx, ads, msg, 
00482                       &info->homedir, &info->shell, &info->full_name, &info->primary_gid );     
00483 
00484         if (info->full_name == NULL) {
00485                 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
00486         }
00487 
00488         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
00489                 DEBUG(1,("No primary group for %s !?\n",
00490                          sid_string_static(sid)));
00491                 goto done;
00492         }
00493 
00494         sid_copy(&info->user_sid, sid);
00495         sid_compose(&info->group_sid, &domain->sid, group_rid);
00496 
00497         status = NT_STATUS_OK;
00498 
00499         DEBUG(3,("ads query_user gave %s\n", info->acct_name));
00500 done:
00501         if (msg) 
00502                 ads_msgfree(ads, msg);
00503 
00504         return status;
00505 }
00506 
00507 /* Lookup groups a user is a member of - alternate method, for when
00508    tokenGroups are not available. */
00509 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
00510                                          TALLOC_CTX *mem_ctx,
00511                                          const char *user_dn, 
00512                                          DOM_SID *primary_group,
00513                                          size_t *p_num_groups, DOM_SID **user_sids)
00514 {
00515         ADS_STATUS rc;
00516         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00517         int count;
00518         LDAPMessage *res = NULL;
00519         LDAPMessage *msg = NULL;
00520         char *ldap_exp;
00521         ADS_STRUCT *ads;
00522         const char *group_attrs[] = {"objectSid", NULL};
00523         char *escaped_dn;
00524         size_t num_groups = 0;
00525 
00526         DEBUG(3,("ads: lookup_usergroups_member\n"));
00527 
00528         ads = ads_cached_connection(domain);
00529 
00530         if (!ads) {
00531                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00532                 goto done;
00533         }
00534 
00535         if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) {
00536                 status = NT_STATUS_NO_MEMORY;
00537                 goto done;
00538         }
00539 
00540         if (!(ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectCategory=group))", escaped_dn))) {
00541                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
00542                 SAFE_FREE(escaped_dn);
00543                 status = NT_STATUS_NO_MEMORY;
00544                 goto done;
00545         }
00546 
00547         SAFE_FREE(escaped_dn);
00548 
00549         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
00550         
00551         if (!ADS_ERR_OK(rc) || !res) {
00552                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
00553                 return ads_ntstatus(rc);
00554         }
00555         
00556         count = ads_count_replies(ads, res);
00557         
00558         *user_sids = NULL;
00559         num_groups = 0;
00560 
00561         /* always add the primary group to the sid array */
00562         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
00563                 status = NT_STATUS_NO_MEMORY;
00564                 goto done;
00565         }
00566 
00567         if (count > 0) {
00568                 for (msg = ads_first_entry(ads, res); msg;
00569                      msg = ads_next_entry(ads, msg)) {
00570                         DOM_SID group_sid;
00571                 
00572                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
00573                                 DEBUG(1,("No sid for this group ?!?\n"));
00574                                 continue;
00575                         }
00576         
00577                         /* ignore Builtin groups from ADS - Guenther */
00578                         if (sid_check_is_in_builtin(&group_sid)) {
00579                                 continue;
00580                         }
00581                                
00582                         if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
00583                                          &num_groups)) {
00584                                 status = NT_STATUS_NO_MEMORY;
00585                                 goto done;
00586                         }
00587                 }
00588 
00589         }
00590 
00591         *p_num_groups = num_groups;
00592         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
00593 
00594         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
00595 done:
00596         if (res) 
00597                 ads_msgfree(ads, res);
00598 
00599         return status;
00600 }
00601 
00602 /* Lookup groups a user is a member of - alternate method, for when
00603    tokenGroups are not available. */
00604 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
00605                                            TALLOC_CTX *mem_ctx,
00606                                            const char *user_dn, 
00607                                            DOM_SID *primary_group,
00608                                            size_t *p_num_groups, DOM_SID **user_sids)
00609 {
00610         ADS_STATUS rc;
00611         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00612         int count;
00613         LDAPMessage *res = NULL;
00614         ADS_STRUCT *ads;
00615         const char *attrs[] = {"memberOf", NULL};
00616         size_t num_groups = 0;
00617         DOM_SID *group_sids = NULL;
00618         int i;
00619 
00620         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
00621 
00622         ads = ads_cached_connection(domain);
00623 
00624         if (!ads) {
00625                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00626                 goto done;
00627         }
00628 
00629         rc = ads_search_retry_extended_dn(ads, &res, user_dn, attrs, 
00630                                           ADS_EXTENDED_DN_HEX_STRING);
00631         
00632         if (!ADS_ERR_OK(rc) || !res) {
00633                 DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", 
00634                         user_dn, ads_errstr(rc)));
00635                 return ads_ntstatus(rc);
00636         }
00637         
00638         count = ads_count_replies(ads, res);
00639 
00640         if (count == 0) {
00641                 status = NT_STATUS_NO_SUCH_USER;
00642                 goto done;
00643         }
00644         
00645         *user_sids = NULL;
00646         num_groups = 0;
00647 
00648         /* always add the primary group to the sid array */
00649         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
00650                 status = NT_STATUS_NO_MEMORY;
00651                 goto done;
00652         }
00653 
00654         count = ads_pull_sids_from_extendeddn(ads, mem_ctx, res, "memberOf", 
00655                                               ADS_EXTENDED_DN_HEX_STRING, 
00656                                               &group_sids);
00657         if (count == 0) {
00658                 DEBUG(1,("No memberOf for this user?!?\n"));
00659                 status = NT_STATUS_NO_MEMORY;
00660                 goto done;
00661         }
00662 
00663         for (i=0; i<count; i++) {
00664 
00665                 /* ignore Builtin groups from ADS - Guenther */
00666                 if (sid_check_is_in_builtin(&group_sids[i])) {
00667                         continue;
00668                 }
00669                        
00670                 if (!add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
00671                                  &num_groups)) {
00672                         status = NT_STATUS_NO_MEMORY;
00673                         goto done;
00674                 }
00675         
00676         }
00677 
00678         *p_num_groups = num_groups;
00679         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
00680 
00681         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn));
00682 done:
00683         TALLOC_FREE(group_sids);
00684         if (res) 
00685                 ads_msgfree(ads, res);
00686 
00687         return status;
00688 }
00689 
00690 
00691 /* Lookup groups a user is a member of. */
00692 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
00693                                   TALLOC_CTX *mem_ctx,
00694                                   const DOM_SID *sid, 
00695                                   uint32 *p_num_groups, DOM_SID **user_sids)
00696 {
00697         ADS_STRUCT *ads = NULL;
00698         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
00699         ADS_STATUS rc;
00700         int count;
00701         LDAPMessage *msg = NULL;
00702         char *user_dn = NULL;
00703         DOM_SID *sids;
00704         int i;
00705         DOM_SID primary_group;
00706         uint32 primary_group_rid;
00707         fstring sid_string;
00708         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00709         size_t num_groups = 0;
00710 
00711         DEBUG(3,("ads: lookup_usergroups\n"));
00712         *p_num_groups = 0;
00713 
00714         status = lookup_usergroups_cached(domain, mem_ctx, sid, 
00715                                           p_num_groups, user_sids);
00716         if (NT_STATUS_IS_OK(status)) {
00717                 return NT_STATUS_OK;
00718         }
00719 
00720         ads = ads_cached_connection(domain);
00721         
00722         if (!ads) {
00723                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00724                 status = NT_STATUS_SERVER_DISABLED;
00725                 goto done;
00726         }
00727 
00728         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
00729 
00730         if (!ADS_ERR_OK(rc)) {
00731                 status = ads_ntstatus(rc);
00732                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", 
00733                          sid_to_string(sid_string, sid), ads_errstr(rc)));
00734                 goto done;
00735         }
00736         
00737         count = ads_count_replies(ads, msg);
00738         if (count != 1) {
00739                 status = NT_STATUS_UNSUCCESSFUL;
00740                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
00741                          "invalid number of results (count=%d)\n", 
00742                          sid_to_string(sid_string, sid), count));
00743                 goto done;
00744         }
00745 
00746         if (!msg) {
00747                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
00748                          sid_to_string(sid_string, sid)));
00749                 status = NT_STATUS_UNSUCCESSFUL;
00750                 goto done;
00751         }
00752 
00753         user_dn = ads_get_dn(ads, msg);
00754         if (user_dn == NULL) {
00755                 status = NT_STATUS_NO_MEMORY;
00756                 goto done;
00757         }
00758 
00759         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
00760                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
00761                          domain->name, sid_to_string(sid_string, sid)));
00762                 goto done;
00763         }
00764 
00765         sid_copy(&primary_group, &domain->sid);
00766         sid_append_rid(&primary_group, primary_group_rid);
00767 
00768         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
00769 
00770         /* there must always be at least one group in the token, 
00771            unless we are talking to a buggy Win2k server */
00772 
00773         /* actually this only happens when the machine account has no read
00774          * permissions on the tokenGroup attribute - gd */
00775 
00776         if (count == 0) {
00777 
00778                 /* no tokenGroups */
00779                 
00780                 /* lookup what groups this user is a member of by DN search on
00781                  * "memberOf" */
00782 
00783                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
00784                                                     &primary_group,
00785                                                     &num_groups, user_sids);
00786                 *p_num_groups = (uint32)num_groups;
00787                 if (NT_STATUS_IS_OK(status)) {
00788                         goto done;
00789                 }
00790 
00791                 /* lookup what groups this user is a member of by DN search on
00792                  * "member" */
00793 
00794                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
00795                                                   &primary_group,
00796                                                   &num_groups, user_sids);
00797                 *p_num_groups = (uint32)num_groups;
00798                 goto done;
00799         }
00800 
00801         *user_sids = NULL;
00802         num_groups = 0;
00803 
00804         if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
00805                 status = NT_STATUS_NO_MEMORY;
00806                 goto done;
00807         }
00808         
00809         for (i=0;i<count;i++) {
00810 
00811                 /* ignore Builtin groups from ADS - Guenther */
00812                 if (sid_check_is_in_builtin(&sids[i])) {
00813                         continue;
00814                 }
00815                                
00816                 if (!add_sid_to_array_unique(mem_ctx, &sids[i],
00817                                         user_sids, &num_groups)) {
00818                         status = NT_STATUS_NO_MEMORY;
00819                         goto done;
00820                 }
00821         }
00822 
00823         *p_num_groups = (uint32)num_groups;
00824         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
00825 
00826         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
00827                  sid_to_string(sid_string, sid)));
00828 done:
00829         ads_memfree(ads, user_dn);
00830         ads_msgfree(ads, msg);
00831         return status;
00832 }
00833 
00834 /*
00835   find the members of a group, given a group rid and domain
00836  */
00837 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
00838                                 TALLOC_CTX *mem_ctx,
00839                                 const DOM_SID *group_sid, uint32 *num_names, 
00840                                 DOM_SID **sid_mem, char ***names, 
00841                                 uint32 **name_types)
00842 {
00843         ADS_STATUS rc;
00844         int count;
00845         LDAPMessage *res=NULL;
00846         ADS_STRUCT *ads = NULL;
00847         char *ldap_exp;
00848         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00849         char *sidstr;
00850         char **members;
00851         int i;
00852         size_t num_members;
00853         fstring sid_string;
00854         BOOL more_values;
00855         const char **attrs;
00856         uint32 first_usn;
00857         uint32 current_usn;
00858         int num_retries = 0;
00859 
00860         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, 
00861                   sid_string_static(group_sid)));
00862 
00863         *num_names = 0;
00864 
00865         ads = ads_cached_connection(domain);
00866         
00867         if (!ads) {
00868                 domain->last_status = NT_STATUS_SERVER_DISABLED;
00869                 goto done;
00870         }
00871 
00872         if ((sidstr = sid_binstring(group_sid)) == NULL) {
00873                 status = NT_STATUS_NO_MEMORY;
00874                 goto done;
00875         }
00876 
00877         /* search for all members of the group */
00878         if (!(ldap_exp = talloc_asprintf(mem_ctx, "(objectSid=%s)",sidstr))) {
00879                 SAFE_FREE(sidstr);
00880                 DEBUG(1, ("ads: lookup_groupmem: tallloc_asprintf for ldap_exp failed!\n"));
00881                 status = NT_STATUS_NO_MEMORY;
00882                 goto done;
00883         }
00884         SAFE_FREE(sidstr);
00885 
00886         members = NULL;
00887         num_members = 0;
00888 
00889         if ((attrs = TALLOC_ARRAY(mem_ctx, const char *, 3)) == NULL) {
00890                 status = NT_STATUS_NO_MEMORY;
00891                 goto done;
00892         }
00893                 
00894         attrs[1] = talloc_strdup(mem_ctx, "usnChanged");
00895         attrs[2] = NULL;
00896                 
00897         do {
00898                 if (num_members == 0) 
00899                         attrs[0] = talloc_strdup(mem_ctx, "member");
00900 
00901                 DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1]));
00902 
00903                 rc = ads_search_retry(ads, &res, ldap_exp, attrs);
00904 
00905                 if (!ADS_ERR_OK(rc) || !res) {
00906                         DEBUG(1,("ads: lookup_groupmem ads_search: %s\n",
00907                                  ads_errstr(rc)));
00908                         status = ads_ntstatus(rc);
00909                         goto done;
00910                 }
00911 
00912                 count = ads_count_replies(ads, res);
00913                 if (count == 0)
00914                         break;
00915 
00916                 if (num_members == 0) {
00917                         if (!ads_pull_uint32(ads, res, "usnChanged", &first_usn)) {
00918                                 DEBUG(1, ("ads: lookup_groupmem could not pull usnChanged!\n"));
00919                                 goto done;
00920                         }
00921                 }
00922 
00923                 if (!ads_pull_uint32(ads, res, "usnChanged", &current_usn)) {
00924                         DEBUG(1, ("ads: lookup_groupmem could not pull usnChanged!\n"));
00925                         goto done;
00926                 }
00927 
00928                 if (first_usn != current_usn) {
00929                         DEBUG(5, ("ads: lookup_groupmem USN on this record changed"
00930                                   " - restarting search\n"));
00931                         if (num_retries < 5) {
00932                                 num_retries++;
00933                                 num_members = 0;
00934                                 ads_msgfree(ads, res);
00935                                 res = NULL;
00936                                 continue;
00937                         } else {
00938                                 DEBUG(5, ("ads: lookup_groupmem USN on this record changed"
00939                                           " - restarted search too many times, aborting!\n"));
00940                                 status = NT_STATUS_UNSUCCESSFUL;
00941                                 goto done;
00942                         }
00943                 }
00944 
00945                 members = ads_pull_strings_range(ads, mem_ctx, res,
00946                                                  "member",
00947                                                  members,
00948                                                  &attrs[0],
00949                                                  &num_members,
00950                                                  &more_values);
00951 
00952                 ads_msgfree(ads, res);
00953                 res = NULL;
00954 
00955                 if ((members == NULL) || (num_members == 0))
00956                         break;
00957 
00958         } while (more_values);
00959                 
00960         /* now we need to turn a list of members into rids, names and name types 
00961            the problem is that the members are in the form of distinguised names
00962         */
00963 
00964         if (num_members) {
00965                 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
00966                 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
00967                 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
00968 
00969                 if ((members == NULL) || (*sid_mem == NULL) ||
00970                      (*name_types == NULL) || (*names == NULL)) {
00971                         DEBUG(1, ("talloc failed\n"));
00972                         status = NT_STATUS_NO_MEMORY;
00973                         goto done;
00974                 }
00975         } else {
00976                 (*sid_mem) = NULL;
00977                 (*name_types) = NULL;
00978                 (*names) = NULL;
00979         }
00980  
00981         for (i=0;i<num_members;i++) {
00982                 uint32 name_type;
00983                 char *name;
00984                 DOM_SID sid;
00985 
00986                 if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) {
00987                     (*names)[*num_names] = name;
00988                     (*name_types)[*num_names] = name_type;
00989                     sid_copy(&(*sid_mem)[*num_names], &sid);
00990                     (*num_names)++;
00991                 }
00992         }       
00993 
00994         status = NT_STATUS_OK;
00995         DEBUG(3,("ads lookup_groupmem for sid=%s\n", sid_to_string(sid_string, group_sid)));
00996 done:
00997 
00998         if (res) 
00999                 ads_msgfree(ads, res);
01000 
01001         return status;
01002 }
01003 
01004 /* find the sequence number for a domain */
01005 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
01006 {
01007         ADS_STRUCT *ads = NULL;
01008         ADS_STATUS rc;
01009 
01010         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
01011 
01012         *seq = DOM_SEQUENCE_NONE;
01013 
01014         ads = ads_cached_connection(domain);
01015         
01016         if (!ads) {
01017                 domain->last_status = NT_STATUS_SERVER_DISABLED;
01018                 return NT_STATUS_UNSUCCESSFUL;
01019         }
01020 
01021         rc = ads_USN(ads, seq);
01022         
01023         if (!ADS_ERR_OK(rc)) {
01024         
01025                 /* its a dead connection, destroy it */
01026 
01027                 if (domain->private_data) {
01028                         ads = (ADS_STRUCT *)domain->private_data;
01029                         ads->is_mine = True;
01030                         ads_destroy(&ads);
01031                         ads_kdestroy("MEMORY:winbind_ccache");
01032                         domain->private_data = NULL;
01033                 }
01034         }
01035         return ads_ntstatus(rc);
01036 }
01037 
01038 /* get a list of trusted domains */
01039 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
01040                                 TALLOC_CTX *mem_ctx,
01041                                 uint32 *num_domains,
01042                                 char ***names,
01043                                 char ***alt_names,
01044                                 DOM_SID **dom_sids)
01045 {
01046         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
01047         struct ds_domain_trust  *domains = NULL;
01048         int                     count = 0;
01049         int                     i;
01050         uint32                  flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
01051         struct rpc_pipe_client *cli;
01052 
01053         DEBUG(3,("ads: trusted_domains\n"));
01054 
01055         *num_domains = 0;
01056         *alt_names   = NULL;
01057         *names       = NULL;
01058         *dom_sids    = NULL;
01059 
01060         result = cm_connect_netlogon(domain, &cli);
01061 
01062         if (!NT_STATUS_IS_OK(result)) {
01063                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
01064                           "for PIPE_NETLOGON (%s)\n", 
01065                           domain->name, nt_errstr(result)));
01066                 return NT_STATUS_UNSUCCESSFUL;
01067         }
01068         
01069         if ( NT_STATUS_IS_OK(result) ) {
01070                 result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
01071                                                       cli->cli->desthost, 
01072                                                       flags, &domains,
01073                                                       (unsigned int *)&count);
01074         }
01075         
01076         if ( NT_STATUS_IS_OK(result) && count) {
01077         
01078                 /* Allocate memory for trusted domain names and sids */
01079 
01080                 if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
01081                         DEBUG(0, ("trusted_domains: out of memory\n"));
01082                         return NT_STATUS_NO_MEMORY;
01083                 }
01084 
01085                 if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
01086                         DEBUG(0, ("trusted_domains: out of memory\n"));
01087                         return NT_STATUS_NO_MEMORY;
01088                 }
01089 
01090                 if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
01091                         DEBUG(0, ("trusted_domains: out of memory\n"));
01092                         return NT_STATUS_NO_MEMORY;
01093                 }
01094 
01095                 /* Copy across names and sids */
01096 
01097                 for (i = 0; i < count; i++) {
01098                         (*names)[i] = domains[i].netbios_domain;
01099                         (*alt_names)[i] = domains[i].dns_domain;
01100 
01101                         sid_copy(&(*dom_sids)[i], &domains[i].sid);
01102                 }
01103 
01104                 *num_domains = count;   
01105         }
01106 
01107         return result;
01108 }
01109 
01110 /* the ADS backend methods are exposed via this structure */
01111 struct winbindd_methods ads_methods = {
01112         True,
01113         query_user_list,
01114         enum_dom_groups,
01115         enum_local_groups,
01116         msrpc_name_to_sid,
01117         msrpc_sid_to_name,
01118         msrpc_rids_to_names,
01119         query_user,
01120         lookup_usergroups,
01121         msrpc_lookup_useraliases,
01122         lookup_groupmem,
01123         sequence_number,
01124         msrpc_lockout_policy,
01125         msrpc_password_policy,
01126         trusted_domains,
01127 };
01128 
01129 #endif

Sambaに対してSat Aug 29 21:23:09 2009に生成されました。  doxygen 1.4.7