root/source3/winbindd/winbindd_group.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_member
  2. add_expanded_sid
  3. fill_passdb_alias_grmem
  4. fill_grent
  5. fill_grent_mem_domusers
  6. namecmp
  7. sort_unique_list
  8. add_names_to_list
  9. expand_groups
  10. fill_grent_mem
  11. getgrnam_recv
  12. winbindd_getgrnam
  13. getgrsid_sid2gid_recv
  14. getgrsid_lookupsid_recv
  15. winbindd_getgrsid
  16. getgrgid_recv
  17. winbindd_getgrgid
  18. winbindd_setgrent_internal
  19. winbindd_setgrent
  20. winbindd_endgrent
  21. get_sam_group_entries
  22. winbindd_getgrent
  23. winbindd_list_groups
  24. winbindd_getgroups
  25. getgroups_usersid_recv
  26. getgroups_tokensids_recv
  27. getgroups_sid2gid_recv
  28. winbindd_getusersids
  29. getusersids_recv
  30. winbindd_getuserdomgroups
  31. winbindd_dual_getuserdomgroups
  32. winbindd_getsidaliases
  33. winbindd_dual_getsidaliases

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Winbind daemon for ntdom nss module
   5 
   6    Copyright (C) Tim Potter 2000
   7    Copyright (C) Jeremy Allison 2001.
   8    Copyright (C) Gerald (Jerry) Carter 2003.
   9    Copyright (C) Volker Lendecke 2005
  10    
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15    
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20    
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "winbindd.h"
  27 
  28 #undef DBGC_CLASS
  29 #define DBGC_CLASS DBGC_WINBIND
  30 
  31 static void add_member(const char *domain, const char *user,
     /* [<][>][^][v][top][bottom][index][help] */
  32            char **pp_members, size_t *p_num_members)
  33 {
  34         fstring name;
  35 
  36         if (domain != NULL) {
  37                 fill_domain_username(name, domain, user, True);
  38         } else {
  39                 fstrcpy(name, user);
  40         }
  41         safe_strcat(name, ",", sizeof(name)-1);
  42         string_append(pp_members, name);
  43         *p_num_members += 1;
  44 }
  45 
  46 /**********************************************************************
  47  Add member users resulting from sid. Expand if it is a domain group.
  48 **********************************************************************/
  49 
  50 static void add_expanded_sid(const DOM_SID *sid,
     /* [<][>][^][v][top][bottom][index][help] */
  51                              char **pp_members,
  52                              size_t *p_num_members)
  53 {
  54         DOM_SID dom_sid;
  55         uint32 rid;
  56         struct winbindd_domain *domain;
  57         size_t i;
  58 
  59         char *domain_name = NULL;
  60         char *name = NULL;
  61         enum lsa_SidType type;
  62 
  63         uint32 num_names;
  64         DOM_SID *sid_mem;
  65         char **names;
  66         uint32 *types;
  67 
  68         NTSTATUS result;
  69 
  70         TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
  71 
  72         if (mem_ctx == NULL) {
  73                 DEBUG(1, ("talloc_init failed\n"));
  74                 return;
  75         }
  76 
  77         sid_copy(&dom_sid, sid);
  78         sid_split_rid(&dom_sid, &rid);
  79 
  80         domain = find_lookup_domain_from_sid(sid);
  81 
  82         if (domain == NULL) {
  83                 DEBUG(3, ("Could not find domain for sid %s\n",
  84                           sid_string_dbg(sid)));
  85                 goto done;
  86         }
  87 
  88         result = domain->methods->sid_to_name(domain, mem_ctx, sid,
  89                                               &domain_name, &name, &type);
  90 
  91         if (!NT_STATUS_IS_OK(result)) {
  92                 DEBUG(3, ("sid_to_name failed for sid %s\n",
  93                           sid_string_dbg(sid)));
  94                 goto done;
  95         }
  96 
  97         DEBUG(10, ("Found name %s, type %d\n", name, type));
  98 
  99         if (type == SID_NAME_USER) {
 100                 add_member(domain_name, name, pp_members, p_num_members);
 101                 goto done;
 102         }
 103 
 104         if (type != SID_NAME_DOM_GRP) {
 105                 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
 106                            name));
 107                 goto done;
 108         }
 109 
 110         /* Expand the domain group, this must be done via the target domain */
 111 
 112         domain = find_domain_from_sid(sid);
 113 
 114         if (domain == NULL) {
 115                 DEBUG(3, ("Could not find domain from SID %s\n",
 116                           sid_string_dbg(sid)));
 117                 goto done;
 118         }
 119 
 120         result = domain->methods->lookup_groupmem(domain, mem_ctx,
 121                                                   sid, &num_names,
 122                                                   &sid_mem, &names,
 123                                                   &types);
 124 
 125         if (!NT_STATUS_IS_OK(result)) {
 126                 DEBUG(10, ("Could not lookup group members for %s: %s\n",
 127                            name, nt_errstr(result)));
 128                 goto done;
 129         }
 130 
 131         for (i=0; i<num_names; i++) {
 132                 DEBUG(10, ("Adding group member SID %s\n",
 133                            sid_string_dbg(&sid_mem[i])));
 134 
 135                 if (types[i] != SID_NAME_USER) {
 136                         DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
 137                                   "Ignoring.\n", names[i], name));
 138                         continue;
 139                 }
 140 
 141                 add_member(NULL, names[i], pp_members, p_num_members);
 142         }
 143 
 144  done:
 145         talloc_destroy(mem_ctx);
 146         return;
 147 }
 148 
 149 static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 150                                     DOM_SID *group_sid, size_t *num_gr_mem,
 151                                     char **gr_mem, size_t *gr_mem_len)
 152 {
 153         DOM_SID *members;
 154         size_t i, num_members;
 155 
 156         *num_gr_mem = 0;
 157         *gr_mem = NULL;
 158         *gr_mem_len = 0;
 159 
 160         if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
 161                                                &num_members)))
 162                 return True;
 163 
 164         for (i=0; i<num_members; i++) {
 165                 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
 166         }
 167 
 168         TALLOC_FREE(members);
 169 
 170         if (*gr_mem != NULL) {
 171                 size_t len;
 172 
 173                 /* We have at least one member, strip off the last "," */
 174                 len = strlen(*gr_mem);
 175                 (*gr_mem)[len-1] = '\0';
 176                 *gr_mem_len = len;
 177         }
 178 
 179         return True;
 180 }
 181 
 182 /* Fill a grent structure from various other information */
 183 
 184 static bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
     /* [<][>][^][v][top][bottom][index][help] */
 185                        const char *dom_name,
 186                        char *gr_name, gid_t unix_gid)
 187 {
 188         fstring full_group_name;
 189         char *mapped_name = NULL;
 190         struct winbindd_domain *domain = find_domain_from_name_noinit(dom_name);
 191         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 192 
 193         nt_status = normalize_name_map(mem_ctx, domain, gr_name,
 194                                        &mapped_name);
 195 
 196         /* Basic whitespace replacement */
 197         if (NT_STATUS_IS_OK(nt_status)) {
 198                 fill_domain_username(full_group_name, dom_name,
 199                                      mapped_name, true);
 200         }
 201         /* Mapped to an aliase */
 202         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 203                 fstrcpy(full_group_name, mapped_name);
 204         }
 205         /* no change */
 206         else {
 207                 fill_domain_username( full_group_name, dom_name,
 208                                       gr_name, True );
 209         }
 210 
 211         gr->gr_gid = unix_gid;
 212 
 213         /* Group name and password */
 214 
 215         safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
 216         safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
 217 
 218         return True;
 219 }
 220 
 221 /***********************************************************************
 222  If "enum users" is set to false, and the group being looked
 223  up is the Domain Users SID: S-1-5-domain-513, then for the
 224  list of members check if the querying user is in that group,
 225  and if so only return that user as the gr_mem array.
 226  We can change this to a different parameter than "enum users"
 227  if neccessaey, or parameterize the group list we do this for.
 228 ***********************************************************************/
 229 
 230 static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 231                                      struct winbindd_domain *domain,
 232                                      struct winbindd_cli_state *state,
 233                                      DOM_SID *group_sid,
 234                                      enum lsa_SidType group_name_type,
 235                                      size_t *num_gr_mem, char **gr_mem,
 236                                      size_t *gr_mem_len)
 237 {
 238         DOM_SID querying_user_sid;
 239         DOM_SID *pquerying_user_sid = NULL;
 240         uint32 num_groups = 0;
 241         DOM_SID *user_sids = NULL;
 242         bool u_in_group = False;
 243         NTSTATUS status;
 244         int i;
 245         unsigned int buf_len = 0;
 246         char *buf = NULL;
 247 
 248         DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
 249                   domain->name ));
 250 
 251         if (state) {
 252                 uid_t ret_uid = (uid_t)-1;
 253                 if (sys_getpeereid(state->sock, &ret_uid)==0) {
 254                         /* We know who's asking - look up their SID if
 255                            it's one we've mapped before. */
 256                         status = idmap_uid_to_sid(domain->name,
 257                                                   &querying_user_sid, ret_uid);
 258                         if (NT_STATUS_IS_OK(status)) {
 259                                 pquerying_user_sid = &querying_user_sid;
 260                                 DEBUG(10,("fill_grent_mem_domain_users: "
 261                                           "querying uid %u -> %s\n",
 262                                           (unsigned int)ret_uid,
 263                                           sid_string_dbg(pquerying_user_sid)));
 264                         }
 265                 }
 266         }
 267 
 268         /* Only look up if it was a winbindd user in this domain. */
 269         if (pquerying_user_sid &&
 270             (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
 271 
 272                 DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
 273                           sid_string_dbg(pquerying_user_sid) ));
 274 
 275                 status = domain->methods->lookup_usergroups(domain,
 276                                                             mem_ctx,
 277                                                             pquerying_user_sid,
 278                                                             &num_groups,
 279                                                             &user_sids);
 280                 if (!NT_STATUS_IS_OK(status)) {
 281                         DEBUG(1, ("fill_grent_mem_domain_users: "
 282                                   "lookup_usergroups failed "
 283                                   "for sid %s in domain %s (error: %s)\n",
 284                                   sid_string_dbg(pquerying_user_sid),
 285                                   domain->name,
 286                                   nt_errstr(status)));
 287                         return False;
 288                 }
 289 
 290                 for (i = 0; i < num_groups; i++) {
 291                         if (sid_equal(group_sid, &user_sids[i])) {
 292                                 /* User is in Domain Users, add their name
 293                                    as the only group member. */
 294                                 u_in_group = True;
 295                                 break;
 296                         }
 297                 }
 298         }
 299 
 300         if (u_in_group) {
 301                 size_t len = 0;
 302                 char *domainname = NULL;
 303                 char *username = NULL;
 304                 fstring name;
 305                 char *mapped_name = NULL;
 306                 enum lsa_SidType type;
 307                 struct winbindd_domain *target_domain = NULL;
 308                 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 309 
 310                 DEBUG(10,("fill_grent_mem_domain_users: "
 311                           "sid %s in 'Domain Users' in domain %s\n",
 312                           sid_string_dbg(pquerying_user_sid),
 313                           domain->name ));
 314 
 315                 status = domain->methods->sid_to_name(domain, mem_ctx,
 316                                                       pquerying_user_sid,
 317                                                       &domainname,
 318                                                       &username,
 319                                                       &type);
 320                 if (!NT_STATUS_IS_OK(status)) {
 321                         DEBUG(1, ("could not lookup username for user "
 322                                   "sid %s in domain %s (error: %s)\n",
 323                                   sid_string_dbg(pquerying_user_sid),
 324                                   domain->name,
 325                                   nt_errstr(status)));
 326                         return False;
 327                 }
 328 
 329                 target_domain = find_domain_from_name_noinit(domainname);
 330                 name_map_status = normalize_name_map(mem_ctx, target_domain,
 331                                                      username, &mapped_name);
 332 
 333                 /* Basic whitespace replacement */
 334                 if (NT_STATUS_IS_OK(name_map_status)) {
 335                         fill_domain_username(name, domainname, mapped_name, true);
 336                 }
 337                 /* Mapped to an alias */
 338                 else if (NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
 339                         fstrcpy(name, mapped_name);
 340                 }
 341                 /* no mapping done...use original name */
 342                 else {
 343                         fill_domain_username(name, domainname, username, true);
 344                 }
 345 
 346                 len = strlen(name);
 347                 buf_len = len + 1;
 348                 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
 349                         DEBUG(1, ("out of memory\n"));
 350                         return False;
 351                 }
 352                 memcpy(buf, name, buf_len);
 353 
 354                 DEBUG(10,("fill_grent_mem_domain_users: user %s in "
 355                           "'Domain Users' in domain %s\n",
 356                           name, domain->name ));
 357 
 358                 /* user is the only member */
 359                 *num_gr_mem = 1;
 360         }
 361 
 362         *gr_mem = buf;
 363         *gr_mem_len = buf_len;
 364 
 365         DEBUG(10, ("fill_grent_mem_domain_users: "
 366                    "num_mem = %u, len = %u, mem = %s\n",
 367                    (unsigned int)*num_gr_mem,
 368                    (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
 369 
 370         return True;
 371 }
 372 
 373 /***********************************************************************
 374  Add names to a list.  Assumes  a canonical version of the string
 375  in DOMAIN\user
 376 ***********************************************************************/
 377 
 378 static int namecmp( const void *a, const void *b )
     /* [<][>][^][v][top][bottom][index][help] */
 379 {
 380         return StrCaseCmp( * (char * const *) a, * (char * const *) b);
 381 }
 382 
 383 static void sort_unique_list(char ***list, uint32 *n_list)
     /* [<][>][^][v][top][bottom][index][help] */
 384 {
 385         uint32_t i;
 386 
 387         /* search for duplicates for sorting and looking for matching
 388            neighbors */
 389 
 390         qsort(*list, *n_list, sizeof(char*), QSORT_CAST namecmp);
 391 
 392         for (i=1; i < *n_list; i++) {
 393                 if (strcmp((*list)[i-1], (*list)[i]) == 0) {
 394                         memmove(&((*list)[i-1]), &((*list)[i]),
 395                                  sizeof(char*)*((*n_list)-i));
 396                         (*n_list)--;
 397                 }
 398         }
 399 }
 400 
 401 static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 402                                    char ***list, uint32 *n_list,
 403                                    char **names, uint32 n_names )
 404 {
 405         char **new_list = NULL;
 406         uint32 n_new_list = 0;
 407         int i, j;
 408 
 409         if ( !names || (n_names == 0) )
 410                 return NT_STATUS_OK;
 411 
 412         /* Alloc the maximum size we'll need */
 413 
 414         if ( *list == NULL ) {
 415                 if ((new_list = TALLOC_ARRAY(ctx, char *, n_names)) == NULL) {
 416                         return NT_STATUS_NO_MEMORY;
 417                 }
 418                 n_new_list = n_names;
 419         } else {
 420                 new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
 421                                                  (*n_list) + n_names );
 422                 if ( !new_list )
 423                         return NT_STATUS_NO_MEMORY;
 424                 n_new_list = (*n_list) + n_names;
 425         }
 426 
 427         /* Add all names */
 428 
 429         for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
 430                 new_list[i] = talloc_strdup( new_list, names[j] );
 431         }
 432 
 433         *list = new_list;
 434         *n_list = n_new_list;
 435 
 436         return NT_STATUS_OK;
 437 }
 438 
 439 /***********************************************************************
 440 ***********************************************************************/
 441 
 442 static NTSTATUS expand_groups( TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 443                                struct winbindd_domain *d,
 444                                DOM_SID *glist, uint32 n_glist,
 445                                DOM_SID **new_glist, uint32 *n_new_glist,
 446                                char ***members, uint32 *n_members )
 447 {
 448         int i, j;
 449         NTSTATUS status = NT_STATUS_OK;
 450         uint32 num_names = 0;
 451         uint32 *name_types = NULL;
 452         char **names = NULL;
 453         DOM_SID *sid_mem = NULL;
 454         TALLOC_CTX *tmp_ctx = NULL;
 455         DOM_SID *new_groups = NULL;
 456         size_t new_groups_size = 0;
 457 
 458         *members = NULL;
 459         *n_members = 0;
 460         *new_glist = NULL;
 461         *n_new_glist = 0;
 462 
 463         for ( i=0; i<n_glist; i++ ) {
 464                 tmp_ctx = talloc_new( ctx );
 465 
 466                 /* Lookup the group membership */
 467 
 468                 status = d->methods->lookup_groupmem(d, tmp_ctx,
 469                                                      &glist[i], &num_names,
 470                                                      &sid_mem, &names,
 471                                                      &name_types);
 472                 if ( !NT_STATUS_IS_OK(status) )
 473                         goto out;
 474 
 475                 /* Separate users and groups into two lists */
 476 
 477                 for ( j=0; j<num_names; j++ ) {
 478 
 479                         /* Users */
 480                         if ( name_types[j] == SID_NAME_USER ||
 481                              name_types[j] == SID_NAME_COMPUTER )
 482                         {
 483                                 status = add_names_to_list( ctx, members,
 484                                                             n_members,
 485                                                             names+j, 1 );
 486                                 if ( !NT_STATUS_IS_OK(status) )
 487                                         goto out;
 488 
 489                                 continue;
 490                         }
 491 
 492                         /* Groups */
 493                         if ( name_types[j] == SID_NAME_DOM_GRP ||
 494                              name_types[j] == SID_NAME_ALIAS )
 495                         {
 496                                 status = add_sid_to_array_unique(ctx,
 497                                                                  &sid_mem[j],
 498                                                                  &new_groups,
 499                                                                  &new_groups_size);
 500                                 if (!NT_STATUS_IS_OK(status)) {
 501                                         goto out;
 502                                 }
 503 
 504                                 continue;
 505                         }
 506                 }
 507 
 508                 TALLOC_FREE( tmp_ctx );
 509         }
 510 
 511         *new_glist = new_groups;
 512         *n_new_glist = (uint32)new_groups_size;
 513 
 514  out:
 515         TALLOC_FREE( tmp_ctx );
 516 
 517         return status;
 518 }
 519 
 520 /***********************************************************************
 521  Fill in the group membership field of a NT group given by group_sid
 522 ***********************************************************************/
 523 
 524 static bool fill_grent_mem(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 525                            struct winbindd_cli_state *state,
 526                            DOM_SID *group_sid,
 527                            enum lsa_SidType group_name_type,
 528                            size_t *num_gr_mem, char **gr_mem,
 529                            size_t *gr_mem_len)
 530 {
 531         uint32 num_names = 0;
 532         unsigned int buf_len = 0, buf_ndx = 0, i;
 533         char **names = NULL, *buf = NULL;
 534         bool result = False;
 535         TALLOC_CTX *mem_ctx;
 536         uint32 group_rid;
 537         DOM_SID *glist = NULL;
 538         DOM_SID *new_glist = NULL;
 539         uint32 n_glist, n_new_glist;
 540         int max_depth = lp_winbind_expand_groups();
 541 
 542         if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
 543                 return False;
 544 
 545         DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
 546 
 547         /* Initialize with no members */
 548 
 549         *num_gr_mem = 0;
 550 
 551         /* HACK ALERT!! This whole routine does not cope with group members
 552          * from more than one domain, ie aliases. Thus we have to work it out
 553          * ourselves in a special routine. */
 554 
 555         if (domain->internal) {
 556                 result = fill_passdb_alias_grmem(domain, group_sid,
 557                                                num_gr_mem,
 558                                                gr_mem, gr_mem_len);
 559                 goto done;
 560         }
 561 
 562         /* Verify name type */
 563 
 564         if ( !((group_name_type==SID_NAME_DOM_GRP) ||
 565                ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
 566         {
 567                 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
 568                           sid_string_dbg(group_sid),
 569                           domain->name, group_name_type));
 570                 goto done;
 571         }
 572 
 573         /* OPTIMIZATION / HACK. See comment in
 574            fill_grent_mem_domusers() */
 575 
 576         sid_peek_rid( group_sid, &group_rid );
 577         if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
 578                 result = fill_grent_mem_domusers( mem_ctx, domain, state,
 579                                                   group_sid, group_name_type,
 580                                                   num_gr_mem, gr_mem,
 581                                                   gr_mem_len );
 582                 goto done;
 583         }
 584 
 585         /* Real work goes here.  Create a list of group names to
 586            expand starting with the initial one.  Pass that to
 587            expand_groups() which returns a list of more group names
 588            to expand.  Do this up to the max search depth. */
 589 
 590         if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
 591                 result = False;
 592                 DEBUG(0,("fill_grent_mem: talloc failure!\n"));
 593                 goto done;
 594         }
 595         sid_copy( &glist[0], group_sid );
 596         n_glist = 1;
 597 
 598         for ( i=0; i<max_depth && glist; i++ ) {
 599                 uint32 n_members = 0;
 600                 char **members = NULL;
 601                 NTSTATUS nt_status;
 602                 int j;
 603 
 604                 nt_status = expand_groups( mem_ctx, domain,
 605                                            glist, n_glist,
 606                                            &new_glist, &n_new_glist,
 607                                            &members, &n_members);
 608                 if ( !NT_STATUS_IS_OK(nt_status) ) {
 609                         result = False;
 610                         goto done;
 611                 }
 612 
 613                 /* Add new group members to list.  Pass through the
 614                    alias mapping function */
 615 
 616                 for (j=0; j<n_members; j++) {
 617                         fstring name_domain, name_acct;
 618                         fstring qualified_name;
 619                         char *mapped_name = NULL;
 620                         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 621                         struct winbindd_domain *target_domain = NULL;
 622 
 623                         if (parse_domain_user(members[j], name_domain, name_acct)) {
 624                                 target_domain = find_domain_from_name_noinit(name_domain);
 625                                 /* NOW WHAT ? */
 626                         }
 627                         if (!target_domain) {
 628                                 target_domain = domain;
 629                         }
 630 
 631                         name_map_status = normalize_name_map(members, target_domain,
 632                                                              name_acct, &mapped_name);
 633 
 634                         /* Basic whitespace replacement */
 635                         if (NT_STATUS_IS_OK(name_map_status)) {
 636                                 fill_domain_username(qualified_name, name_domain,
 637                                                      mapped_name, true);
 638                                 mapped_name = qualified_name;
 639                         }
 640                         /* no mapping at all */
 641                         else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
 642                                 mapped_name = members[j];
 643                         }
 644 
 645                         nt_status = add_names_to_list( mem_ctx, &names,
 646                                                        &num_names,
 647                                                        &mapped_name, 1);
 648                         if ( !NT_STATUS_IS_OK(nt_status) ) {
 649                                 result = False;
 650                                 goto done;
 651                         }
 652                 }
 653 
 654                 TALLOC_FREE( members );
 655 
 656                 /* If we have no more groups to expand, break out
 657                    early */
 658 
 659                 if (new_glist == NULL)
 660                         break;
 661 
 662                 /* One more round */
 663                 TALLOC_FREE(glist);
 664                 glist = new_glist;
 665                 n_glist = n_new_glist;
 666         }
 667         TALLOC_FREE( glist );
 668 
 669         sort_unique_list(&names, &num_names);
 670 
 671         DEBUG(10, ("looked up %d names\n", num_names));
 672 
 673  again:
 674         /* Add members to list */
 675 
 676         for (i = 0; i < num_names; i++) {
 677                 int len;
 678 
 679                 DEBUG(10, ("processing name %s\n", names[i]));
 680 
 681                 len = strlen(names[i]);
 682 
 683                 /* Add to list or calculate buffer length */
 684 
 685                 if (!buf) {
 686                         buf_len += len + 1; /* List is comma separated */
 687                         (*num_gr_mem)++;
 688                         DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
 689                 } else {
 690                         DEBUG(10, ("appending %s at ndx %d\n",
 691                                    names[i], buf_ndx));
 692                         parse_add_domuser(&buf[buf_ndx], names[i], &len);
 693                         buf_ndx += len;
 694                         buf[buf_ndx] = ',';
 695                         buf_ndx++;
 696                 }
 697         }
 698 
 699         /* Allocate buffer */
 700 
 701         if (!buf && buf_len != 0) {
 702                 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
 703                         DEBUG(1, ("out of memory\n"));
 704                         result = False;
 705                         goto done;
 706                 }
 707                 memset(buf, 0, buf_len);
 708                 goto again;
 709         }
 710 
 711         /* Now we're done */
 712 
 713         if (buf && buf_ndx > 0) {
 714                 buf[buf_ndx - 1] = '\0';
 715         }
 716 
 717         *gr_mem = buf;
 718         *gr_mem_len = buf_len;
 719 
 720         DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
 721                    (unsigned int)*num_gr_mem,
 722                    (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
 723         result = True;
 724 
 725 done:
 726 
 727         talloc_destroy(mem_ctx);
 728 
 729         DEBUG(10, ("fill_grent_mem returning %d\n", result));
 730 
 731         return result;
 732 }
 733 
 734 static void winbindd_getgrsid(struct winbindd_cli_state *state, DOM_SID group_sid);
 735 
 736 static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
     /* [<][>][^][v][top][bottom][index][help] */
 737                            enum lsa_SidType type )
 738 {
 739         struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
 740 
 741         if (!success) {
 742                 DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
 743                 request_error(state);
 744                 return;
 745         }
 746 
 747         if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
 748                 DEBUG(5,("getgrnam_recv: not a group!\n"));
 749                 request_error(state);
 750                 return;
 751         }
 752 
 753         winbindd_getgrsid( state, *sid );
 754 }
 755 
 756 
 757 /* Return a group structure from a group name */
 758 
 759 void winbindd_getgrnam(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 760 {
 761         struct winbindd_domain *domain;
 762         fstring name_domain, name_group;
 763         char *tmp;
 764         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 765 
 766         /* Ensure null termination */
 767         state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
 768 
 769         DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
 770                   state->request.data.groupname));
 771 
 772         nt_status = normalize_name_unmap(state->mem_ctx,
 773                                          state->request.data.groupname,
 774                                          &tmp);
 775         /* If we didn't map anything in the above call, just reset the
 776            tmp pointer to the original string */
 777         if (!NT_STATUS_IS_OK(nt_status) &&
 778             !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
 779         {
 780                 tmp = state->request.data.groupname;
 781         }
 782 
 783         /* Parse domain and groupname */
 784 
 785         memset(name_group, 0, sizeof(name_group));
 786 
 787         name_domain[0] = '\0';
 788         name_group[0] = '\0';
 789 
 790         parse_domain_user(tmp, name_domain, name_group);
 791 
 792         /* if no domain or our local domain and no local tdb group, default to
 793          * our local domain for aliases */
 794 
 795         if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
 796                 fstrcpy(name_domain, get_global_sam_name());
 797         }
 798 
 799         /* Get info for the domain */
 800 
 801         if ((domain = find_domain_from_name_noinit(name_domain)) == NULL) {
 802                 DEBUG(3, ("could not get domain sid for domain %s\n",
 803                           name_domain));
 804                 request_error(state);
 805                 return;
 806         }
 807         /* should we deal with users for our domain? */
 808 
 809         if ( lp_winbind_trusted_domains_only() && domain->primary) {
 810                 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
 811                          "getgrnam() for %s\\%s.\n", name_domain, name_group));
 812                 request_error(state);
 813                 return;
 814         }
 815 
 816         /* Get rid and name type from name */
 817 
 818         fstrcpy( name_group, tmp );
 819 
 820         winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
 821                                    getgrnam_recv, WINBINDD_GETGRNAM, state );
 822 }
 823 
 824 struct getgrsid_state {
 825         struct winbindd_cli_state *state;
 826         struct winbindd_domain *domain;
 827         char *group_name;
 828         enum lsa_SidType group_type;
 829         uid_t gid;
 830         DOM_SID group_sid;
 831 };
 832 
 833 static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 834 {
 835         struct getgrsid_state *s =
 836                 (struct getgrsid_state *)private_data;
 837         struct winbindd_domain *domain;
 838         size_t gr_mem_len;
 839         size_t num_gr_mem;
 840         char *gr_mem;
 841         fstring dom_name, group_name;
 842 
 843         if (!success) {
 844                 DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
 845                 request_error(s->state);
 846                 return;
 847         }
 848 
 849         s->gid = gid;
 850 
 851         if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
 852                 DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
 853                 request_error(s->state);
 854                 return;
 855         }
 856 
 857 
 858         /* Fill in group structure */
 859 
 860         if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
 861                 DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
 862                 request_error(s->state);
 863                 return;
 864         }
 865 
 866         if (!fill_grent(s->state->mem_ctx, &s->state->response.data.gr,
 867                         dom_name, group_name, gid) ||
 868             !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
 869                             &num_gr_mem, &gr_mem, &gr_mem_len))
 870         {
 871                 request_error(s->state);
 872                 return;
 873         }
 874 
 875         s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
 876 
 877         /* Group membership lives at start of extra data */
 878 
 879         s->state->response.data.gr.gr_mem_ofs = 0;
 880 
 881         s->state->response.length += gr_mem_len;
 882         s->state->response.extra_data.data = gr_mem;
 883 
 884         request_ok(s->state);
 885 }
 886 
 887 static void getgrsid_lookupsid_recv( void *private_data, bool success,
     /* [<][>][^][v][top][bottom][index][help] */
 888                                      const char *dom_name, const char *name,
 889                                      enum lsa_SidType name_type )
 890 {
 891         struct getgrsid_state *s = (struct getgrsid_state *)private_data;
 892         char *mapped_name = NULL;
 893         fstring raw_name;
 894         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 895 
 896         if (!success) {
 897                 DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
 898                 request_error(s->state);
 899                 return;
 900         }
 901 
 902         /* either it's a domain group, a domain local group, or a
 903            local group in an internal domain */
 904 
 905         if ( !( (name_type==SID_NAME_DOM_GRP) ||
 906                 ((name_type==SID_NAME_ALIAS) &&
 907                  (s->domain->primary || s->domain->internal)) ) )
 908         {
 909                 DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
 910                           dom_name, name, name_type));
 911                 request_error(s->state);
 912                 return;
 913         }
 914 
 915         /* normalize the name and ensure that we have the DOM\name
 916           coming out of here */
 917 
 918         fstrcpy(raw_name, name);
 919 
 920         nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
 921                                          &mapped_name);
 922 
 923         /* basic whitespace reversal */
 924         if (NT_STATUS_IS_OK(nt_status)) {
 925                 s->group_name = talloc_asprintf(s->state->mem_ctx,
 926                                                 "%s%c%s",
 927                                                 dom_name,
 928                                                 *lp_winbind_separator(),
 929                                                 mapped_name);
 930         }
 931         /* mapped from alias */
 932         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 933                 s->group_name = mapped_name;
 934         }
 935         /* no mapping at all.  use original string */
 936         else {
 937                 s->group_name = talloc_asprintf(s->state->mem_ctx,
 938                                                 "%s%c%s",
 939                                                 dom_name,
 940                                                 *lp_winbind_separator(),
 941                                                 raw_name);
 942         }
 943 
 944         if (s->group_name == NULL) {
 945                 DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
 946                 request_error(s->state);
 947                 return;
 948         }
 949 
 950         s->group_type = name_type;
 951 
 952         winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
 953                                getgrsid_sid2gid_recv, s);
 954 }
 955 
 956 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
     /* [<][>][^][v][top][bottom][index][help] */
 957 {
 958         struct getgrsid_state *s;
 959 
 960         if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
 961                 DEBUG(0, ("talloc failed\n"));
 962                 request_error(state);
 963                 return;
 964         }
 965 
 966         s->state = state;
 967 
 968         if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
 969                 DEBUG(3, ("Could not find domain for sid %s\n",
 970                           sid_string_dbg(&group_sid)));
 971                 request_error(state);
 972                 return;
 973         }
 974 
 975         sid_copy(&s->group_sid, &group_sid);
 976 
 977         winbindd_lookupsid_async( s->state->mem_ctx,  &group_sid,
 978                                   getgrsid_lookupsid_recv, s );
 979 }
 980 
 981 
 982 static void getgrgid_recv(void *private_data, bool success, const char *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 983 {
 984         struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
 985         enum lsa_SidType name_type;
 986         DOM_SID group_sid;
 987 
 988         if (success) {
 989                 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
 990                           (unsigned long)(state->request.data.gid), sid));
 991 
 992                 if (!string_to_sid(&group_sid, sid)) {
 993                         DEBUG(1,("getgrgid_recv: Could not convert sid %s "
 994                                 "from string\n", sid));
 995                         request_error(state);
 996                         return;
 997                 }
 998 
 999                 winbindd_getgrsid(state, group_sid);
1000                 return;
1001         }
1002 
1003         /* Ok, this might be "ours", i.e. an alias */
1004         if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
1005             lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
1006             (name_type == SID_NAME_ALIAS)) {
1007                 /* Hey, got an alias */
1008                 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
1009                           (unsigned long)(state->request.data.gid), sid));
1010                 winbindd_getgrsid(state, group_sid);
1011                 return;
1012         }
1013 
1014         DEBUG(1, ("could not convert gid %lu to sid\n",
1015                   (unsigned long)state->request.data.gid));
1016         request_error(state);
1017 }
1018 
1019 /* Return a group structure from a gid number */
1020 void winbindd_getgrgid(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1021 {
1022         gid_t gid = state->request.data.gid;
1023 
1024         DEBUG(3, ("[%5lu]: getgrgid %lu\n",
1025                   (unsigned long)state->pid,
1026                   (unsigned long)gid));
1027 
1028         /* always use the async interface */
1029         winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
1030 }
1031 
1032 /*
1033  * set/get/endgrent functions
1034  */
1035 
1036 /* "Rewind" file pointer for group database enumeration */
1037 
1038 static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1039 {
1040         struct winbindd_domain *domain;
1041 
1042         DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
1043 
1044         /* Check user has enabled this */
1045 
1046         if (!lp_winbind_enum_groups()) {
1047                 return False;
1048         }
1049 
1050         /* Free old static data if it exists */
1051 
1052         if (state->getgrent_state != NULL) {
1053                 free_getent_state(state->getgrent_state);
1054                 state->getgrent_state = NULL;
1055         }
1056 
1057         /* Create sam pipes for each domain we know about */
1058 
1059         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1060                 struct getent_state *domain_state;
1061 
1062                 /* Create a state record for this domain */
1063 
1064                 /* don't add our domaina if we are a PDC or if we
1065                    are a member of a Samba domain */
1066 
1067                 if ( lp_winbind_trusted_domains_only() && domain->primary )
1068                 {
1069                         continue;
1070                 }
1071 
1072                 domain_state = SMB_MALLOC_P(struct getent_state);
1073                 if (!domain_state) {
1074                         DEBUG(1, ("winbindd_setgrent: "
1075                                   "malloc failed for domain_state!\n"));
1076                         return False;
1077                 }
1078 
1079                 ZERO_STRUCTP(domain_state);
1080 
1081                 fstrcpy(domain_state->domain_name, domain->name);
1082 
1083                 /* Add to list of open domains */
1084 
1085                 DLIST_ADD(state->getgrent_state, domain_state);
1086         }
1087 
1088         state->getgrent_initialized = True;
1089         return True;
1090 }
1091 
1092 void winbindd_setgrent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1093 {
1094         if (winbindd_setgrent_internal(state)) {
1095                 request_ok(state);
1096         } else {
1097                 request_error(state);
1098         }
1099 }
1100 
1101 /* Close file pointer to ntdom group database */
1102 
1103 void winbindd_endgrent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1104 {
1105         DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
1106 
1107         free_getent_state(state->getgrent_state);
1108         state->getgrent_initialized = False;
1109         state->getgrent_state = NULL;
1110         request_ok(state);
1111 }
1112 
1113 /* Get the list of domain groups and domain aliases for a domain.  We fill in
1114    the sam_entries and num_sam_entries fields with domain group information.
1115    Return True if some groups were returned, False otherwise. */
1116 
1117 bool get_sam_group_entries(struct getent_state *ent)
     /* [<][>][^][v][top][bottom][index][help] */
