Make winbindd_cli_state->response a pointer instead of a struct member
[Samba.git] / source3 / winbindd / winbindd_user.c
blobda6a303e5d26a2ae406c91cdcd9a69af1beff607
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - user related functions
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
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.
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.
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/>.
24 #include "includes.h"
25 #include "winbindd.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
30 static bool fillup_pw_field(const char *lp_template,
31 const char *username,
32 const char *domname,
33 uid_t uid,
34 gid_t gid,
35 const char *in,
36 fstring out)
38 char *templ;
40 if (out == NULL)
41 return False;
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. */
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);
59 if (!templ)
60 return False;
62 safe_strcpy(out, templ, sizeof(fstring) - 1);
63 TALLOC_FREE(templ);
65 return True;
68 /* Fill a pwent structure with information we have obtained */
70 static bool winbindd_fill_pwent(TALLOC_CTX *ctx, char *dom_name, char *user_name,
71 DOM_SID *user_sid, DOM_SID *group_sid,
72 char *full_name, char *homedir, char *shell,
73 struct winbindd_pw *pw)
75 fstring output_username;
76 char *mapped_name = NULL;
77 struct winbindd_domain *domain = NULL;
78 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
80 if (!pw || !dom_name || !user_name)
81 return False;
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;
91 /* Resolve the uid number */
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;
101 /* Resolve the gid number */
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;
111 /* Username */
113 strlower_m(user_name);
114 nt_status = normalize_name_map(ctx, domain, user_name, &mapped_name);
116 /* Basic removal of whitespace */
117 if (NT_STATUS_IS_OK(nt_status)) {
118 fill_domain_username(output_username, dom_name, mapped_name, True);
120 /* Complete name replacement */
121 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
122 fstrcpy(output_username, mapped_name);
124 /* No change at all */
125 else {
126 fill_domain_username(output_username, dom_name, user_name, True);
129 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
131 /* Full name (gecos) */
133 safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
135 /* Home directory and shell */
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;
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;
145 /* Password - set to "*" as we can't generate anything useful here.
146 Authentication can be done using the pam_winbind module. */
148 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
150 return True;
153 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
155 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
156 struct winbindd_cli_state *state)
158 DOM_SID sid;
159 WINBIND_USERINFO user_info;
160 NTSTATUS status;
162 /* Ensure null termination */
163 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
165 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
166 state->request->data.sid));
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;
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;
181 fstrcpy(state->response->data.user_info.acct_name,
182 user_info.acct_name);
183 fstrcpy(state->response->data.user_info.full_name,
184 user_info.full_name);
185 fstrcpy(state->response->data.user_info.homedir, user_info.homedir);
186 fstrcpy(state->response->data.user_info.shell, user_info.shell);
187 state->response->data.user_info.primary_gid = user_info.primary_gid;
188 if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
189 &state->response->data.user_info.group_rid)) {
190 DEBUG(1, ("Could not extract group rid out of %s\n",
191 sid_string_dbg(&sid)));
192 return WINBINDD_ERROR;
195 return WINBINDD_OK;
198 struct getpwsid_state {
199 struct winbindd_cli_state *state;
200 struct winbindd_domain *domain;
201 char *username;
202 char *fullname;
203 char *homedir;
204 char *shell;
205 DOM_SID user_sid;
206 uid_t uid;
207 DOM_SID group_sid;
208 gid_t gid;
209 bool username_mapped;
212 static void getpwsid_queryuser_recv(void *private_data, bool success,
213 const char *acct_name,
214 const char *full_name,
215 const char *homedir,
216 const char *shell,
217 gid_t gid,
218 uint32 group_rid);
219 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid);
220 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid);
222 static void getpwsid_queryuser(struct winbindd_cli_state *state,
223 const DOM_SID *sid)
225 struct getpwsid_state *s;
227 s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
228 if (s == NULL) {
229 DEBUG(0, ("talloc failed\n"));
230 goto error;
233 s->state = state;
234 s->domain = find_domain_from_sid_noinit(sid);
235 if (s->domain == NULL) {
236 DEBUG(3, ("Could not find domain for sid %s\n",
237 sid_string_dbg(sid)));
238 goto error;
241 sid_copy(&s->user_sid, sid);
243 query_user_async(s->state->mem_ctx, s->domain, sid,
244 getpwsid_queryuser_recv, s);
245 return;
247 error:
248 request_error(state);
251 static void getpwsid_queryuser_recv(void *private_data, bool success,
252 const char *acct_name,
253 const char *full_name,
254 const char *homedir,
255 const char *shell,
256 gid_t gid,
257 uint32 group_rid)
259 fstring username;
260 struct getpwsid_state *s =
261 talloc_get_type_abort(private_data, struct getpwsid_state);
262 char *mapped_name;
263 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
265 if (!success) {
266 DEBUG(5, ("Could not query domain %s SID %s\n",
267 s->domain->name, sid_string_dbg(&s->user_sid)));
268 request_error(s->state);
269 return;
272 if ( acct_name && *acct_name ) {
273 fstrcpy( username, acct_name );
274 } else {
275 char *domain_name = NULL;
276 enum lsa_SidType type;
277 char *user_name = NULL;
278 struct winbindd_domain *domain = NULL;
280 domain = find_lookup_domain_from_sid(&s->user_sid);
281 if (domain == NULL) {
282 DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
283 sid_string_dbg(&s->user_sid)));
284 request_error(s->state);
285 return;
287 winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
288 &s->user_sid, &domain_name,
289 &user_name, &type );
291 /* If this still fails we ar4e done. Just error out */
292 if ( !user_name ) {
293 DEBUG(5,("Could not obtain a name for SID %s\n",
294 sid_string_dbg(&s->user_sid)));
295 request_error(s->state);
296 return;
299 fstrcpy( username, user_name );
302 strlower_m( username );
303 s->username = talloc_strdup(s->state->mem_ctx, username);
305 nt_status = normalize_name_map(s->state->mem_ctx, s->domain,
306 s->username, &mapped_name);
308 /* Basic removal of whitespace */
309 if (NT_STATUS_IS_OK(nt_status)) {
310 s->username = mapped_name;
311 s->username_mapped = false;
313 /* Complete name replacement */
314 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
315 s->username = mapped_name;
316 s->username_mapped = true;
318 /* No change at all */
319 else {
320 s->username_mapped = false;
323 s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
324 s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
325 s->shell = talloc_strdup(s->state->mem_ctx, shell);
326 s->gid = gid;
327 sid_copy(&s->group_sid, &s->domain->sid);
328 sid_append_rid(&s->group_sid, group_rid);
330 winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
331 getpwsid_sid2uid_recv, s);
334 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid)
336 struct getpwsid_state *s =
337 talloc_get_type_abort(private_data, struct getpwsid_state);
339 if (!success) {
340 DEBUG(5, ("Could not query uid for user %s\\%s\n",
341 s->domain->name, s->username));
342 request_error(s->state);
343 return;
346 s->uid = uid;
347 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
348 getpwsid_sid2gid_recv, s);
351 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
353 struct getpwsid_state *s =
354 talloc_get_type_abort(private_data, struct getpwsid_state);
355 struct winbindd_pw *pw;
356 fstring output_username;
358 /* allow the nss backend to override the primary group ID.
359 If the gid has already been set, then keep it.
360 This makes me feel dirty. If the nss backend already
361 gave us a gid, we don't really care whether the sid2gid()
362 call worked or not. --jerry */
364 if ( s->gid == (gid_t)-1 ) {
366 if (!success) {
367 DEBUG(5, ("Could not query gid for user %s\\%s\n",
368 s->domain->name, s->username));
369 goto failed;
372 /* take what the sid2gid() call gave us */
373 s->gid = gid;
376 pw = &s->state->response->data.pw;
377 pw->pw_uid = s->uid;
378 pw->pw_gid = s->gid;
380 /* allow username to be overridden by the alias mapping */
382 if ( s->username_mapped ) {
383 fstrcpy( output_username, s->username );
384 } else {
385 fill_domain_username(output_username, s->domain->name,
386 s->username, True);
389 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
390 safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
392 if (!fillup_pw_field(lp_template_homedir(), s->username,
393 s->domain->name, pw->pw_uid, pw->pw_gid,
394 s->homedir, pw->pw_dir)) {
395 DEBUG(5, ("Could not compose homedir\n"));
396 goto failed;
399 if (!fillup_pw_field(lp_template_shell(), s->username,
400 s->domain->name, pw->pw_uid, pw->pw_gid,
401 s->shell, pw->pw_shell)) {
402 DEBUG(5, ("Could not compose shell\n"));
403 goto failed;
406 /* Password - set to "*" as we can't generate anything useful here.
407 Authentication can be done using the pam_winbind module. */
409 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
411 request_ok(s->state);
412 return;
414 failed:
415 request_error(s->state);
418 /* Return a password structure from a username. */
420 static void getpwnam_name2sid_recv(void *private_data, bool success,
421 const DOM_SID *sid, enum lsa_SidType type);
423 void winbindd_getpwnam(struct winbindd_cli_state *state)
425 struct winbindd_domain *domain;
426 fstring domname, username;
427 char *mapped_user = NULL;
428 char *domuser;
429 size_t dusize;
430 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
432 domuser = state->request->data.username;
433 dusize = sizeof(state->request->data.username);
435 /* Ensure null termination (it's an fstring) */
436 domuser[dusize-1] = '\0';
438 DEBUG(3, ("[%5lu]: getpwnam %s\n",
439 (unsigned long)state->pid,
440 domuser));
442 nt_status = normalize_name_unmap(state->mem_ctx, domuser,
443 &mapped_user);
445 /* If we could not convert from an aliased name or a
446 normalized name, then just use the original name */
448 if (!NT_STATUS_IS_OK(nt_status) &&
449 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
451 mapped_user = domuser;
454 if (!parse_domain_user(mapped_user, domname, username)) {
455 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
456 request_error(state);
457 return;
460 /* Get info for the domain */
462 domain = find_domain_from_name_noinit(domname);
464 if (domain == NULL) {
465 DEBUG(7, ("could not find domain entry for domain %s. "
466 "Using primary domain\n", domname));
467 if ( (domain = find_our_domain()) == NULL ) {
468 DEBUG(0,("Cannot find my primary domain structure!\n"));
469 request_error(state);
470 return;
474 if (strequal(domname, lp_workgroup()) &&
475 lp_winbind_trusted_domains_only() ) {
476 DEBUG(7,("winbindd_getpwnam: My domain -- "
477 "rejecting getpwnam() for %s\\%s.\n",
478 domname, username));
479 request_error(state);
480 return;
483 /* Get rid and name type from name. The following costs 1 packet */
485 winbindd_lookupname_async(state->mem_ctx, domname, username,
486 getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
487 state);
490 static void getpwnam_name2sid_recv(void *private_data, bool success,
491 const DOM_SID *sid, enum lsa_SidType type)
493 struct winbindd_cli_state *state =
494 (struct winbindd_cli_state *)private_data;
495 fstring domname, username;
496 char *domuser = state->request->data.username;
498 if (!success) {
499 DEBUG(5, ("Could not lookup name for user %s\n", domuser));
500 request_error(state);
501 return;
504 if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
505 DEBUG(5, ("%s is not a user\n", domuser));
506 request_error(state);
507 return;
510 if (parse_domain_user(domuser, domname, username)) {
511 check_domain_trusted(domname, sid);
514 getpwsid_queryuser(state, sid);
517 static void getpwuid_recv(void *private_data, bool success, const char *sid)
519 struct winbindd_cli_state *state =
520 (struct winbindd_cli_state *)private_data;
521 DOM_SID user_sid;
523 if (!success) {
524 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
525 (unsigned long)(state->request->data.uid)));
526 request_error(state);
527 return;
530 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
531 (unsigned long)(state->request->data.uid), sid));
533 if (!string_to_sid(&user_sid, sid)) {
534 DEBUG(1,("uid2sid_recv: Could not convert sid %s "
535 "from string\n,", sid));
536 request_error(state);
537 return;
540 getpwsid_queryuser(state, &user_sid);
543 /* Return a password structure given a uid number */
544 void winbindd_getpwuid(struct winbindd_cli_state *state)
546 uid_t uid = state->request->data.uid;
548 DEBUG(3, ("[%5lu]: getpwuid %lu\n",
549 (unsigned long)state->pid,
550 (unsigned long)uid));
552 /* always query idmap via the async interface */
553 /* if this turns to be too slow we will add here
554 * a direct query to the cache */
555 winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state);
558 /* Return a password structure given a sid */
559 void winbindd_getpwsid(struct winbindd_cli_state *state)
561 DOM_SID sid;
563 /* Ensure null termination */
564 state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
566 DEBUG(3, ("[%5lu]: getpwsid %s\n", (unsigned long)state->pid,
567 state->request->data.sid));
569 if (!string_to_sid(&sid, state->request->data.sid)) {
570 DEBUG(5, ("%s not a SID\n", state->request->data.sid));
571 request_error(state);
572 return;
575 getpwsid_queryuser(state, &sid);
579 * set/get/endpwent functions
582 /* Rewind file pointer for ntdom passwd database */
584 static bool winbindd_setpwent_internal(struct winbindd_cli_state *state)
586 struct winbindd_domain *domain;
588 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
590 /* Check user has enabled this */
592 if (!lp_winbind_enum_users()) {
593 return False;
596 /* Free old static data if it exists */
598 if (state->getpwent_state != NULL) {
599 free_getent_state(state->getpwent_state);
600 state->getpwent_state = NULL;
603 /* Create sam pipes for each domain we know about */
605 for(domain = domain_list(); domain != NULL; domain = domain->next) {
606 struct getent_state *domain_state;
609 /* don't add our domaina if we are a PDC or if we
610 are a member of a Samba domain */
612 if ((IS_DC || lp_winbind_trusted_domains_only())
613 && strequal(domain->name, lp_workgroup())) {
614 continue;
617 /* Create a state record for this domain */
619 domain_state = SMB_MALLOC_P(struct getent_state);
620 if (!domain_state) {
621 DEBUG(0, ("malloc failed\n"));
622 return False;
625 ZERO_STRUCTP(domain_state);
627 fstrcpy(domain_state->domain_name, domain->name);
629 /* Add to list of open domains */
631 DLIST_ADD(state->getpwent_state, domain_state);
634 state->getpwent_initialized = True;
635 return True;
638 void winbindd_setpwent(struct winbindd_cli_state *state)
640 if (winbindd_setpwent_internal(state)) {
641 request_ok(state);
642 } else {
643 request_error(state);
647 /* Close file pointer to ntdom passwd database */
649 void winbindd_endpwent(struct winbindd_cli_state *state)
651 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
653 free_getent_state(state->getpwent_state);
654 state->getpwent_initialized = False;
655 state->getpwent_state = NULL;
656 request_ok(state);
659 /* Get partial list of domain users for a domain. We fill in the sam_entries,
660 and num_sam_entries fields with domain user information. The dispinfo_ndx
661 field is incremented to the index of the next user to fetch. Return True if
662 some users were returned, False otherwise. */
664 static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
666 NTSTATUS status;
667 uint32 num_entries;
668 WINBIND_USERINFO *info;
669 struct getpwent_user *name_list = NULL;
670 struct winbindd_domain *domain;
671 struct winbindd_methods *methods;
672 unsigned int i;
674 if (ent->num_sam_entries)
675 return False;
677 if (!(domain = find_domain_from_name(ent->domain_name))) {
678 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
679 ent->domain_name));
680 return False;
683 methods = domain->methods;
685 /* Free any existing user info */
687 SAFE_FREE(ent->sam_entries);
688 ent->num_sam_entries = 0;
690 /* Call query_user_list to get a list of usernames and user rids */
692 num_entries = 0;
694 status = methods->query_user_list(domain, mem_ctx, &num_entries, &info);
696 if (!NT_STATUS_IS_OK(status)) {
697 DEBUG(10,("get_sam_user_entries: "
698 "query_user_list failed with %s\n",
699 nt_errstr(status)));
700 return False;
703 if (num_entries) {
704 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user,
705 ent->num_sam_entries + num_entries);
706 if (!name_list) {
707 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
708 return False;
712 for (i = 0; i < num_entries; i++) {
713 /* Store account name and gecos */
714 if (!info[i].acct_name) {
715 fstrcpy(name_list[ent->num_sam_entries + i].name, "");
716 } else {
717 fstrcpy(name_list[ent->num_sam_entries + i].name,
718 info[i].acct_name);
720 if (!info[i].full_name) {
721 fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
722 } else {
723 fstrcpy(name_list[ent->num_sam_entries + i].gecos,
724 info[i].full_name);
726 if (!info[i].homedir) {
727 fstrcpy(name_list[ent->num_sam_entries + i].homedir,"");
728 } else {
729 fstrcpy(name_list[ent->num_sam_entries + i].homedir,
730 info[i].homedir);
732 if (!info[i].shell) {
733 fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
734 } else {
735 fstrcpy(name_list[ent->num_sam_entries + i].shell,
736 info[i].shell);
740 /* User and group ids */
741 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
742 &info[i].user_sid);
743 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
744 &info[i].group_sid);
747 ent->num_sam_entries += num_entries;
749 /* Fill in remaining fields */
751 ent->sam_entries = name_list;
752 ent->sam_entry_index = 0;
753 return ent->num_sam_entries > 0;
756 /* Fetch next passwd entry from ntdom database */
758 #define MAX_GETPWENT_USERS 500
760 void winbindd_getpwent(struct winbindd_cli_state *state)
762 struct getent_state *ent;
763 struct winbindd_pw *user_list;
764 int num_users, user_list_ndx;
766 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
768 /* Check user has enabled this */
770 if (!lp_winbind_enum_users()) {
771 request_error(state);
772 return;
775 /* Allocate space for returning a chunk of users */
777 num_users = MIN(MAX_GETPWENT_USERS, state->request->data.num_entries);
779 if (num_users == 0) {
780 request_error(state);
781 return;
784 user_list = talloc_zero_array(state->mem_ctx, struct winbindd_pw,
785 num_users);
786 if (!user_list) {
787 request_error(state);
788 return;
790 state->response->extra_data.data = user_list;
792 if (!state->getpwent_initialized)
793 winbindd_setpwent_internal(state);
795 if (!(ent = state->getpwent_state)) {
796 request_error(state);
797 return;
800 /* Start sending back users */
802 for (user_list_ndx = 0; user_list_ndx < num_users; ) {
803 struct getpwent_user *name_list = NULL;
804 uint32 result;
806 /* Do we need to fetch another chunk of users? */
808 if (ent->num_sam_entries == ent->sam_entry_index) {
810 while(ent &&
811 !get_sam_user_entries(ent, state->mem_ctx)) {
812 struct getent_state *next_ent;
814 /* Free state information for this domain */
816 SAFE_FREE(ent->sam_entries);
818 next_ent = ent->next;
819 DLIST_REMOVE(state->getpwent_state, ent);
821 SAFE_FREE(ent);
822 ent = next_ent;
825 /* No more domains */
827 if (!ent)
828 break;
831 name_list = (struct getpwent_user *)ent->sam_entries;
833 /* Lookup user info */
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]);
846 /* Add user to return list */
848 if (result) {
850 user_list_ndx++;
851 state->response->data.num_entries++;
852 state->response->length += sizeof(struct winbindd_pw);
854 } else
855 DEBUG(1, ("could not lookup domain user %s\n",
856 name_list[ent->sam_entry_index].name));
858 ent->sam_entry_index++;
862 /* Out of domains */
864 if (user_list_ndx > 0)
865 request_ok(state);
866 else
867 request_error(state);
870 /* List domain users without mapping to unix ids */
871 void winbindd_list_users(struct winbindd_cli_state *state)
873 winbindd_list_ent(state, LIST_USERS);