root/source3/winbindd/winbindd_user.c

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

DEFINITIONS

This source file includes following definitions.
  1. fillup_pw_field
  2. winbindd_fill_pwent
  3. winbindd_dual_userinfo
  4. getpwsid_queryuser
  5. getpwsid_queryuser_recv
  6. getpwsid_sid2uid_recv
  7. getpwsid_sid2gid_recv
  8. winbindd_getpwnam
  9. getpwnam_name2sid_recv
  10. getpwuid_recv
  11. winbindd_getpwuid
  12. winbindd_getpwsid
  13. winbindd_setpwent_internal
  14. winbindd_setpwent
  15. winbindd_endpwent
  16. get_sam_user_entries
  17. winbindd_getpwent
  18. winbindd_list_users

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Winbind daemon - user related functions
   5 
   6    Copyright (C) Tim Potter 2000
   7    Copyright (C) Jeremy Allison 2001.
   8    Copyright (C) Gerald (Jerry) Carter 2003.
   9    
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "winbindd.h"
  26 
  27 #undef DBGC_CLASS
  28 #define DBGC_CLASS DBGC_WINBIND
  29 
  30 static bool fillup_pw_field(const char *lp_template,
     /* [<][>][^][v][top][bottom][index][help] */
  31                             const char *username,
  32                             const char *domname,
  33                             uid_t uid,
  34                             gid_t gid,
  35                             const char *in,
  36                             fstring out)
  37 {
  38         char *templ;
  39 
  40         if (out == NULL)
  41                 return False;
  42 
  43         /* The substitution of %U and %D in the 'template
  44            homedir' is done by talloc_sub_specified() below.
  45            If we have an in string (which means the value has already
  46            been set in the nss_info backend), then use that.
  47            Otherwise use the template value passed in. */
  48 
  49         if ( in && !strequal(in,"") && lp_security() == SEC_ADS ) {
  50                 templ = talloc_sub_specified(NULL, in,
  51                                              username, domname,
  52                                      uid, gid);
  53         } else {
  54                 templ = talloc_sub_specified(NULL, lp_template,
  55                                              username, domname,
  56                                              uid, gid);
  57         }
  58 
  59         if (!templ)
  60                 return False;
  61 
  62         safe_strcpy(out, templ, sizeof(fstring) - 1);
  63         TALLOC_FREE(templ);
  64 
  65         return True;
  66 
  67 }
  68 /* Fill a pwent structure with information we have obtained */
  69 
  70 static bool winbindd_fill_pwent(TALLOC_CTX *ctx, char *dom_name, char *user_name,
     /* [<][>][^][v][top][bottom][index][help] */
  71                                 DOM_SID *user_sid, DOM_SID *group_sid,
  72                                 char *full_name, char *homedir, char *shell,
  73                                 struct winbindd_pw *pw)
  74 {
  75         fstring output_username;
  76         char *mapped_name = NULL;
  77         struct winbindd_domain *domain = NULL;
  78         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
  79 
  80         if (!pw || !dom_name || !user_name)
  81                 return False;
  82 
  83         domain = find_domain_from_name_noinit(dom_name);
  84         if (domain == NULL) {
  85                 DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s.\n",
  86                          dom_name));
  87                 nt_status = NT_STATUS_NO_SUCH_DOMAIN;
  88                 return false;
  89         }
  90 
  91         /* Resolve the uid number */
  92 
  93         if (!NT_STATUS_IS_OK(idmap_sid_to_uid(domain->have_idmap_config ?
  94                                               dom_name : "", user_sid,
  95                                               &pw->pw_uid))) {
  96                 DEBUG(1, ("error getting user id for sid %s\n",
  97                           sid_string_dbg(user_sid)));
  98                 return False;
  99         }
 100 
 101         /* Resolve the gid number */
 102 
 103         if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config ?
 104                                               dom_name : "", group_sid,
 105                                               &pw->pw_gid))) {
 106                 DEBUG(1, ("error getting group id for sid %s\n",
 107                           sid_string_dbg(group_sid)));
 108                 return False;
 109         }
 110 
 111         /* Username */
 112 
 113         strlower_m(user_name);
 114         nt_status = normalize_name_map(ctx, domain, user_name, &mapped_name);
 115 
 116         /* Basic removal of whitespace */
 117         if (NT_STATUS_IS_OK(nt_status)) {
 118                 fill_domain_username(output_username, dom_name, mapped_name, True);
 119         }
 120         /* Complete name replacement */
 121         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 122                 fstrcpy(output_username, mapped_name);
 123         }
 124         /* No change at all */
 125         else {
 126                 fill_domain_username(output_username, dom_name, user_name, True);
 127         }
 128 
 129         safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
 130 
 131         /* Full name (gecos) */
 132 
 133         safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
 134 
 135         /* Home directory and shell */
 136 
 137         if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
 138                              pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
 139                 return False;
 140 
 141         if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
 142                              pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
 143                 return False;
 144 
 145         /* Password - set to "*" as we can't generate anything useful here.
 146            Authentication can be done using the pam_winbind module. */
 147 
 148         safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
 149 
 150         return True;
 151 }
 152 
 153 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
 154 
 155 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 156                                             struct winbindd_cli_state *state)
 157 {
 158         DOM_SID sid;
 159         WINBIND_USERINFO user_info;
 160         NTSTATUS status;
 161 
 162         /* Ensure null termination */
 163         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 164 
 165         DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
 166                   state->request.data.sid));
 167 
 168         if (!string_to_sid(&sid, state->request.data.sid)) {
 169                 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
 170                 return WINBINDD_ERROR;
 171         }
 172 
 173         status = domain->methods->query_user(domain, state->mem_ctx,
 174                                              &sid, &user_info);
 175         if (!NT_STATUS_IS_OK(status)) {
 176                 DEBUG(1, ("error getting user info for sid %s\n",
 177                           sid_string_dbg(&sid)));
 178                 return WINBINDD_ERROR;
 179         }
 180 
 181         fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
 182         fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
 183         fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
 184         fstrcpy(state->response.data.user_info.shell, user_info.shell);
 185         state->response.data.user_info.primary_gid = user_info.primary_gid;
 186         if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
 187                                 &state->response.data.user_info.group_rid)) {
 188                 DEBUG(1, ("Could not extract group rid out of %s\n",
 189                           sid_string_dbg(&sid)));
 190                 return WINBINDD_ERROR;
 191         }
 192 
 193         return WINBINDD_OK;
 194 }
 195 
 196 struct getpwsid_state {
 197         struct winbindd_cli_state *state;
 198         struct winbindd_domain *domain;
 199         char *username;
 200         char *fullname;
 201         char *homedir;
 202         char *shell;
 203         DOM_SID user_sid;
 204         uid_t uid;
 205         DOM_SID group_sid;
 206         gid_t gid;
 207         bool username_mapped;
 208 };
 209 
 210 static void getpwsid_queryuser_recv(void *private_data, bool success,
 211                                     const char *acct_name,
 212                                     const char *full_name,
 213                                     const char *homedir,
 214                                     const char *shell,
 215                                     gid_t gid,
 216                                     uint32 group_rid);
 217 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid);
 218 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid);
 219 
 220 static void getpwsid_queryuser(struct winbindd_cli_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 221                                 const DOM_SID *sid)
 222 {
 223         struct getpwsid_state *s;
 224 
 225         s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
 226         if (s == NULL) {
 227                 DEBUG(0, ("talloc failed\n"));
 228                 goto error;
 229         }
 230 
 231         s->state = state;
 232         s->domain = find_domain_from_sid_noinit(sid);
 233         if (s->domain == NULL) {
 234                 DEBUG(3, ("Could not find domain for sid %s\n",
 235                           sid_string_dbg(sid)));
 236                 goto error;
 237         }
 238 
 239         sid_copy(&s->user_sid, sid);
 240 
 241         query_user_async(s->state->mem_ctx, s->domain, sid,
 242                          getpwsid_queryuser_recv, s);
 243         return;
 244 
 245  error:
 246         request_error(state);
 247 }
 248 
 249 static void getpwsid_queryuser_recv(void *private_data, bool success,
     /* [<][>][^][v][top][bottom][index][help] */
 250                                     const char *acct_name,
 251                                     const char *full_name,
 252                                     const char *homedir,
 253                                     const char *shell,
 254                                     gid_t gid,
 255                                     uint32 group_rid)
 256 {
 257         fstring username;
 258         struct getpwsid_state *s =
 259                 talloc_get_type_abort(private_data, struct getpwsid_state);
 260         char *mapped_name;
 261         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 262 
 263         if (!success) {
 264                 DEBUG(5, ("Could not query domain %s SID %s\n",
 265                           s->domain->name, sid_string_dbg(&s->user_sid)));
 266                 request_error(s->state);
 267                 return;
 268         }
 269 
 270         if ( acct_name && *acct_name ) {
 271         fstrcpy( username, acct_name );
 272         } else {
 273                 char *domain_name = NULL;
 274                 enum lsa_SidType type;
 275                 char *user_name = NULL;
 276                 struct winbindd_domain *domain = NULL;
 277 
 278                 domain = find_lookup_domain_from_sid(&s->user_sid);
 279                 if (domain == NULL) {
 280                         DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
 281                                   sid_string_dbg(&s->user_sid)));
 282                         request_error(s->state);
 283                         return;
 284                 }
 285                 winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
 286                                             &s->user_sid, &domain_name,
 287                                             &user_name, &type );
 288 
 289                 /* If this still fails we ar4e done.  Just error out */
 290                 if ( !user_name ) {
 291                         DEBUG(5,("Could not obtain a name for SID %s\n",
 292                                  sid_string_dbg(&s->user_sid)));
 293                         request_error(s->state);
 294                         return;
 295                 }
 296 
 297                 fstrcpy( username, user_name );
 298         }
 299 
 300         strlower_m( username );
 301         s->username = talloc_strdup(s->state->mem_ctx, username);
 302 
 303         nt_status = normalize_name_map(s->state->mem_ctx, s->domain,
 304                                        s->username, &mapped_name);
 305 
 306         /* Basic removal of whitespace */
 307         if (NT_STATUS_IS_OK(nt_status)) {
 308                 s->username = mapped_name;
 309                 s->username_mapped = false;
 310         }
 311         /* Complete name replacement */
 312         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 313                 s->username = mapped_name;
 314                 s->username_mapped = true;
 315         }
 316         /* No change at all */
 317         else {
 318                 s->username_mapped = false;
 319         }
 320 
 321         s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
 322         s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
 323         s->shell = talloc_strdup(s->state->mem_ctx, shell);
 324         s->gid = gid;
 325         sid_copy(&s->group_sid, &s->domain->sid);
 326         sid_append_rid(&s->group_sid, group_rid);
 327 
 328         winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
 329                                getpwsid_sid2uid_recv, s);
 330 }
 331 
 332 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid)
     /* [<][>][^][v][top][bottom][index][help] */
 333 {
 334         struct getpwsid_state *s =
 335                 talloc_get_type_abort(private_data, struct getpwsid_state);
 336 
 337         if (!success) {
 338                 DEBUG(5, ("Could not query uid for user %s\\%s\n",
 339                           s->domain->name, s->username));
 340                 request_error(s->state);
 341                 return;
 342         }
 343 
 344         s->uid = uid;
 345         winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
 346                                getpwsid_sid2gid_recv, s);
 347 }
 348 
 349 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 350 {
 351         struct getpwsid_state *s =
 352                 talloc_get_type_abort(private_data, struct getpwsid_state);
 353         struct winbindd_pw *pw;
 354         fstring output_username;
 355 
 356         /* allow the nss backend to override the primary group ID.
 357            If the gid has already been set, then keep it.
 358            This makes me feel dirty.  If the nss backend already
 359            gave us a gid, we don't really care whether the sid2gid()
 360            call worked or not.   --jerry  */
 361 
 362         if ( s->gid == (gid_t)-1 ) {
 363 
 364                 if (!success) {
 365                         DEBUG(5, ("Could not query gid for user %s\\%s\n",
 366                                   s->domain->name, s->username));
 367                         goto failed;
 368                 }
 369 
 370                 /* take what the sid2gid() call gave us */
 371                 s->gid = gid;
 372         }
 373 
 374         pw = &s->state->response.data.pw;
 375         pw->pw_uid = s->uid;
 376         pw->pw_gid = s->gid;
 377 
 378         /* allow username to be overridden by the alias mapping */
 379 
 380         if ( s->username_mapped ) {
 381                 fstrcpy( output_username, s->username );
 382         } else {
 383         fill_domain_username(output_username, s->domain->name,
 384                              s->username, True);
 385         }
 386 
 387         safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
 388         safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
 389 
 390         if (!fillup_pw_field(lp_template_homedir(), s->username,
 391                              s->domain->name, pw->pw_uid, pw->pw_gid,
 392                              s->homedir, pw->pw_dir)) {
 393                 DEBUG(5, ("Could not compose homedir\n"));
 394                 goto failed;
 395         }
 396 
 397         if (!fillup_pw_field(lp_template_shell(), s->username,
 398                              s->domain->name, pw->pw_uid, pw->pw_gid,
 399                              s->shell, pw->pw_shell)) {
 400                 DEBUG(5, ("Could not compose shell\n"));
 401                 goto failed;
 402         }
 403 
 404         /* Password - set to "*" as we can't generate anything useful here.
 405            Authentication can be done using the pam_winbind module. */
 406 
 407         safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
 408 
 409         request_ok(s->state);
 410         return;
 411 
 412  failed:
 413         request_error(s->state);
 414 }
 415 
 416 /* Return a password structure from a username.  */
 417 
 418 static void getpwnam_name2sid_recv(void *private_data, bool success,
 419                                    const DOM_SID *sid, enum lsa_SidType type);
 420 
 421 void winbindd_getpwnam(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 422 {
 423         struct winbindd_domain *domain;
 424         fstring domname, username;
 425         char *mapped_user = NULL;
 426         char *domuser;
 427         size_t dusize;
 428         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 429 
 430         domuser = state->request.data.username;
 431         dusize = sizeof(state->request.data.username);
 432 
 433         /* Ensure null termination (it's an fstring) */
 434         domuser[dusize-1] = '\0';
 435 
 436         DEBUG(3, ("[%5lu]: getpwnam %s\n",
 437                   (unsigned long)state->pid,
 438                   domuser));
 439 
 440         nt_status = normalize_name_unmap(state->mem_ctx, domuser,
 441                                          &mapped_user);
 442 
 443         /* If we could not convert from an aliased name or a
 444            normalized name, then just use the original name */
 445 
 446         if (!NT_STATUS_IS_OK(nt_status) &&
 447             !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
 448         {
 449                 mapped_user = domuser;
 450         }
 451 
 452         if (!parse_domain_user(mapped_user, domname, username)) {
 453                 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
 454                 request_error(state);
 455                 return;
 456         }
 457 
 458         /* Get info for the domain */
 459 
 460         domain = find_domain_from_name_noinit(domname);
 461 
 462         if (domain == NULL) {
 463                 DEBUG(7, ("could not find domain entry for domain %s.  "
 464                           "Using primary domain\n", domname));
 465                 if ( (domain = find_our_domain()) == NULL ) {
 466                         DEBUG(0,("Cannot find my primary domain structure!\n"));
 467                         request_error(state);
 468                         return;
 469                 }
 470         }
 471 
 472         if (strequal(domname, lp_workgroup()) &&
 473             lp_winbind_trusted_domains_only() ) {
 474                 DEBUG(7,("winbindd_getpwnam: My domain -- "
 475                          "rejecting getpwnam() for %s\\%s.\n",
 476                          domname, username));
 477                 request_error(state);
 478                 return;
 479         }
 480 
 481         /* Get rid and name type from name.  The following costs 1 packet */
 482 
 483         winbindd_lookupname_async(state->mem_ctx, domname, username,
 484                                   getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
 485                                   state);
 486 }
 487 
 488 static void getpwnam_name2sid_recv(void *private_data, bool success,
     /* [<][>][^][v][top][bottom][index][help] */
 489                                    const DOM_SID *sid, enum lsa_SidType type)
 490 {
 491         struct winbindd_cli_state *state =
 492                 (struct winbindd_cli_state *)private_data;
 493         fstring domname, username;
 494         char *domuser = state->request.data.username;
 495 
 496         if (!success) {
 497                 DEBUG(5, ("Could not lookup name for user %s\n", domuser));
 498                 request_error(state);
 499                 return;
 500         }
 501 
 502         if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
 503                 DEBUG(5, ("%s is not a user\n", domuser));
 504                 request_error(state);
 505                 return;
 506         }
 507 
 508         if (parse_domain_user(domuser, domname, username)) {
 509                 check_domain_trusted(domname, sid);
 510         }
 511 
 512         getpwsid_queryuser(state, sid);
 513 }
 514 
 515 static void getpwuid_recv(void *private_data, bool success, const char *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 516 {
 517         struct winbindd_cli_state *state =
 518                 (struct winbindd_cli_state *)private_data;
 519         DOM_SID user_sid;
 520 
 521         if (!success) {
 522                 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
 523                           (unsigned long)(state->request.data.uid)));
 524                 request_error(state);
 525                 return;
 526         }
 527 
 528         DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
 529                   (unsigned long)(state->request.data.uid), sid));
 530 
 531         if (!string_to_sid(&user_sid, sid)) {
 532                 DEBUG(1,("uid2sid_recv: Could not convert sid %s "
 533                         "from string\n,", sid));
 534                 request_error(state);
 535                 return;
 536         }
 537 
 538         getpwsid_queryuser(state, &user_sid);
 539 }
 540 
 541 /* Return a password structure given a uid number */
 542 void winbindd_getpwuid(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 543 {
 544         uid_t uid = state->request.data.uid;
 545 
 546         DEBUG(3, ("[%5lu]: getpwuid %lu\n",
 547                   (unsigned long)state->pid,
 548                   (unsigned long)uid));
 549 
 550         /* always query idmap via the async interface */
 551         /* if this turns to be too slow we will add here
 552          * a direct query to the cache */
 553         winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state);
 554 }
 555 
 556 /* Return a password structure given a sid */
 557 void winbindd_getpwsid(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 558 {
 559         DOM_SID sid;
 560 
 561         /* Ensure null termination */
 562         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 563 
 564         DEBUG(3, ("[%5lu]: getpwsid %s\n", (unsigned long)state->pid,
 565                   state->request.data.sid));
 566 
 567         if (!string_to_sid(&sid, state->request.data.sid)) {
 568                 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
 569                 request_error(state);
 570                 return;
 571         }
 572 
 573         getpwsid_queryuser(state, &sid);
 574 }
 575 
 576 /*
 577  * set/get/endpwent functions
 578  */
 579 
 580 /* Rewind file pointer for ntdom passwd database */
 581 
 582 static bool winbindd_setpwent_internal(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 583 {
 584         struct winbindd_domain *domain;
 585 
 586         DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
 587 
 588         /* Check user has enabled this */
 589 
 590         if (!lp_winbind_enum_users()) {
 591                 return False;
 592         }
 593 
 594         /* Free old static data if it exists */
 595 
 596         if (state->getpwent_state != NULL) {
 597                 free_getent_state(state->getpwent_state);
 598                 state->getpwent_state = NULL;
 599         }
 600 
 601         /* Create sam pipes for each domain we know about */
 602 
 603         for(domain = domain_list(); domain != NULL; domain = domain->next) {
 604                 struct getent_state *domain_state;
 605 
 606 
 607                 /* don't add our domaina if we are a PDC or if we
 608                    are a member of a Samba domain */
 609 
 610                 if ((IS_DC || lp_winbind_trusted_domains_only())
 611                         && strequal(domain->name, lp_workgroup())) {
 612                         continue;
 613                 }
 614 
 615                 /* Create a state record for this domain */
 616 
 617                 domain_state = SMB_MALLOC_P(struct getent_state);
 618                 if (!domain_state) {
 619                         DEBUG(0, ("malloc failed\n"));
 620                         return False;
 621                 }
 622 
 623                 ZERO_STRUCTP(domain_state);
 624 
 625                 fstrcpy(domain_state->domain_name, domain->name);
 626 
 627                 /* Add to list of open domains */
 628 
 629                 DLIST_ADD(state->getpwent_state, domain_state);
 630         }
 631 
 632         state->getpwent_initialized = True;
 633         return True;
 634 }
 635 
 636 void winbindd_setpwent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 637 {
 638         if (winbindd_setpwent_internal(state)) {
 639                 request_ok(state);
 640         } else {
 641                 request_error(state);
 642         }
 643 }
 644 
 645 /* Close file pointer to ntdom passwd database */
 646 
 647 void winbindd_endpwent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 648 {
 649         DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
 650 
 651         free_getent_state(state->getpwent_state);
 652         state->getpwent_initialized = False;
 653         state->getpwent_state = NULL;
 654         request_ok(state);
 655 }
 656 
 657 /* Get partial list of domain users for a domain.  We fill in the sam_entries,
 658    and num_sam_entries fields with domain user information.  The dispinfo_ndx
 659    field is incremented to the index of the next user to fetch.  Return True if
 660    some users were returned, False otherwise. */
 661 
 662 static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 663 {
 664         NTSTATUS status;
 665         uint32 num_entries;
 666         WINBIND_USERINFO *info;
 667         struct getpwent_user *name_list = NULL;
 668         struct winbindd_domain *domain;
 669         struct winbindd_methods *methods;
 670         unsigned int i;
 671 
 672         if (ent->num_sam_entries)
 673                 return False;
 674 
 675         if (!(domain = find_domain_from_name(ent->domain_name))) {
 676                 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
 677                           ent->domain_name));
 678                 return False;
 679         }
 680 
 681         methods = domain->methods;
 682 
 683         /* Free any existing user info */
 684 
 685         SAFE_FREE(ent->sam_entries);
 686         ent->num_sam_entries = 0;
 687 
 688         /* Call query_user_list to get a list of usernames and user rids */
 689 
 690         num_entries = 0;
 691 
 692         status = methods->query_user_list(domain, mem_ctx, &num_entries, &info);
 693 
 694         if (!NT_STATUS_IS_OK(status)) {
 695                 DEBUG(10,("get_sam_user_entries: "
 696                           "query_user_list failed with %s\n",
 697                           nt_errstr(status)));
 698                 return False;
 699         }
 700 
 701         if (num_entries) {
 702                 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user,
 703                                             ent->num_sam_entries + num_entries);
 704                 if (!name_list) {
 705                         DEBUG(0,("get_sam_user_entries realloc failed.\n"));
 706                         return False;
 707                 }
 708         }
 709 
 710         for (i = 0; i < num_entries; i++) {
 711                 /* Store account name and gecos */
 712                 if (!info[i].acct_name) {
 713                         fstrcpy(name_list[ent->num_sam_entries + i].name, "");
 714                 } else {
 715                         fstrcpy(name_list[ent->num_sam_entries + i].name,
 716                                 info[i].acct_name);
 717                 }
 718                 if (!info[i].full_name) {
 719                         fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
 720                 } else {
 721                         fstrcpy(name_list[ent->num_sam_entries + i].gecos,
 722                                 info[i].full_name);
 723                 }
 724                 if (!info[i].homedir) {
 725                         fstrcpy(name_list[ent->num_sam_entries + i].homedir,"");
 726                 } else {
 727                         fstrcpy(name_list[ent->num_sam_entries + i].homedir,
 728                                 info[i].homedir);
 729                 }
 730                 if (!info[i].shell) {
 731                         fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
 732                 } else {
 733                         fstrcpy(name_list[ent->num_sam_entries + i].shell,
 734                                 info[i].shell);
 735                 }
 736 
 737 
 738                 /* User and group ids */
 739                 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
 740                          &info[i].user_sid);
 741                 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
 742                          &info[i].group_sid);
 743         }
 744 
 745         ent->num_sam_entries += num_entries;
 746 
 747         /* Fill in remaining fields */
 748 
 749         ent->sam_entries = name_list;
 750         ent->sam_entry_index = 0;
 751         return ent->num_sam_entries > 0;
 752 }
 753 
 754 /* Fetch next passwd entry from ntdom database */
 755 
 756 #define MAX_GETPWENT_USERS 500
 757 
 758 void winbindd_getpwent(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 759 {
 760         struct getent_state *ent;
 761         struct winbindd_pw *user_list;
 762         int num_users, user_list_ndx;
 763 
 764         DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
 765 
 766         /* Check user has enabled this */
 767 
 768         if (!lp_winbind_enum_users()) {
 769                 request_error(state);
 770                 return;
 771         }
 772 
 773         /* Allocate space for returning a chunk of users */
 774 
 775         num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
 776 
 777         if (num_users == 0) {
 778                 request_error(state);
 779                 return;
 780         }
 781 
 782         user_list = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users);
 783         if (!user_list) {
 784                 request_error(state);
 785                 return;
 786         }
 787         /* will be freed by process_request() */
 788         state->response.extra_data.data = user_list;
 789 
 790         memset(user_list, 0, num_users * sizeof(struct winbindd_pw));
 791 
 792         if (!state->getpwent_initialized)
 793                 winbindd_setpwent_internal(state);
 794 
 795         if (!(ent = state->getpwent_state)) {
 796                 request_error(state);
 797                 return;
 798         }
 799 
 800         /* Start sending back users */
 801 
 802         for (user_list_ndx = 0; user_list_ndx < num_users; ) {
 803                 struct getpwent_user *name_list = NULL;
 804                 uint32 result;
 805 
 806                 /* Do we need to fetch another chunk of users? */
 807 
 808                 if (ent->num_sam_entries == ent->sam_entry_index) {
 809 
 810                         while(ent &&
 811                               !get_sam_user_entries(ent, state->mem_ctx)) {
 812                                 struct getent_state *next_ent;
 813 
 814                                 /* Free state information for this domain */
 815 
 816                                 SAFE_FREE(ent->sam_entries);
 817 
 818                                 next_ent = ent->next;
 819                                 DLIST_REMOVE(state->getpwent_state, ent);
 820 
 821                                 SAFE_FREE(ent);
 822                                 ent = next_ent;
 823                         }
 824 
 825                         /* No more domains */
 826 
 827                         if (!ent)
 828                                 break;
 829                 }
 830 
 831                 name_list = (struct getpwent_user *)ent->sam_entries;
 832 
 833                 /* Lookup user info */
 834 
 835                 result = winbindd_fill_pwent(
 836                         state->mem_ctx,
 837                         ent->domain_name,
 838                         name_list[ent->sam_entry_index].name,
 839                         &name_list[ent->sam_entry_index].user_sid,
 840                         &name_list[ent->sam_entry_index].group_sid,
 841                         name_list[ent->sam_entry_index].gecos,
 842                         name_list[ent->sam_entry_index].homedir,
 843                         name_list[ent->sam_entry_index].shell,
 844                         &user_list[user_list_ndx]);
 845 
 846                 /* Add user to return list */
 847 
 848                 if (result) {
 849 
 850                         user_list_ndx++;
 851                         state->response.data.num_entries++;
 852                         state->response.length += sizeof(struct winbindd_pw);
 853 
 854                 } else
 855                         DEBUG(1, ("could not lookup domain user %s\n",
 856                                   name_list[ent->sam_entry_index].name));
 857 
 858                 ent->sam_entry_index++;
 859 
 860         }
 861 
 862         /* Out of domains */
 863 
 864         if (user_list_ndx > 0)
 865                 request_ok(state);
 866         else
 867                 request_error(state);
 868 }
 869 
 870 /* List domain users without mapping to unix ids */
 871 void winbindd_list_users(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 872 {
 873         winbindd_list_ent(state, LIST_USERS);
 874 }

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