1118 {
1119         NTSTATUS status;
1120         uint32 num_entries;
1121         struct acct_info *name_list = NULL;
1122         TALLOC_CTX *mem_ctx;
1123         bool result = False;
1124         struct acct_info *sam_grp_entries = NULL;
1125         struct winbindd_domain *domain;
1126 
1127         if (ent->got_sam_entries)
1128                 return False;
1129 
1130         if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
1131                                           ent->domain_name))) {
1132                 DEBUG(1, ("get_sam_group_entries: "
1133                           "could not create talloc context!\n"));
1134                 return False;
1135         }
1136 
1137         /* Free any existing group info */
1138 
1139         SAFE_FREE(ent->sam_entries);
1140         ent->num_sam_entries = 0;
1141         ent->got_sam_entries = True;
1142 
1143         /* Enumerate domain groups */
1144 
1145         num_entries = 0;
1146 
1147         if (!(domain = find_domain_from_name(ent->domain_name))) {
1148                 DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
1149                           ent->domain_name));
1150                 goto done;
1151         }
1152 
1153         /* always get the domain global groups */
1154 
1155         status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
1156                                                   &sam_grp_entries);
1157 
1158         if (!NT_STATUS_IS_OK(status)) {
1159                 DEBUG(3, ("get_sam_group_entries: "
1160                           "could not enumerate domain groups! Error: %s\n",
1161                           nt_errstr(status)));
1162                 result = False;
1163                 goto done;
1164         }
1165 
1166         /* Copy entries into return buffer */
1167 
1168         if (num_entries) {
1169                 name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
1170                 if (!name_list) {
1171                         DEBUG(0,("get_sam_group_entries: Failed to malloc "
1172                                  "memory for %d domain groups!\n",
1173                                  num_entries));
1174                         result = False;
1175                         goto done;
1176                 }
1177                 memcpy(name_list, sam_grp_entries,
1178                         num_entries * sizeof(struct acct_info));
1179         }
1180 
1181         ent->num_sam_entries = num_entries;
1182 
1183         /* get the domain local groups if we are a member of a native win2k
1184          * domain and are not using LDAP to get the groups */
1185 
1186         if ( ( lp_security() != SEC_ADS && domain->native_mode
1187                 && domain->primary) || domain->internal )
1188         {
1189                 DEBUG(4,("get_sam_group_entries: %s domain; "
1190                          "enumerating local groups as well\n",
1191                          domain->native_mode ? "Native Mode 2k":
1192                                                 "BUILTIN or local"));
1193 
1194                 status = domain->methods->enum_local_groups(domain, mem_ctx,
1195                                                             &num_entries,
1196                                                             &sam_grp_entries);
1197 
1198                 if ( !NT_STATUS_IS_OK(status) ) {
1199                         DEBUG(3,("get_sam_group_entries: "
1200                                 "Failed to enumerate "
1201                                 "domain local groups with error %s!\n",
1202                                 nt_errstr(status)));
1203                         num_entries = 0;
1204                 }
1205                 else
1206                         DEBUG(4,("get_sam_group_entries: "
1207                                  "Returned %d local groups\n",
1208                                  num_entries));
1209 
1210                 /* Copy entries into return buffer */
1211 
1212                 if ( num_entries ) {
1213                         name_list = SMB_REALLOC_ARRAY(name_list,
1214                                                       struct acct_info,
1215                                                       ent->num_sam_entries+
1216                                                         num_entries);
1217                         if (!name_list) {
1218                                 DEBUG(0,("get_sam_group_entries: "
1219                                          "Failed to realloc more memory "
1220                                          "for %d local groups!\n",
1221                                          num_entries));
1222                                 result = False;
1223                                 goto done;
1224                         }
1225 
1226                         memcpy(&name_list[ent->num_sam_entries],
1227                                 sam_grp_entries,
1228                                 num_entries * sizeof(struct acct_info));
1229                 }
1230 
1231                 ent->num_sam_entries += num_entries;
1232         }
1233 
1234 
1235         /* Fill in remaining fields */
1236 
1237         ent->sam_entries = name_list;
1238         ent->sam_entry_index = 0;
1239 
1240         result = (ent->num_sam_entries > 0);
1241 
1242  done:
1243         talloc_destroy(mem_ctx);
1244 
1245         return result;
1246 }
1247 
1248 /* Fetch next group entry from ntdom database */
1249 
1250 #define MAX_GETGRENT_GROUPS 500
1251 
1252 void winbindd_getgrent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1253 {
1254         struct getent_state *ent;
1255         struct winbindd_gr *group_list = NULL;
1256         int num_groups, group_list_ndx, gr_mem_list_len = 0;
1257         char *gr_mem_list = NULL;
1258 
1259         DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
1260 
1261         /* Check user has enabled this */
1262 
1263         if (!lp_winbind_enum_groups()) {
1264                 request_error(state);
1265                 return;
1266         }
1267 
1268         num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
1269 
1270         if (num_groups == 0) {
1271                 request_error(state);
1272                 return;
1273         }
1274 
1275         group_list = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups);
1276         if (!group_list) {
1277                 request_error(state);
1278                 return;
1279         }
1280         /* will be freed by process_request() */
1281         state->response.extra_data.data = group_list;
1282 
1283         memset(state->response.extra_data.data, '\0',
1284                 num_groups * sizeof(struct winbindd_gr) );
1285 
1286         state->response.data.num_entries = 0;
1287 
1288         if (!state->getgrent_initialized)
1289                 winbindd_setgrent_internal(state);
1290 
1291         if (!(ent = state->getgrent_state)) {
1292                 request_error(state);
1293                 return;
1294         }
1295 
1296         /* Start sending back groups */
1297 
1298         for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
1299                 struct acct_info *name_list = NULL;
1300                 fstring domain_group_name;
1301                 uint32 result;
1302                 gid_t group_gid;
1303                 size_t gr_mem_len;
1304                 char *gr_mem;
1305                 DOM_SID group_sid;
1306                 struct winbindd_domain *domain;
1307 
1308                 /* Do we need to fetch another chunk of groups? */
1309 
1310         tryagain:
1311 
1312                 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
1313                            ent->sam_entry_index, ent->num_sam_entries));
1314 
1315                 if (ent->num_sam_entries == ent->sam_entry_index) {
1316 
1317                         while(ent && !get_sam_group_entries(ent)) {
1318                                 struct getent_state *next_ent;
1319 
1320                                 DEBUG(10, ("freeing state info for domain %s\n",
1321                                            ent->domain_name));
1322 
1323                                 /* Free state information for this domain */
1324 
1325                                 SAFE_FREE(ent->sam_entries);
1326 
1327                                 next_ent = ent->next;
1328                                 DLIST_REMOVE(state->getgrent_state, ent);
1329 
1330                                 SAFE_FREE(ent);
1331                                 ent = next_ent;
1332                         }
1333 
1334                         /* No more domains */
1335 
1336                         if (!ent)
1337                                 break;
1338                 }
1339 
1340                 name_list = (struct acct_info *)ent->sam_entries;
1341 
1342                 if (!(domain = find_domain_from_name(ent->domain_name))) {
1343                         DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
1344                                   ent->domain_name));
1345                         result = False;
1346                         goto done;
1347                 }
1348 
1349                 /* Lookup group info */
1350 
1351                 sid_copy(&group_sid, &domain->sid);
1352                 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1353 
1354                 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config
1355                                                       ? domain->name : "",
1356                                                       &group_sid, &group_gid)))
1357                 {
1358                         union unid_t id;
1359                         enum lsa_SidType type;
1360 
1361                         DEBUG(10, ("SID %s not in idmap\n",
1362                                    sid_string_dbg(&group_sid)));
1363 
1364                         if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1365                                 DEBUG(1,("could not look up gid for group %s\n",
1366                                          name_list[ent->sam_entry_index].acct_name));
1367                                 ent->sam_entry_index++;
1368                                 goto tryagain;
1369                         }
1370 
1371                         if ((type != SID_NAME_DOM_GRP) &&
1372                             (type != SID_NAME_ALIAS) &&
1373                             (type != SID_NAME_WKN_GRP)) {
1374                                 DEBUG(1, ("Group %s is a %s, not a group\n",
1375                                           sid_type_lookup(type),
1376                                           name_list[ent->sam_entry_index].acct_name));
1377                                 ent->sam_entry_index++;
1378                                 goto tryagain;
1379                         }
1380                         group_gid = id.gid;
1381                 }
1382 
1383                 DEBUG(10, ("got gid %lu for group %lu\n",
1384                            (unsigned long)group_gid,
1385                            (unsigned long)name_list[ent->sam_entry_index].rid));
1386 
1387                 /* Fill in group entry */
1388 
1389                 fill_domain_username(domain_group_name, ent->domain_name,
1390                          name_list[ent->sam_entry_index].acct_name, True);
1391 
1392                 result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
1393                                     ent->domain_name,
1394                                     name_list[ent->sam_entry_index].acct_name,
1395                                     group_gid);
1396 
1397                 /* Fill in group membership entry */
1398 
1399                 if (result) {
1400                         size_t num_gr_mem = 0;
1401                         DOM_SID member_sid;
1402                         group_list[group_list_ndx].num_gr_mem = 0;
1403                         gr_mem = NULL;
1404                         gr_mem_len = 0;
1405 
1406                         /* Get group membership */
1407                         if (state->request.cmd == WINBINDD_GETGRLST) {
1408                                 result = True;
1409                         } else {
1410                                 sid_copy(&member_sid, &domain->sid);
1411                                 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1412                                 result = fill_grent_mem(
1413                                         domain,
1414                                         NULL,
1415                                         &member_sid,
1416                                         SID_NAME_DOM_GRP,
1417                                         &num_gr_mem,
1418                                         &gr_mem, &gr_mem_len);
1419 
1420                                 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1421                         }
1422                 }
1423 
1424                 if (result) {
1425                         /* Append to group membership list */
1426                         gr_mem_list = (char *)SMB_REALLOC(
1427                                 gr_mem_list, gr_mem_list_len + gr_mem_len);
1428 
1429                         if (!gr_mem_list &&
1430                             (group_list[group_list_ndx].num_gr_mem != 0)) {
1431                                 DEBUG(0, ("out of memory\n"));
1432                                 gr_mem_list_len = 0;
1433                                 break;
1434                         }
1435 
1436                         DEBUG(10, ("list_len = %d, mem_len = %u\n",
1437                                    gr_mem_list_len, (unsigned int)gr_mem_len));
1438 
1439                         memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1440                                gr_mem_len);
1441 
1442                         SAFE_FREE(gr_mem);
1443 
1444                         group_list[group_list_ndx].gr_mem_ofs =
1445                                 gr_mem_list_len;
1446 
1447                         gr_mem_list_len += gr_mem_len;
1448                 }
1449 
1450                 ent->sam_entry_index++;
1451 
1452                 /* Add group to return list */
1453 
1454                 if (result) {
1455 
1456                         DEBUG(10, ("adding group num_entries = %d\n",
1457                                    state->response.data.num_entries));
1458 
1459                         group_list_ndx++;
1460                         state->response.data.num_entries++;
1461 
1462                         state->response.length +=
1463                                 sizeof(struct winbindd_gr);
1464 
1465                 } else {
1466                         DEBUG(0, ("could not lookup domain group %s\n",
1467                                   domain_group_name));
1468                 }
1469         }
1470 
1471         /* Copy the list of group memberships to the end of the extra data */
1472 
1473         if (group_list_ndx == 0)
1474                 goto done;
1475 
1476         state->response.extra_data.data = SMB_REALLOC(
1477                 state->response.extra_data.data,
1478                 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1479 
1480         if (!state->response.extra_data.data) {
1481                 DEBUG(0, ("out of memory\n"));
1482                 group_list_ndx = 0;
1483                 SAFE_FREE(gr_mem_list);
1484                 request_error(state);
1485                 return;
1486         }
1487 
1488         memcpy(&((char *)state->response.extra_data.data)
1489                [group_list_ndx * sizeof(struct winbindd_gr)],
1490                gr_mem_list, gr_mem_list_len);
1491 
1492         state->response.length += gr_mem_list_len;
1493 
1494         DEBUG(10, ("returning %d groups, length = %d\n",
1495                    group_list_ndx, gr_mem_list_len));
1496 
1497         /* Out of domains */
1498 
1499  done:
1500 
1501         SAFE_FREE(gr_mem_list);
1502 
1503         if (group_list_ndx > 0)
1504                 request_ok(state);
1505         else
1506                 request_error(state);
1507 }
1508 
1509 /* List domain groups without mapping to unix ids */
1510 void winbindd_list_groups(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1511 {
1512         winbindd_list_ent(state, LIST_GROUPS);
1513 }
1514 
1515 /* Get user supplementary groups.  This is much quicker than trying to
1516    invert the groups database.  We merge the groups from the gids and
1517    other_sids info3 fields as trusted domain, universal group
1518    memberships, and nested groups (win2k native mode only) are not
1519    returned by the getgroups RPC call but are present in the info3. */
1520 
1521 struct getgroups_state {
1522         struct winbindd_cli_state *state;
1523         struct winbindd_domain *domain;
1524         char *domname;
1525         char *username;
1526         DOM_SID user_sid;
1527 
1528         const DOM_SID *token_sids;
1529         size_t i, num_token_sids;
1530 
1531         gid_t *token_gids;
1532         size_t num_token_gids;
1533 };
1534 
1535 static void getgroups_usersid_recv(void *private_data, bool success,
1536                                    const DOM_SID *sid, enum lsa_SidType type);
1537 static void getgroups_tokensids_recv(void *private_data, bool success,
1538                                      DOM_SID *token_sids, size_t num_token_sids);
1539 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
1540 
1541 void winbindd_getgroups(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1542 {
1543         struct getgroups_state *s;
1544         char *real_name = NULL;
1545         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1546 
1547         /* Ensure null termination */
1548         state->request.data.username
1549                 [sizeof(state->request.data.username)-1]='\0';
1550 
1551         DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1552                   state->request.data.username));
1553 
1554         /* Parse domain and username */
1555 
1556         s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1557         if (s == NULL) {
1558                 DEBUG(0, ("talloc failed\n"));
1559                 request_error(state);
1560                 return;
1561         }
1562 
1563         s->state = state;
1564 
1565         nt_status = normalize_name_unmap(state->mem_ctx,
1566                                          state->request.data.username,
1567                                          &real_name);
1568 
1569         /* Reset the real_name pointer if we didn't do anything
1570            productive in the above call */
1571         if (!NT_STATUS_IS_OK(nt_status) &&
1572             !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
1573         {
1574                 real_name = state->request.data.username;
1575         }
1576 
1577         if (!parse_domain_user_talloc(state->mem_ctx, real_name,
1578                                       &s->domname, &s->username)) {
1579                 DEBUG(5, ("Could not parse domain user: %s\n",
1580                           real_name));
1581 
1582                 /* error out if we do not have nested group support */
1583 
1584                 if ( !lp_winbind_nested_groups() ) {
1585                         request_error(state);
1586                         return;
1587                 }
1588 
1589                 s->domname = talloc_strdup(state->mem_ctx,
1590                                            get_global_sam_name());
1591                 s->username = talloc_strdup(state->mem_ctx,
1592                                             state->request.data.username);
1593         }
1594 
1595         /* Get info for the domain (either by short domain name or
1596            DNS name in the case of a UPN) */
1597 
1598         s->domain = find_domain_from_name_noinit(s->domname);
1599         if (!s->domain) {
1600                 char *p = strchr(s->username, '@');
1601 
1602                 if (p) {
1603                         s->domain = find_domain_from_name_noinit(p+1);
1604                 }
1605 
1606         }
1607 
1608         if (s->domain == NULL) {
1609                 DEBUG(7, ("could not find domain entry for domain %s\n",
1610                           s->domname));
1611                 request_error(state);
1612                 return;
1613         }
1614 
1615         if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1616                 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1617                          "getgroups() for %s\\%s.\n", s->domname,
1618                          s->username));
1619                 request_error(state);
1620                 return;
1621         }
1622 
1623         /* Get rid and name type from name.  The following costs 1 packet */
1624 
1625         winbindd_lookupname_async(state->mem_ctx,
1626                                   s->domname, s->username,
1627                                   getgroups_usersid_recv,
1628                                   WINBINDD_GETGROUPS, s);
1629 }
1630 
1631 static void getgroups_usersid_recv(void *private_data, bool success,
     /* [<][>][^][v][top][bottom][index][help] */
1632                                    const DOM_SID *sid, enum lsa_SidType type)
1633 {
1634         struct getgroups_state *s =
1635                 (struct getgroups_state *)private_data;
1636 
1637         if ((!success) ||
1638             ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1639                 request_error(s->state);
1640                 return;
1641         }
1642 
1643         sid_copy(&s->user_sid, sid);
1644 
1645         winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1646                                 getgroups_tokensids_recv, s);
1647 }
1648 
1649 static void getgroups_tokensids_recv(void *private_data, bool success,
     /* [<][>][^][v][top][bottom][index][help] */
1650                                      DOM_SID *token_sids, size_t num_token_sids)
1651 {
1652         struct getgroups_state *s =
1653                 (struct getgroups_state *)private_data;
1654 
1655         /* We need at least the user sid and the primary group in the token,
1656          * otherwise it's an error */
1657 
1658         if ((!success) || (num_token_sids < 2)) {
1659                 request_error(s->state);
1660                 return;
1661         }
1662 
1663         s->token_sids = token_sids;
1664         s->num_token_sids = num_token_sids;
1665         s->i = 0;
1666 
1667         s->token_gids = NULL;
1668         s->num_token_gids = 0;
1669 
1670         getgroups_sid2gid_recv(s, False, 0);
1671 }
1672 
1673 static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
1674 {
1675         struct getgroups_state *s =
1676                 (struct getgroups_state *)private_data;
1677 
1678         if (success) {
1679                 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1680                                         &s->token_gids,
1681                                         &s->num_token_gids)) {
1682                         return;
1683                 }
1684         }
1685 
1686         if (s->i < s->num_token_sids) {
1687                 const DOM_SID *sid = &s->token_sids[s->i];
1688                 s->i += 1;
1689 
1690                 if (sid_equal(sid, &s->user_sid)) {
1691                         getgroups_sid2gid_recv(s, False, 0);
1692                         return;
1693                 }
1694 
1695                 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1696                                        getgroups_sid2gid_recv, s);
1697                 return;
1698         }
1699 
1700         s->state->response.data.num_entries = s->num_token_gids;
1701         if (s->num_token_gids) {
1702                 /* s->token_gids are talloced */
1703                 s->state->response.extra_data.data =
1704                         smb_xmemdup(s->token_gids,
1705                                         s->num_token_gids * sizeof(gid_t));
1706                 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1707         }
1708         request_ok(s->state);
1709 }
1710 
1711 /* Get user supplementary sids. This is equivalent to the
1712    winbindd_getgroups() function but it involves a SID->SIDs mapping
1713    rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1714    idmap. This call is designed to be used with applications that need
1715    to do ACL evaluation themselves. Note that the cached info3 data is
1716    not used
1717 
1718    this function assumes that the SID that comes in is a user SID. If
1719    you pass in another type of SID then you may get unpredictable
1720    results.
1721 */
1722 
1723 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
1724                              size_t num_sids);
1725 
1726 void winbindd_getusersids(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1727 {
1728         DOM_SID *user_sid;
1729 
1730         /* Ensure null termination */
1731         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1732 
1733         user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1734         if (user_sid == NULL) {
1735                 DEBUG(1, ("talloc failed\n"));
1736                 request_error(state);
1737                 return;
1738         }
1739 
1740         if (!string_to_sid(user_sid, state->request.data.sid)) {
1741                 DEBUG(1, ("Could not get convert sid %s from string\n",
1742                           state->request.data.sid));
1743                 request_error(state);
1744                 return;
1745         }
1746 
1747         winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1748                                 state);
1749 }
1750 
1751 static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
     /* [<][>][^][v][top][bottom][index][help] */
