nsswitch/winbindd_group.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind daemon for ntdom nss module
00005 
00006    Copyright (C) Tim Potter 2000
00007    Copyright (C) Jeremy Allison 2001.
00008    Copyright (C) Gerald (Jerry) Carter 2003.
00009    Copyright (C) Volker Lendecke 2005
00010    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015    
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020    
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 */
00025 
00026 #include "includes.h"
00027 #include "winbindd.h"
00028 
00029 extern BOOL opt_nocache;
00030 
00031 #undef DBGC_CLASS
00032 #define DBGC_CLASS DBGC_WINBIND
00033 
00034 static void add_member(const char *domain, const char *user,
00035            char **pp_members, size_t *p_num_members)
00036 {
00037         fstring name;
00038 
00039         fill_domain_username(name, domain, user, True);
00040         safe_strcat(name, ",", sizeof(name)-1);
00041         string_append(pp_members, name);
00042         *p_num_members += 1;
00043 }
00044 
00045 /**********************************************************************
00046  Add member users resulting from sid. Expand if it is a domain group.
00047 **********************************************************************/
00048 
00049 static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
00050 {
00051         DOM_SID dom_sid;
00052         uint32 rid;
00053         struct winbindd_domain *domain;
00054         size_t i;
00055 
00056         char *domain_name = NULL;
00057         char *name = NULL;
00058         enum lsa_SidType type;
00059 
00060         uint32 num_names;
00061         DOM_SID *sid_mem;
00062         char **names;
00063         uint32 *types;
00064 
00065         NTSTATUS result;
00066 
00067         TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
00068 
00069         if (mem_ctx == NULL) {
00070                 DEBUG(1, ("talloc_init failed\n"));
00071                 return;
00072         }
00073 
00074         sid_copy(&dom_sid, sid);
00075         sid_split_rid(&dom_sid, &rid);
00076 
00077         domain = find_lookup_domain_from_sid(sid);
00078 
00079         if (domain == NULL) {
00080                 DEBUG(3, ("Could not find domain for sid %s\n",
00081                           sid_string_static(sid)));
00082                 goto done;
00083         }
00084 
00085         result = domain->methods->sid_to_name(domain, mem_ctx, sid,
00086                                               &domain_name, &name, &type);
00087 
00088         if (!NT_STATUS_IS_OK(result)) {
00089                 DEBUG(3, ("sid_to_name failed for sid %s\n",
00090                           sid_string_static(sid)));
00091                 goto done;
00092         }
00093 
00094         DEBUG(10, ("Found name %s, type %d\n", name, type));
00095 
00096         if (type == SID_NAME_USER) {
00097                 add_member(domain_name, name, pp_members, p_num_members);
00098                 goto done;
00099         }
00100 
00101         if (type != SID_NAME_DOM_GRP) {
00102                 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
00103                            name));
00104                 goto done;
00105         }
00106 
00107         /* Expand the domain group, this must be done via the target domain */
00108 
00109         domain = find_domain_from_sid(sid);
00110 
00111         if (domain == NULL) {
00112                 DEBUG(3, ("Could not find domain from SID %s\n",
00113                           sid_string_static(sid)));
00114                 goto done;
00115         }
00116 
00117         result = domain->methods->lookup_groupmem(domain, mem_ctx,
00118                                                   sid, &num_names,
00119                                                   &sid_mem, &names,
00120                                                   &types);
00121 
00122         if (!NT_STATUS_IS_OK(result)) {
00123                 DEBUG(10, ("Could not lookup group members for %s: %s\n",
00124                            name, nt_errstr(result)));
00125                 goto done;
00126         }
00127 
00128         for (i=0; i<num_names; i++) {
00129                 DEBUG(10, ("Adding group member SID %s\n",
00130                            sid_string_static(&sid_mem[i])));
00131 
00132                 if (types[i] != SID_NAME_USER) {
00133                         DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
00134                                   "Ignoring.\n", names[i], name));
00135                         continue;
00136                 }
00137 
00138                 add_member(domain->name, names[i], pp_members, p_num_members);
00139         }
00140 
00141  done:
00142         talloc_destroy(mem_ctx);
00143         return;
00144 }
00145 
00146 static BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
00147                              DOM_SID *group_sid, 
00148                              size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
00149 {
00150         DOM_SID *members;
00151         size_t i, num_members;
00152 
00153         *num_gr_mem = 0;
00154         *gr_mem = NULL;
00155         *gr_mem_len = 0;
00156 
00157         if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
00158                                                &num_members)))
00159                 return True;
00160 
00161         for (i=0; i<num_members; i++) {
00162                 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
00163         }
00164 
00165         TALLOC_FREE(members);
00166 
00167         if (*gr_mem != NULL) {
00168                 size_t len;
00169 
00170                 /* We have at least one member, strip off the last "," */
00171                 len = strlen(*gr_mem);
00172                 (*gr_mem)[len-1] = '\0';
00173                 *gr_mem_len = len;
00174         }
00175 
00176         return True;
00177 }
00178 
00179 /* Fill a grent structure from various other information */
00180 
00181 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name, 
00182                        const char *gr_name, gid_t unix_gid)
00183 {
00184         fstring full_group_name;
00185 
00186         fill_domain_username( full_group_name, dom_name, gr_name, True );
00187 
00188         gr->gr_gid = unix_gid;
00189     
00190         /* Group name and password */
00191     
00192         safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
00193         safe_strcpy(gr->gr_passwd, "*", sizeof(gr->gr_passwd) - 1);
00194 
00195         return True;
00196 }
00197 
00198 /* Fill in the group membership field of a NT group given by group_sid */
00199 
00200 static BOOL fill_grent_mem(struct winbindd_domain *domain,
00201                            struct winbindd_cli_state *state,
00202                            DOM_SID *group_sid, 
00203                            enum lsa_SidType group_name_type, 
00204                            size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
00205 {
00206         DOM_SID *sid_mem = NULL;
00207         uint32 num_names = 0;
00208         uint32 *name_types = NULL;
00209         unsigned int buf_len = 0, buf_ndx = 0, i;
00210         char **names = NULL, *buf = NULL;
00211         BOOL result = False;
00212         TALLOC_CTX *mem_ctx;
00213         NTSTATUS status;
00214         uint32 group_rid;
00215         fstring sid_string;
00216 
00217         if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
00218                 return False;
00219 
00220         /* Initialise group membership information */
00221         
00222         DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
00223 
00224         /* Initialize with no members */
00225         *num_gr_mem = 0;
00226 
00227         /* HACK ALERT!! This whole routine does not cope with group members
00228          * from more than one domain, ie aliases. Thus we have to work it out
00229          * ourselves in a special routine. */
00230 
00231         if (domain->internal) {
00232                 result = fill_passdb_alias_grmem(domain, group_sid,
00233                                                num_gr_mem,
00234                                                gr_mem, gr_mem_len);
00235                 goto done;
00236         }
00237         
00238         if ( !((group_name_type==SID_NAME_DOM_GRP) ||
00239                 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
00240         {
00241                 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n", 
00242                           sid_to_string(sid_string, group_sid), domain->name, 
00243                           group_name_type));
00244                 goto done;
00245         }
00246 
00247         /* OPTIMIZATION / HACK. */
00248         /* If "enum users" is set to false, and the group being looked
00249            up is the Domain Users SID: S-1-5-domain-513, then for the
00250            list of members check if the querying user is in that group,
00251            and if so only return that user as the gr_mem array.
00252            We can change this to a different parameter than "enum users"
00253            if neccessaey, or parameterize the group list we do this for. */
00254 
00255         sid_peek_rid( group_sid, &group_rid );
00256         if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
00257                 DOM_SID querying_user_sid;
00258                 DOM_SID *pquerying_user_sid = NULL;
00259                 uint32 num_groups = 0;
00260                 DOM_SID *user_sids = NULL;
00261                 BOOL u_in_group = False;
00262 
00263                 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
00264                         sid_to_string(sid_string, group_sid), domain->name ));
00265 
00266                 if (state) {
00267                         uid_t ret_uid = (uid_t)-1;
00268                         if (sys_getpeereid(state->sock, &ret_uid)==0) {
00269                                 /* We know who's asking - look up their SID if
00270                                    it's one we've mapped before. */
00271                                 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
00272                                 if (NT_STATUS_IS_OK(status)) {
00273                                         pquerying_user_sid = &querying_user_sid;
00274                                         DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
00275                                                 (unsigned int)ret_uid,
00276                                                 sid_to_string(sid_string, pquerying_user_sid) ));
00277                                 }
00278                         }
00279                 }
00280 
00281                 /* Only look up if it was a winbindd user in this domain. */
00282                 if (pquerying_user_sid &&
00283                                 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
00284 
00285                         DEBUG(10,("fill_grent_mem: querying user = %s\n",
00286                                 sid_to_string(sid_string, pquerying_user_sid) ));
00287 
00288                         status = domain->methods->lookup_usergroups(domain,
00289                                                         mem_ctx,
00290                                                         pquerying_user_sid,
00291                                                         &num_groups,
00292                                                         &user_sids);
00293                         if (!NT_STATUS_IS_OK(status)) {
00294                                 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
00295                                         "for sid %s in domain %s (error: %s)\n", 
00296                                         sid_to_string(sid_string, pquerying_user_sid),
00297                                         domain->name,
00298                                         nt_errstr(status)));
00299                                 goto done;
00300                         }
00301 
00302                         for (i = 0; i < num_groups; i++) {
00303                                 if (sid_equal(group_sid, &user_sids[i])) {
00304                                         /* User is in Domain Users, add their name
00305                                            as the only group member. */
00306                                         u_in_group = True;
00307                                         break;
00308                                 }
00309                         }
00310                 }
00311 
00312                 if (u_in_group) {
00313                         size_t len = 0;
00314                         char *domainname = NULL;
00315                         char *username = NULL;
00316                         fstring name;
00317                         enum lsa_SidType type;
00318 
00319                         DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
00320                                 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
00321 
00322                         status = domain->methods->sid_to_name(domain, mem_ctx,
00323                                                                 pquerying_user_sid,
00324                                                                 &domainname,
00325                                                                 &username,
00326                                                                 &type);
00327                         if (!NT_STATUS_IS_OK(status)) {
00328                                 DEBUG(1, ("could not lookup username for user "
00329                                         "sid %s in domain %s (error: %s)\n", 
00330                                         sid_to_string(sid_string, pquerying_user_sid),
00331                                         domain->name,
00332                                         nt_errstr(status)));
00333                                 goto done;
00334                         }
00335                         fill_domain_username(name, domain->name, username, True);
00336                         len = strlen(name);
00337                         buf_len = len + 1;
00338                         if (!(buf = (char *)SMB_MALLOC(buf_len))) {
00339                                 DEBUG(1, ("out of memory\n"));
00340                                 goto done;
00341                         }
00342                         memcpy(buf, name, buf_len);
00343 
00344                         DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
00345                                 name, domain->name ));
00346 
00347                         /* user is the only member */
00348                         *num_gr_mem = 1;
00349                 }
00350                 
00351                 *gr_mem = buf;
00352                 *gr_mem_len = buf_len;
00353 
00354                 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem, 
00355                    (unsigned int)buf_len, *num_gr_mem ? buf : "NULL")); 
00356                 result = True;
00357                 goto done;
00358         }
00359 
00360         /* Lookup group members */
00361         status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names, 
00362                                                   &sid_mem, &names, &name_types);
00363         if (!NT_STATUS_IS_OK(status)) {
00364                 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n", 
00365                           sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
00366                 goto done;
00367         }
00368 
00369         DEBUG(10, ("looked up %d names\n", num_names));
00370 
00371         if (DEBUGLEVEL >= 10) {
00372                 for (i = 0; i < num_names; i++)
00373                         DEBUG(10, ("\t%20s %s %d\n", names[i],
00374                                    sid_string_static(&sid_mem[i]),
00375                                    name_types[i]));
00376         }
00377 
00378         /* Add members to list */
00379 
00380  again:
00381 
00382         for (i = 0; i < num_names; i++) {
00383                 char *the_name;
00384                 fstring name;
00385                 int len;
00386                         
00387                 the_name = names[i];
00388 
00389                 DEBUG(10, ("processing name %s\n", the_name));
00390 
00391                 /* FIXME: need to cope with groups within groups.  These
00392                    occur in Universal groups on a Windows 2000 native mode
00393                    server. */
00394 
00395                 /* make sure to allow machine accounts */
00396 
00397                 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
00398                         DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
00399                         continue;
00400                 }
00401 
00402                 /* Append domain name */
00403 
00404                 fill_domain_username(name, domain->name, the_name, True);
00405 
00406                 len = strlen(name);
00407                 
00408                 /* Add to list or calculate buffer length */
00409 
00410                 if (!buf) {
00411                         buf_len += len + 1; /* List is comma separated */
00412                         (*num_gr_mem)++;
00413                         DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
00414                 } else {
00415                         DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
00416                         safe_strcpy(&buf[buf_ndx], name, len);
00417                         buf_ndx += len;
00418                         buf[buf_ndx] = ',';
00419                         buf_ndx++;
00420                 }
00421         }
00422 
00423         /* Allocate buffer */
00424 
00425         if (!buf && buf_len != 0) {
00426                 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
00427                         DEBUG(1, ("out of memory\n"));
00428                         result = False;
00429                         goto done;
00430                 }
00431                 memset(buf, 0, buf_len);
00432                 goto again;
00433         }
00434 
00435         if (buf && buf_ndx > 0) {
00436                 buf[buf_ndx - 1] = '\0';
00437         }
00438 
00439         *gr_mem = buf;
00440         *gr_mem_len = buf_len;
00441 
00442         DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem, 
00443                    (unsigned int)buf_len, *num_gr_mem ? buf : "NULL")); 
00444         result = True;
00445 
00446 done:
00447 
00448         talloc_destroy(mem_ctx);
00449         
00450         DEBUG(10, ("fill_grent_mem returning %d\n", result));
00451 
00452         return result;
00453 }
00454 
00455 /* Return a group structure from a group name */
00456 
00457 void winbindd_getgrnam(struct winbindd_cli_state *state)
00458 {
00459         DOM_SID group_sid, tmp_sid;
00460         uint32 grp_rid;
00461         struct winbindd_domain *domain;
00462         enum lsa_SidType name_type;
00463         fstring name_domain, name_group;
00464         char *tmp, *gr_mem;
00465         size_t gr_mem_len;
00466         size_t num_gr_mem;
00467         gid_t gid;
00468         union unid_t id;
00469         NTSTATUS status;
00470         
00471         /* Ensure null termination */
00472         state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
00473 
00474         DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
00475                   state->request.data.groupname));
00476 
00477         /* Parse domain and groupname */
00478         
00479         memset(name_group, 0, sizeof(fstring));
00480 
00481         tmp = state->request.data.groupname;
00482 
00483         name_domain[0] = '\0';
00484         name_group[0] = '\0';
00485         
00486         parse_domain_user(tmp, name_domain, name_group);
00487 
00488         /* if no domain or our local domain and no local tdb group, default to
00489          * our local domain for aliases */
00490 
00491         if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
00492                 fstrcpy(name_domain, get_global_sam_name());
00493         }
00494 
00495         /* Get info for the domain */
00496 
00497         if ((domain = find_domain_from_name(name_domain)) == NULL) {
00498                 DEBUG(3, ("could not get domain sid for domain %s\n",
00499                           name_domain));
00500                 request_error(state);
00501                 return;
00502         }
00503         /* should we deal with users for our domain? */
00504         
00505         if ( lp_winbind_trusted_domains_only() && domain->primary) {
00506                 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
00507                          "getgrnam() for %s\\%s.\n", name_domain, name_group));
00508                 request_error(state);
00509                 return;
00510         }
00511 
00512         /* Get rid and name type from name */
00513 
00514         ws_name_replace( name_group, WB_REPLACE_CHAR );
00515         
00516         if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
00517                                          name_group, &group_sid, &name_type)) {
00518                 DEBUG(1, ("group %s in domain %s does not exist\n", 
00519                           name_group, name_domain));
00520                 request_error(state);
00521                 return;
00522         }
00523 
00524         if ( !((name_type==SID_NAME_DOM_GRP) ||
00525                ((name_type==SID_NAME_ALIAS) && domain->primary) ||
00526                ((name_type==SID_NAME_ALIAS) && domain->internal) ||
00527                ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
00528         {
00529                 DEBUG(1, ("name '%s' is not a local, domain or builtin "
00530                           "group: %d\n", name_group, name_type));
00531                 request_error(state);
00532                 return;
00533         }
00534 
00535         /* Make sure that the group SID is within the domain of the
00536            original domain */
00537 
00538         sid_copy( &tmp_sid, &group_sid );
00539         sid_split_rid( &tmp_sid, &grp_rid );
00540         if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
00541                 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n", 
00542                         state->request.data.groupname, sid_string_static(&group_sid)));
00543                 request_error(state);
00544                 return;
00545         }
00546 
00547         
00548 
00549         /* Try to get the GID */
00550 
00551         status = idmap_sid_to_gid(&group_sid, &gid);
00552 
00553         if (NT_STATUS_IS_OK(status)) {
00554                 goto got_gid;
00555         }
00556 
00557         /* Maybe it's one of our aliases in passdb */
00558 
00559         if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
00560             ((name_type == SID_NAME_ALIAS) ||
00561              (name_type == SID_NAME_WKN_GRP))) {
00562                 gid = id.gid;
00563                 goto got_gid;
00564         }
00565 
00566         DEBUG(1, ("error converting unix gid to sid\n"));
00567         request_error(state);
00568         return;
00569 
00570  got_gid:
00571 
00572         if (!fill_grent(&state->response.data.gr, name_domain,
00573                         name_group, gid) ||
00574             !fill_grent_mem(domain, state, &group_sid, name_type,
00575                             &num_gr_mem,
00576                             &gr_mem, &gr_mem_len)) {
00577                 request_error(state);
00578                 return;
00579         }
00580 
00581         state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
00582 
00583         /* Group membership lives at start of extra data */
00584 
00585         state->response.data.gr.gr_mem_ofs = 0;
00586 
00587         state->response.length += gr_mem_len;
00588         state->response.extra_data.data = gr_mem;
00589         request_ok(state);
00590 }
00591 
00592 static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
00593 {
00594         struct winbindd_domain *domain;
00595         enum lsa_SidType name_type;
00596         char *dom_name;
00597         char *group_name;
00598         size_t gr_mem_len;
00599         size_t num_gr_mem;
00600         char *gr_mem;
00601 
00602         /* Get name from sid */
00603 
00604         if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
00605                                          &group_name, &name_type)) {
00606                 DEBUG(1, ("could not lookup sid\n"));
00607                 request_error(state);
00608                 TALLOC_FREE(group_name);
00609                 TALLOC_FREE(dom_name);
00610                 return;
00611         }
00612 
00613         /* Fill in group structure */
00614 
00615         domain = find_domain_from_sid_noinit(&group_sid);
00616 
00617         if (!domain) {
00618                 DEBUG(1,("Can't find domain from sid\n"));
00619                 request_error(state);
00620                 TALLOC_FREE(group_name);
00621                 TALLOC_FREE(dom_name);
00622                 return;
00623         }
00624 
00625         if ( !((name_type==SID_NAME_DOM_GRP) ||
00626                ((name_type==SID_NAME_ALIAS) && domain->primary) ||
00627                ((name_type==SID_NAME_ALIAS) && domain->internal)) )
00628         {
00629                 DEBUG(1, ("name '%s' is not a local or domain group: %d\n", 
00630                           group_name, name_type));
00631                 request_error(state);
00632                 TALLOC_FREE(group_name);
00633                 TALLOC_FREE(dom_name);
00634                 return;
00635         }
00636 
00637         if (!fill_grent(&state->response.data.gr, dom_name, group_name, 
00638                         state->request.data.gid) ||
00639             !fill_grent_mem(domain, state, &group_sid, name_type,
00640                             &num_gr_mem,
00641                             &gr_mem, &gr_mem_len)) {
00642                 request_error(state);
00643                 TALLOC_FREE(group_name);
00644                 TALLOC_FREE(dom_name);
00645                 return;
00646         }
00647 
00648         state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
00649 
00650         /* Group membership lives at start of extra data */
00651 
00652         state->response.data.gr.gr_mem_ofs = 0;
00653 
00654         state->response.length += gr_mem_len;
00655         state->response.extra_data.data = gr_mem;
00656 
00657         TALLOC_FREE(group_name);
00658         TALLOC_FREE(dom_name);
00659 
00660         request_ok(state);
00661 }
00662 
00663 static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
00664 {
00665         struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
00666         enum lsa_SidType name_type;
00667         DOM_SID group_sid;
00668 
00669         if (success) {
00670                 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
00671                           (unsigned long)(state->request.data.gid), sid));
00672 
00673                 string_to_sid(&group_sid, sid);
00674                 getgrgid_got_sid(state, group_sid);
00675                 return;
00676         }
00677 
00678         /* Ok, this might be "ours", i.e. an alias */
00679         if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
00680             lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
00681             (name_type == SID_NAME_ALIAS)) {
00682                 /* Hey, got an alias */
00683                 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
00684                           (unsigned long)(state->request.data.gid), sid));
00685                 getgrgid_got_sid(state, group_sid);
00686                 return;
00687         }
00688 
00689         DEBUG(1, ("could not convert gid %lu to sid\n", 
00690                   (unsigned long)state->request.data.gid));
00691         request_error(state);
00692 }
00693 
00694 /* Return a group structure from a gid number */
00695 void winbindd_getgrgid(struct winbindd_cli_state *state)
00696 {
00697         DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid, 
00698                   (unsigned long)state->request.data.gid));
00699 
00700         /* always use the async interface */
00701         winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
00702 }
00703 
00704 /*
00705  * set/get/endgrent functions
00706  */
00707 
00708 /* "Rewind" file pointer for group database enumeration */
00709 
00710 static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
00711 {
00712         struct winbindd_domain *domain;
00713 
00714         DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
00715 
00716         /* Check user has enabled this */
00717 
00718         if (!lp_winbind_enum_groups()) {
00719                 return False;
00720         }               
00721 
00722         /* Free old static data if it exists */
00723         
00724         if (state->getgrent_state != NULL) {
00725                 free_getent_state(state->getgrent_state);
00726                 state->getgrent_state = NULL;
00727         }
00728         
00729         /* Create sam pipes for each domain we know about */
00730         
00731         for (domain = domain_list(); domain != NULL; domain = domain->next) {
00732                 struct getent_state *domain_state;
00733                 
00734                 /* Create a state record for this domain */
00735 
00736                 /* don't add our domaina if we are a PDC or if we 
00737                    are a member of a Samba domain */
00738                 
00739                 if ( lp_winbind_trusted_domains_only() && domain->primary )
00740                 {
00741                         continue;
00742                 }
00743                                                 
00744                 
00745                 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
00746                         DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
00747                         return False;
00748                 }
00749                 
00750                 ZERO_STRUCTP(domain_state);
00751                 
00752                 fstrcpy(domain_state->domain_name, domain->name);
00753 
00754                 /* Add to list of open domains */
00755                 
00756                 DLIST_ADD(state->getgrent_state, domain_state);
00757         }
00758         
00759         state->getgrent_initialized = True;
00760         return True;
00761 }
00762 
00763 void winbindd_setgrent(struct winbindd_cli_state *state)
00764 {
00765         if (winbindd_setgrent_internal(state)) {
00766                 request_ok(state);
00767         } else {
00768                 request_error(state);
00769         }
00770 }
00771 
00772 /* Close file pointer to ntdom group database */
00773 
00774 void winbindd_endgrent(struct winbindd_cli_state *state)
00775 {
00776         DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
00777 
00778         free_getent_state(state->getgrent_state);
00779         state->getgrent_initialized = False;
00780         state->getgrent_state = NULL;
00781         request_ok(state);
00782 }
00783 
00784 /* Get the list of domain groups and domain aliases for a domain.  We fill in
00785    the sam_entries and num_sam_entries fields with domain group information.  
00786    The dispinfo_ndx field is incremented to the index of the next group to 
00787    fetch. Return True if some groups were returned, False otherwise. */
00788 
00789 static BOOL get_sam_group_entries(struct getent_state *ent)
00790 {
00791         NTSTATUS status;
00792         uint32 num_entries;
00793         struct acct_info *name_list = NULL;
00794         TALLOC_CTX *mem_ctx;
00795         BOOL result = False;
00796         struct acct_info *sam_grp_entries = NULL;
00797         struct winbindd_domain *domain;
00798         
00799         if (ent->got_sam_entries)
00800                 return False;
00801 
00802         if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
00803                                           ent->domain_name))) {
00804                 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n")); 
00805                 return False;
00806         }
00807                 
00808         /* Free any existing group info */
00809 
00810         SAFE_FREE(ent->sam_entries);
00811         ent->num_sam_entries = 0;
00812         ent->got_sam_entries = True;
00813 
00814         /* Enumerate domain groups */
00815 
00816         num_entries = 0;
00817 
00818         if (!(domain = find_domain_from_name(ent->domain_name))) {
00819                 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
00820                 goto done;
00821         }
00822 
00823         /* always get the domain global groups */
00824 
00825         status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
00826         
00827         if (!NT_STATUS_IS_OK(status)) {
00828                 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
00829                 result = False;
00830                 goto done;
00831         }
00832 
00833         /* Copy entries into return buffer */
00834 
00835         if (num_entries) {
00836                 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
00837                         DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n", 
00838                                 num_entries));
00839                         result = False;
00840                         goto done;
00841                 }
00842                 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
00843         }
00844         
00845         ent->num_sam_entries = num_entries;
00846         
00847         /* get the domain local groups if we are a member of a native win2k domain
00848            and are not using LDAP to get the groups */
00849            
00850         if ( ( lp_security() != SEC_ADS && domain->native_mode 
00851                 && domain->primary) || domain->internal )
00852         {
00853                 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n", 
00854                         domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
00855                 
00856                 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
00857                 
00858                 if ( !NT_STATUS_IS_OK(status) ) { 
00859                         DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
00860                         num_entries = 0;
00861                 }
00862                 else
00863                         DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
00864                 
00865                 /* Copy entries into return buffer */
00866 
00867                 if ( num_entries ) {
00868                         if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
00869                         {
00870                                 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n", 
00871                                         num_entries));
00872                                 result = False;
00873                                 goto done;
00874                         }
00875                         
00876                         memcpy( &name_list[ent->num_sam_entries], sam_grp_entries, 
00877                                 num_entries * sizeof(struct acct_info) );
00878                 }
00879         
00880                 ent->num_sam_entries += num_entries;
00881         }
00882         
00883                 
00884         /* Fill in remaining fields */
00885 
00886         ent->sam_entries = name_list;
00887         ent->sam_entry_index = 0;
00888 
00889         result = (ent->num_sam_entries > 0);
00890 
00891  done:
00892         talloc_destroy(mem_ctx);
00893 
00894         return result;
00895 }
00896 
00897 /* Fetch next group entry from ntdom database */
00898 
00899 #define MAX_GETGRENT_GROUPS 500
00900 
00901 void winbindd_getgrent(struct winbindd_cli_state *state)
00902 {
00903         struct getent_state *ent;
00904         struct winbindd_gr *group_list = NULL;
00905         int num_groups, group_list_ndx, gr_mem_list_len = 0;
00906         char *gr_mem_list = NULL;
00907 
00908         DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
00909 
00910         /* Check user has enabled this */
00911 
00912         if (!lp_winbind_enum_groups()) {
00913                 request_error(state);
00914                 return;
00915         }
00916 
00917         num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
00918 
00919         if (num_groups == 0) {
00920                 request_error(state);
00921                 return;
00922         }
00923 
00924         if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
00925                 request_error(state);
00926                 return;
00927         }
00928 
00929         memset(state->response.extra_data.data, '\0',
00930                 num_groups * sizeof(struct winbindd_gr) );
00931 
00932         state->response.data.num_entries = 0;
00933 
00934         group_list = (struct winbindd_gr *)state->response.extra_data.data;
00935 
00936         if (!state->getgrent_initialized)
00937                 winbindd_setgrent_internal(state);
00938 
00939         if (!(ent = state->getgrent_state)) {
00940                 request_error(state);
00941                 return;
00942         }
00943 
00944         /* Start sending back groups */
00945 
00946         for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
00947                 struct acct_info *name_list = NULL;
00948                 fstring domain_group_name;
00949                 uint32 result;
00950                 gid_t group_gid;
00951                 size_t gr_mem_len;
00952                 char *gr_mem;
00953                 DOM_SID group_sid;
00954                 struct winbindd_domain *domain;
00955                                 
00956                 /* Do we need to fetch another chunk of groups? */
00957 
00958         tryagain:
00959 
00960                 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
00961                            ent->sam_entry_index, ent->num_sam_entries));
00962 
00963                 if (ent->num_sam_entries == ent->sam_entry_index) {
00964 
00965                         while(ent && !get_sam_group_entries(ent)) {
00966                                 struct getent_state *next_ent;
00967 
00968                                 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name)); 
00969 
00970                                 /* Free state information for this domain */
00971 
00972                                 SAFE_FREE(ent->sam_entries);
00973 
00974                                 next_ent = ent->next;
00975                                 DLIST_REMOVE(state->getgrent_state, ent);
00976                                 
00977                                 SAFE_FREE(ent);
00978                                 ent = next_ent;
00979                         }
00980 
00981                         /* No more domains */
00982 
00983                         if (!ent) 
00984                                 break;
00985                 }
00986                 
00987                 name_list = (struct acct_info *)ent->sam_entries;
00988                 
00989                 if (!(domain = 
00990                       find_domain_from_name(ent->domain_name))) {
00991                         DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
00992                         result = False;
00993                         goto done;
00994                 }
00995 
00996                 /* Lookup group info */
00997                 
00998                 sid_copy(&group_sid, &domain->sid);
00999                 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
01000 
01001                 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
01002                         union unid_t id;
01003                         enum lsa_SidType type;
01004 
01005                         DEBUG(10, ("SID %s not in idmap\n",
01006                                    sid_string_static(&group_sid)));
01007 
01008                         if (!pdb_sid_to_id(&group_sid, &id, &type)) {
01009                                 DEBUG(1, ("could not look up gid for group "
01010                                           "%s\n", 
01011                                           name_list[ent->sam_entry_index].acct_name));
01012                                 ent->sam_entry_index++;
01013                                 goto tryagain;
01014                         }
01015 
01016                         if ((type != SID_NAME_DOM_GRP) &&
01017                             (type != SID_NAME_ALIAS) &&
01018                             (type != SID_NAME_WKN_GRP)) {
01019                                 DEBUG(1, ("Group %s is a %s, not a group\n",
01020                                           sid_type_lookup(type),
01021                                           name_list[ent->sam_entry_index].acct_name));
01022                                 ent->sam_entry_index++;
01023                                 goto tryagain;
01024                         }
01025                         group_gid = id.gid;
01026                 }
01027 
01028                 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
01029                            (unsigned long)name_list[ent->sam_entry_index].rid));
01030                 
01031                 /* Fill in group entry */
01032 
01033                 fill_domain_username(domain_group_name, ent->domain_name, 
01034                          name_list[ent->sam_entry_index].acct_name, True);
01035 
01036                 result = fill_grent(&group_list[group_list_ndx], 
01037                                     ent->domain_name,
01038                                     name_list[ent->sam_entry_index].acct_name,
01039                                     group_gid);
01040 
01041                 /* Fill in group membership entry */
01042 
01043                 if (result) {
01044                         size_t num_gr_mem = 0;
01045                         DOM_SID member_sid;
01046                         group_list[group_list_ndx].num_gr_mem = 0;
01047                         gr_mem = NULL;
01048                         gr_mem_len = 0;
01049                         
01050                         /* Get group membership */                      
01051                         if (state->request.cmd == WINBINDD_GETGRLST) {
01052                                 result = True;
01053                         } else {
01054                                 sid_copy(&member_sid, &domain->sid);
01055                                 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
01056                                 result = fill_grent_mem(
01057                                         domain,
01058                                         NULL,
01059                                         &member_sid,
01060                                         SID_NAME_DOM_GRP,
01061                                         &num_gr_mem,
01062                                         &gr_mem, &gr_mem_len);
01063 
01064                                 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
01065                         }
01066                 }
01067 
01068                 if (result) {
01069                         /* Append to group membership list */
01070                         gr_mem_list = (char *)SMB_REALLOC(
01071                                 gr_mem_list, gr_mem_list_len + gr_mem_len);
01072 
01073                         if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
01074                                 DEBUG(0, ("out of memory\n"));
01075                                 gr_mem_list_len = 0;
01076                                 break;
01077                         }
01078 
01079                         DEBUG(10, ("list_len = %d, mem_len = %u\n",
01080                                    gr_mem_list_len, (unsigned int)gr_mem_len));
01081 
01082                         memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
01083                                gr_mem_len);
01084 
01085                         SAFE_FREE(gr_mem);
01086 
01087                         group_list[group_list_ndx].gr_mem_ofs = 
01088                                 gr_mem_list_len;
01089 
01090                         gr_mem_list_len += gr_mem_len;
01091                 }
01092 
01093                 ent->sam_entry_index++;
01094                 
01095                 /* Add group to return list */
01096                 
01097                 if (result) {
01098 
01099                         DEBUG(10, ("adding group num_entries = %d\n",
01100                                    state->response.data.num_entries));
01101 
01102                         group_list_ndx++;
01103                         state->response.data.num_entries++;
01104                         
01105                         state->response.length +=
01106                                 sizeof(struct winbindd_gr);
01107                         
01108                 } else {
01109                         DEBUG(0, ("could not lookup domain group %s\n", 
01110                                   domain_group_name));
01111                 }
01112         }
01113 
01114         /* Copy the list of group memberships to the end of the extra data */
01115 
01116         if (group_list_ndx == 0)
01117                 goto done;
01118 
01119         state->response.extra_data.data = SMB_REALLOC(
01120                 state->response.extra_data.data,
01121                 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
01122 
01123         if (!state->response.extra_data.data) {
01124                 DEBUG(0, ("out of memory\n"));
01125                 group_list_ndx = 0;
01126                 SAFE_FREE(gr_mem_list);
01127                 request_error(state);
01128                 return;
01129         }
01130 
01131         memcpy(&((char *)state->response.extra_data.data)
01132                [group_list_ndx * sizeof(struct winbindd_gr)], 
01133                gr_mem_list, gr_mem_list_len);
01134 
01135         state->response.length += gr_mem_list_len;
01136 
01137         DEBUG(10, ("returning %d groups, length = %d\n",
01138                    group_list_ndx, gr_mem_list_len));
01139 
01140         /* Out of domains */
01141 
01142  done:
01143 
01144         SAFE_FREE(gr_mem_list);
01145 
01146         if (group_list_ndx > 0)
01147                 request_ok(state);
01148         else
01149                 request_error(state);
01150 }
01151 
01152 /* List domain groups without mapping to unix ids */
01153 
01154 void winbindd_list_groups(struct winbindd_cli_state *state)
01155 {
01156         uint32 total_entries = 0;
01157         struct winbindd_domain *domain;
01158         const char *which_domain;
01159         char *extra_data = NULL;
01160         unsigned int extra_data_len = 0, i;
01161 
01162         DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
01163 
01164         /* Ensure null termination */
01165         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';  
01166         which_domain = state->request.domain_name;
01167         
01168         /* Enumerate over trusted domains */
01169 
01170         for (domain = domain_list(); domain; domain = domain->next) {
01171                 struct getent_state groups;
01172 
01173                 /* if we have a domain name restricting the request and this
01174                    one in the list doesn't match, then just bypass the remainder
01175                    of the loop */
01176                    
01177                 if ( *which_domain && !strequal(which_domain, domain->name) )
01178                         continue;
01179                         
01180                 ZERO_STRUCT(groups);
01181 
01182                 /* Get list of sam groups */
01183                 
01184                 fstrcpy(groups.domain_name, domain->name);
01185 
01186                 get_sam_group_entries(&groups);
01187                         
01188                 if (groups.num_sam_entries == 0) {
01189                         /* this domain is empty or in an error state */
01190                         continue;
01191                 }
01192 
01193                 /* keep track the of the total number of groups seen so 
01194                    far over all domains */
01195                 total_entries += groups.num_sam_entries;
01196                 
01197                 /* Allocate some memory for extra data.  Note that we limit
01198                    account names to sizeof(fstring) = 128 characters.  */               
01199                 extra_data = (char *)SMB_REALLOC(
01200                         extra_data, sizeof(fstring) * total_entries);
01201  
01202                 if (!extra_data) {
01203                         DEBUG(0,("failed to enlarge buffer!\n"));
01204                         request_error(state);
01205                         return;
01206                 }
01207 
01208                 /* Pack group list into extra data fields */
01209                 for (i = 0; i < groups.num_sam_entries; i++) {
01210                         char *group_name = ((struct acct_info *)
01211                                             groups.sam_entries)[i].acct_name; 
01212                         fstring name;
01213 
01214                         fill_domain_username(name, domain->name, group_name, True);
01215                         /* Append to extra data */                      
01216                         memcpy(&extra_data[extra_data_len], name, 
01217                                strlen(name));
01218                         extra_data_len += strlen(name);
01219                         extra_data[extra_data_len++] = ',';
01220                 }
01221 
01222                 SAFE_FREE(groups.sam_entries);
01223         }
01224 
01225         /* Assign extra_data fields in response structure */
01226         if (extra_data) {
01227                 extra_data[extra_data_len - 1] = '\0';
01228                 state->response.extra_data.data = extra_data;
01229                 state->response.length += extra_data_len;
01230         }
01231 
01232         /* No domains may have responded but that's still OK so don't
01233            return an error. */
01234 
01235         request_ok(state);
01236 }
01237 
01238 /* Get user supplementary groups.  This is much quicker than trying to
01239    invert the groups database.  We merge the groups from the gids and
01240    other_sids info3 fields as trusted domain, universal group
01241    memberships, and nested groups (win2k native mode only) are not
01242    returned by the getgroups RPC call but are present in the info3. */
01243 
01244 struct getgroups_state {
01245         struct winbindd_cli_state *state;
01246         struct winbindd_domain *domain;
01247         char *domname;
01248         char *username;
01249         DOM_SID user_sid;
01250 
01251         const DOM_SID *token_sids;
01252         size_t i, num_token_sids;
01253 
01254         gid_t *token_gids;
01255         size_t num_token_gids;
01256 };
01257 
01258 static void getgroups_usersid_recv(void *private_data, BOOL success,
01259                                    const DOM_SID *sid, enum lsa_SidType type);
01260 static void getgroups_tokensids_recv(void *private_data, BOOL success,
01261                                      DOM_SID *token_sids, size_t num_token_sids);
01262 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
01263 
01264 void winbindd_getgroups(struct winbindd_cli_state *state)
01265 {
01266         struct getgroups_state *s;
01267 
01268         /* Ensure null termination */
01269         state->request.data.username
01270                 [sizeof(state->request.data.username)-1]='\0';
01271 
01272         DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
01273                   state->request.data.username));
01274 
01275         /* Parse domain and username */
01276 
01277         s = TALLOC_P(state->mem_ctx, struct getgroups_state);
01278         if (s == NULL) {
01279                 DEBUG(0, ("talloc failed\n"));
01280                 request_error(state);
01281                 return;
01282         }
01283 
01284         s->state = state;
01285 
01286         ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
01287 
01288         if (!parse_domain_user_talloc(state->mem_ctx,
01289                                       state->request.data.username,
01290                                       &s->domname, &s->username)) {
01291                 DEBUG(5, ("Could not parse domain user: %s\n",
01292                           state->request.data.username));
01293 
01294                 /* error out if we do not have nested group support */
01295 
01296                 if ( !lp_winbind_nested_groups() ) {
01297                         request_error(state);
01298                         return;
01299                 }
01300 
01301                 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
01302                 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
01303         }
01304         
01305         /* Get info for the domain */
01306 
01307         s->domain = find_domain_from_name_noinit(s->domname);
01308 
01309         if (s->domain == NULL) {
01310                 DEBUG(7, ("could not find domain entry for domain %s\n", 
01311                           s->domname));
01312                 request_error(state);
01313                 return;
01314         }
01315 
01316         if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
01317                 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
01318                          "getgroups() for %s\\%s.\n", s->domname,
01319                          s->username));
01320                 request_error(state);
01321                 return;
01322         }       
01323 
01324         /* Get rid and name type from name.  The following costs 1 packet */
01325 
01326         winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
01327                                   getgroups_usersid_recv, s);
01328 }
01329 
01330 static void getgroups_usersid_recv(void *private_data, BOOL success,
01331                                    const DOM_SID *sid, enum lsa_SidType type)
01332 {
01333         struct getgroups_state *s =
01334                 (struct getgroups_state *)private_data;
01335 
01336         if ((!success) ||
01337             ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
01338                 request_error(s->state);
01339                 return;
01340         }
01341 
01342         sid_copy(&s->user_sid, sid);
01343 
01344         winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
01345                                 getgroups_tokensids_recv, s);
01346 }
01347 
01348 static void getgroups_tokensids_recv(void *private_data, BOOL success,
01349                                      DOM_SID *token_sids, size_t num_token_sids)
01350 {
01351         struct getgroups_state *s =
01352                 (struct getgroups_state *)private_data;
01353 
01354         /* We need at least the user sid and the primary group in the token,
01355          * otherwise it's an error */
01356 
01357         if ((!success) || (num_token_sids < 2)) {
01358                 request_error(s->state);
01359                 return;
01360         }
01361 
01362         s->token_sids = token_sids;
01363         s->num_token_sids = num_token_sids;
01364         s->i = 0;
01365 
01366         s->token_gids = NULL;
01367         s->num_token_gids = 0;
01368 
01369         getgroups_sid2gid_recv(s, False, 0);
01370 }
01371 
01372 static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
01373 {
01374         struct getgroups_state *s =
01375                 (struct getgroups_state *)private_data;
01376 
01377         if (success) {
01378                 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
01379                                         &s->token_gids,
01380                                         &s->num_token_gids)) {
01381                         return;
01382                 }
01383         }
01384 
01385         if (s->i < s->num_token_sids) {
01386                 const DOM_SID *sid = &s->token_sids[s->i];
01387                 s->i += 1;
01388 
01389                 if (sid_equal(sid, &s->user_sid)) {
01390                         getgroups_sid2gid_recv(s, False, 0);
01391                         return;
01392                 }
01393 
01394                 winbindd_sid2gid_async(s->state->mem_ctx, sid,
01395                                        getgroups_sid2gid_recv, s);
01396                 return;
01397         }
01398 
01399         s->state->response.data.num_entries = s->num_token_gids;
01400         /* s->token_gids are talloced */
01401         if (s->num_token_gids != 0) {
01402                 s->state->response.extra_data.data = smb_xmemdup(
01403                         s->token_gids, s->num_token_gids * sizeof(gid_t));
01404                 s->state->response.length += s->num_token_gids * sizeof(gid_t);
01405         }
01406         request_ok(s->state);
01407 }
01408 
01409 /* Get user supplementary sids. This is equivalent to the
01410    winbindd_getgroups() function but it involves a SID->SIDs mapping
01411    rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
01412    idmap. This call is designed to be used with applications that need
01413    to do ACL evaluation themselves. Note that the cached info3 data is
01414    not used 
01415 
01416    this function assumes that the SID that comes in is a user SID. If
01417    you pass in another type of SID then you may get unpredictable
01418    results.
01419 */
01420 
01421 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
01422                              size_t num_sids);
01423 
01424 void winbindd_getusersids(struct winbindd_cli_state *state)
01425 {
01426         DOM_SID *user_sid;
01427 
01428         /* Ensure null termination */
01429         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
01430 
01431         user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
01432         if (user_sid == NULL) {
01433                 DEBUG(1, ("talloc failed\n"));
01434                 request_error(state);
01435                 return;
01436         }
01437 
01438         if (!string_to_sid(user_sid, state->request.data.sid)) {
01439                 DEBUG(1, ("Could not get convert sid %s from string\n",
01440                           state->request.data.sid));
01441                 request_error(state);
01442                 return;
01443         }
01444 
01445         winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
01446                                 state);
01447 }
01448 
01449 static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
01450                              size_t num_sids)
01451 {
01452         struct winbindd_cli_state *state =
01453                 (struct winbindd_cli_state *)private_data;
01454         char *ret = NULL;
01455         unsigned ofs, ret_size = 0;
01456         size_t i;
01457 
01458         if (!success) {
01459                 request_error(state);
01460                 return;
01461         }
01462 
01463         /* work out the response size */
01464         for (i = 0; i < num_sids; i++) {
01465                 const char *s = sid_string_static(&sids[i]);
01466                 ret_size += strlen(s) + 1;
01467         }
01468 
01469         /* build the reply */
01470         ret = (char *)SMB_MALLOC(ret_size);
01471         if (!ret) {
01472                 DEBUG(0, ("malloc failed\n"));
01473                 request_error(state);
01474                 return;
01475         }
01476         ofs = 0;
01477         for (i = 0; i < num_sids; i++) {
01478                 const char *s = sid_string_static(&sids[i]);
01479                 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
01480                 ofs += strlen(ret+ofs) + 1;
01481         }
01482 
01483         /* Send data back to client */
01484         state->response.data.num_entries = num_sids;
01485         state->response.extra_data.data = ret;
01486         state->response.length += ret_size;
01487         request_ok(state);
01488 }
01489 
01490 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
01491 {
01492         DOM_SID user_sid;
01493         struct winbindd_domain *domain;
01494 
01495         /* Ensure null termination */
01496         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
01497 
01498         if (!string_to_sid(&user_sid, state->request.data.sid)) {
01499                 DEBUG(1, ("Could not get convert sid %s from string\n",
01500                           state->request.data.sid));
01501                 request_error(state);
01502                 return;
01503         }
01504 
01505         /* Get info for the domain */   
01506         if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
01507                 DEBUG(0,("could not find domain entry for sid %s\n", 
01508                          sid_string_static(&user_sid)));
01509                 request_error(state);
01510                 return;
01511         }
01512 
01513         sendto_domain(state, domain);
01514 }
01515 
01516 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
01517                                                     struct winbindd_cli_state *state)
01518 {
01519         DOM_SID user_sid;
01520         NTSTATUS status;
01521 
01522         char *sidstring;
01523         ssize_t len;
01524         DOM_SID *groups;
01525         uint32 num_groups;
01526 
01527         /* Ensure null termination */
01528         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
01529 
01530         if (!string_to_sid(&user_sid, state->request.data.sid)) {
01531                 DEBUG(1, ("Could not get convert sid %s from string\n",
01532                           state->request.data.sid));
01533                 return WINBINDD_ERROR;
01534         }
01535 
01536         status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
01537                                                     &user_sid, &num_groups,
01538                                                     &groups);
01539         if (!NT_STATUS_IS_OK(status))
01540                 return WINBINDD_ERROR;
01541 
01542         if (num_groups == 0) {
01543                 state->response.data.num_entries = 0;
01544                 state->response.extra_data.data = NULL;
01545                 return WINBINDD_OK;
01546         }
01547 
01548         if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
01549                 DEBUG(0, ("talloc failed\n"));
01550                 return WINBINDD_ERROR;
01551         }
01552 
01553         state->response.extra_data.data = SMB_STRDUP(sidstring);
01554         if (!state->response.extra_data.data) {
01555                 return WINBINDD_ERROR;
01556         }
01557         state->response.length += len+1;
01558         state->response.data.num_entries = num_groups;
01559 
01560         return WINBINDD_OK;
01561 }

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