1752                              size_t num_sids)
1753 {
1754         struct winbindd_cli_state *state =
1755                 (struct winbindd_cli_state *)private_data;
1756         char *ret = NULL;
1757         unsigned ofs, ret_size = 0;
1758         size_t i;
1759 
1760         if (!success) {
1761                 request_error(state);
1762                 return;
1763         }
1764 
1765         /* work out the response size */
1766         for (i = 0; i < num_sids; i++) {
1767                 fstring s;
1768                 sid_to_fstring(s, &sids[i]);
1769                 ret_size += strlen(s) + 1;
1770         }
1771 
1772         /* build the reply */
1773         ret = (char *)SMB_MALLOC(ret_size);
1774         if (!ret) {
1775                 DEBUG(0, ("malloc failed\n"));
1776                 request_error(state);
1777                 return;
1778         }
1779         ofs = 0;
1780         for (i = 0; i < num_sids; i++) {
1781                 fstring s;
1782                 sid_to_fstring(s, &sids[i]);
1783                 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1784                 ofs += strlen(ret+ofs) + 1;
1785         }
1786 
1787         /* Send data back to client */
1788         state->response.data.num_entries = num_sids;
1789         state->response.extra_data.data = ret;
1790         state->response.length += ret_size;
1791         request_ok(state);
1792 }
1793 
1794 void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1795 {
1796         DOM_SID user_sid;
1797         struct winbindd_domain *domain;
1798 
1799         /* Ensure null termination */
1800         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1801 
1802         if (!string_to_sid(&user_sid, state->request.data.sid)) {
1803                 DEBUG(1, ("Could not get convert sid %s from string\n",
1804                           state->request.data.sid));
1805                 request_error(state);
1806                 return;
1807         }
1808 
1809         /* Get info for the domain */
1810         if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1811                 DEBUG(0,("could not find domain entry for sid %s\n",
1812                          sid_string_dbg(&user_sid)));
1813                 request_error(state);
1814                 return;
1815         }
1816 
1817         sendto_domain(state, domain);
1818 }
1819 
1820 enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1821                                                     struct winbindd_cli_state *state)
1822 {
1823         DOM_SID user_sid;
1824         NTSTATUS status;
1825 
1826         char *sidstring;
1827         ssize_t len;
1828         DOM_SID *groups;
1829         uint32 num_groups;
1830 
1831         /* Ensure null termination */
1832         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1833 
1834         if (!string_to_sid(&user_sid, state->request.data.sid)) {
1835                 DEBUG(1, ("Could not get convert sid %s from string\n",
1836                           state->request.data.sid));
1837                 return WINBINDD_ERROR;
1838         }
1839 
1840         status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1841                                                     &user_sid, &num_groups,
1842                                                     &groups);
1843         if (!NT_STATUS_IS_OK(status))
1844                 return WINBINDD_ERROR;
1845 
1846         if (num_groups == 0) {
1847                 state->response.data.num_entries = 0;
1848                 state->response.extra_data.data = NULL;
1849                 return WINBINDD_OK;
1850         }
1851 
1852         if (!print_sidlist(state->mem_ctx,
1853                            groups, num_groups,
1854                            &sidstring, &len)) {
1855                 DEBUG(0, ("talloc failed\n"));
1856                 return WINBINDD_ERROR;
1857         }
1858 
1859         state->response.extra_data.data = SMB_STRDUP(sidstring);
1860         if (!state->response.extra_data.data) {
1861                 return WINBINDD_ERROR;
1862         }
1863         state->response.length += len+1;
1864         state->response.data.num_entries = num_groups;
1865 
1866         return WINBINDD_OK;
1867 }
1868 
1869 void winbindd_getsidaliases(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1870 {
1871         DOM_SID domain_sid;
1872         struct winbindd_domain *domain;
1873 
1874         /* Ensure null termination */
1875         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1876 
1877         if (!string_to_sid(&domain_sid, state->request.data.sid)) {
1878                 DEBUG(1, ("Could not get convert sid %s from string\n",
1879                           state->request.data.sid));
1880                 request_error(state);
1881                 return;
1882         }
1883 
1884         /* Get info for the domain */
1885         if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) {
1886                 DEBUG(0,("could not find domain entry for sid %s\n",
1887                          sid_string_dbg(&domain_sid)));
1888                 request_error(state);
1889                 return;
1890         }
1891 
1892         sendto_domain(state, domain);
1893 }
1894 
1895 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1896                                                  struct winbindd_cli_state *state)
1897 {
1898         DOM_SID *sids = NULL;
1899         size_t num_sids = 0;
1900         char *sidstr = NULL;
1901         ssize_t len;
1902         size_t i;
1903         uint32 num_aliases;
1904         uint32 *alias_rids;
1905         NTSTATUS result;
1906 
1907         DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
1908 
1909         sidstr = state->request.extra_data.data;
1910         if (sidstr == NULL) {
1911                 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
1912                 if (!sidstr) {
1913                         DEBUG(0, ("Out of memory\n"));
1914                         return WINBINDD_ERROR;
1915                 }
1916         }
1917 
1918         DEBUG(10, ("Sidlist: %s\n", sidstr));
1919 
1920         if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
1921                 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
1922                 return WINBINDD_ERROR;
1923         }
1924 
1925         num_aliases = 0;
1926         alias_rids = NULL;
1927 
1928         result = domain->methods->lookup_useraliases(domain,
1929                                                      state->mem_ctx,
1930                                                      num_sids, sids,
1931                                                      &num_aliases,
1932                                                      &alias_rids);
1933 
1934         if (!NT_STATUS_IS_OK(result)) {
1935                 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1936                           nt_errstr(result)));
1937                 return WINBINDD_ERROR;
1938         }
1939 
1940         num_sids = 0;
1941         sids = NULL;
1942         sidstr = NULL;
1943 
1944         DEBUG(10, ("Got %d aliases\n", num_aliases));
1945 
1946         for (i=0; i<num_aliases; i++) {
1947                 DOM_SID sid;
1948                 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
1949                 sid_copy(&sid, &domain->sid);
1950                 sid_append_rid(&sid, alias_rids[i]);
1951                 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
1952                                           &num_sids);
1953                 if (!NT_STATUS_IS_OK(result)) {
1954                         return WINBINDD_ERROR;
1955                 }
1956         }
1957 
1958 
1959         if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
1960                 DEBUG(0, ("Could not print_sidlist\n"));
1961                 state->response.extra_data.data = NULL;
1962                 return WINBINDD_ERROR;
1963         }
1964 
1965         state->response.extra_data.data = NULL;
1966 
1967         if (sidstr) {
1968                 state->response.extra_data.data = SMB_STRDUP(sidstr);
1969                 if (!state->response.extra_data.data) {
1970                         DEBUG(0, ("Out of memory\n"));
1971                         return WINBINDD_ERROR;
1972                 }
1973                 DEBUG(10, ("aliases_list: %s\n",
1974                            (char *)state->response.extra_data.data));
1975                 state->response.length += len+1;
1976                 state->response.data.num_entries = num_sids;
1977         }
1978 
1979         return WINBINDD_OK;
1980 }
1981 
1982 

/* [<][>][^][v][top][bottom][index][help] */