s3:winbind_user: move initialization of domain up in winbindd_fill_pwent()
[Samba/bb.git] / source / winbindd / winbindd_user.c
blob2e326430fc10fb83558078ae07aec60da6c4f350
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. "
86 "Disabling name alias support\n", dom_name));
87 nt_status = NT_STATUS_NO_SUCH_DOMAIN;
90 /* Resolve the uid number */
92 if (!NT_STATUS_IS_OK(idmap_sid_to_uid(dom_name, user_sid,
93 &pw->pw_uid))) {
94 DEBUG(1, ("error getting user id for sid %s\n",
95 sid_string_dbg(user_sid)));
96 return False;
99 /* Resolve the gid number */
101 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(dom_name, group_sid,
102 &pw->pw_gid))) {
103 DEBUG(1, ("error getting group id for sid %s\n",
104 sid_string_dbg(group_sid)));
105 return False;
108 /* Username */
110 strlower_m(user_name);
111 nt_status = normalize_name_map(ctx, domain, user_name, &mapped_name);
113 /* Basic removal of whitespace */
114 if (NT_STATUS_IS_OK(nt_status)) {
115 fill_domain_username(output_username, dom_name, mapped_name, True);
117 /* Complete name replacement */
118 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
119 fstrcpy(output_username, mapped_name);
121 /* No change at all */
122 else {
123 fill_domain_username(output_username, dom_name, user_name, True);
126 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
128 /* Full name (gecos) */
130 safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
132 /* Home directory and shell */
134 if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
135 pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
136 return False;
138 if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
139 pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
140 return False;
142 /* Password - set to "*" as we can't generate anything useful here.
143 Authentication can be done using the pam_winbind module. */
145 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
147 return True;
150 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
152 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
153 struct winbindd_cli_state *state)
155 DOM_SID sid;
156 WINBIND_USERINFO user_info;
157 NTSTATUS status;
159 /* Ensure null termination */
160 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
162 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
163 state->request.data.sid));
165 if (!string_to_sid(&sid, state->request.data.sid)) {
166 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
167 return WINBINDD_ERROR;
170 status = domain->methods->query_user(domain, state->mem_ctx,
171 &sid, &user_info);
172 if (!NT_STATUS_IS_OK(status)) {
173 DEBUG(1, ("error getting user info for sid %s\n",
174 sid_string_dbg(&sid)));
175 return WINBINDD_ERROR;
178 fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
179 fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
180 fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
181 fstrcpy(state->response.data.user_info.shell, user_info.shell);
182 state->response.data.user_info.primary_gid = user_info.primary_gid;
183 if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
184 &state->response.data.user_info.group_rid)) {
185 DEBUG(1, ("Could not extract group rid out of %s\n",
186 sid_string_dbg(&sid)));
187 return WINBINDD_ERROR;
190 return WINBINDD_OK;
193 struct getpwsid_state {
194 struct winbindd_cli_state *state;
195 struct winbindd_domain *domain;
196 char *username;
197 char *fullname;
198 char *homedir;
199 char *shell;
200 DOM_SID user_sid;
201 uid_t uid;
202 DOM_SID group_sid;
203 gid_t gid;
204 bool username_mapped;
207 static void getpwsid_queryuser_recv(void *private_data, bool success,
208 const char *acct_name,
209 const char *full_name,
210 const char *homedir,
211 const char *shell,
212 gid_t gid,
213 uint32 group_rid);
214 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid);
215 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid);
217 static void winbindd_getpwsid(struct winbindd_cli_state *state,
218 const DOM_SID *sid)
220 struct getpwsid_state *s;
222 s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
223 if (s == NULL) {
224 DEBUG(0, ("talloc failed\n"));
225 goto error;
228 s->state = state;
229 s->domain = find_domain_from_sid_noinit(sid);
230 if (s->domain == NULL) {
231 DEBUG(3, ("Could not find domain for sid %s\n",
232 sid_string_dbg(sid)));
233 goto error;
236 sid_copy(&s->user_sid, sid);
238 query_user_async(s->state->mem_ctx, s->domain, sid,
239 getpwsid_queryuser_recv, s);
240 return;
242 error:
243 request_error(state);
246 static void getpwsid_queryuser_recv(void *private_data, bool success,
247 const char *acct_name,
248 const char *full_name,
249 const char *homedir,
250 const char *shell,
251 gid_t gid,
252 uint32 group_rid)
254 fstring username;
255 struct getpwsid_state *s =
256 talloc_get_type_abort(private_data, struct getpwsid_state);
257 char *mapped_name;
258 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
260 if (!success) {
261 DEBUG(5, ("Could not query domain %s SID %s\n",
262 s->domain->name, sid_string_dbg(&s->user_sid)));
263 request_error(s->state);
264 return;
267 if ( acct_name && *acct_name ) {
268 fstrcpy( username, acct_name );
269 } else {
270 char *domain_name = NULL;
271 enum lsa_SidType type;
272 char *user_name = NULL;
273 struct winbindd_domain *domain = NULL;
275 domain = find_lookup_domain_from_sid(&s->user_sid);
276 if (domain == NULL) {
277 DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
278 sid_string_dbg(&s->user_sid)));
279 request_error(s->state);
280 return;
282 winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
283 &s->user_sid, &domain_name,
284 &user_name, &type );
286 /* If this still fails we ar4e done. Just error out */
287 if ( !user_name ) {
288 DEBUG(5,("Could not obtain a name for SID %s\n",
289 sid_string_dbg(&s->user_sid)));
290 request_error(s->state);
291 return;
294 fstrcpy( username, user_name );
297 strlower_m( username );
298 s->username = talloc_strdup(s->state->mem_ctx, username);
300 nt_status = normalize_name_map(s->state->mem_ctx, s->domain,
301 s->username, &mapped_name);
303 /* Basic removal of whitespace */
304 if (NT_STATUS_IS_OK(nt_status)) {
305 s->username = mapped_name;
306 s->username_mapped = false;
308 /* Complete name replacement */
309 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
310 s->username = mapped_name;
311 s->username_mapped = true;
313 /* No change at all */
314 else {
315 s->username_mapped = false;
318 s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
319 s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
320 s->shell = talloc_strdup(s->state->mem_ctx, shell);
321 s->gid = gid;
322 sid_copy(&s->group_sid, &s->domain->sid);
323 sid_append_rid(&s->group_sid, group_rid);
325 winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
326 getpwsid_sid2uid_recv, s);
329 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid)
331 struct getpwsid_state *s =
332 talloc_get_type_abort(private_data, struct getpwsid_state);
334 if (!success) {
335 DEBUG(5, ("Could not query uid for user %s\\%s\n",
336 s->domain->name, s->username));
337 request_error(s->state);
338 return;
341 s->uid = uid;
342 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
343 getpwsid_sid2gid_recv, s);
346 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
348 struct getpwsid_state *s =
349 talloc_get_type_abort(private_data, struct getpwsid_state);
350 struct winbindd_pw *pw;
351 fstring output_username;
353 /* allow the nss backend to override the primary group ID.
354 If the gid has already been set, then keep it.
355 This makes me feel dirty. If the nss backend already
356 gave us a gid, we don't really care whether the sid2gid()
357 call worked or not. --jerry */
359 if ( s->gid == (gid_t)-1 ) {
361 if (!success) {
362 DEBUG(5, ("Could not query gid for user %s\\%s\n",
363 s->domain->name, s->username));
364 goto failed;
367 /* take what the sid2gid() call gave us */
368 s->gid = gid;
371 pw = &s->state->response.data.pw;
372 pw->pw_uid = s->uid;
373 pw->pw_gid = s->gid;
375 /* allow username to be overridden by the alias mapping */
377 if ( s->username_mapped ) {
378 fstrcpy( output_username, s->username );
379 } else {
380 fill_domain_username(output_username, s->domain->name,
381 s->username, True);
384 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
385 safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
387 if (!fillup_pw_field(lp_template_homedir(), s->username,
388 s->domain->name, pw->pw_uid, pw->pw_gid,
389 s->homedir, pw->pw_dir)) {
390 DEBUG(5, ("Could not compose homedir\n"));
391 goto failed;
394 if (!fillup_pw_field(lp_template_shell(), s->username,
395 s->domain->name, pw->pw_uid, pw->pw_gid,
396 s->shell, pw->pw_shell)) {
397 DEBUG(5, ("Could not compose shell\n"));
398 goto failed;
401 /* Password - set to "*" as we can't generate anything useful here.
402 Authentication can be done using the pam_winbind module. */
404 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
406 request_ok(s->state);
407 return;
409 failed:
410 request_error(s->state);
413 /* Return a password structure from a username. */
415 static void getpwnam_name2sid_recv(void *private_data, bool success,
416 const DOM_SID *sid, enum lsa_SidType type);
418 void winbindd_getpwnam(struct winbindd_cli_state *state)
420 struct winbindd_domain *domain;
421 fstring domname, username;
422 char *mapped_user = NULL;
423 char *domuser;
424 size_t dusize;
425 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
427 domuser = state->request.data.username;
428 dusize = sizeof(state->request.data.username);
430 /* Ensure null termination (it's an fstring) */
431 domuser[dusize-1] = '\0';
433 DEBUG(3, ("[%5lu]: getpwnam %s\n",
434 (unsigned long)state->pid,
435 domuser));
437 nt_status = normalize_name_unmap(state->mem_ctx, domuser,
438 &mapped_user);
440 /* If we could not convert from an aliased name or a
441 normalized name, then just use the original name */
443 if (!NT_STATUS_IS_OK(nt_status) &&
444 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
446 mapped_user = domuser;
449 if (!parse_domain_user(mapped_user, domname, username)) {
450 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
451 request_error(state);
452 return;
455 /* Get info for the domain */
457 domain = find_domain_from_name_noinit(domname);
459 if (domain == NULL) {
460 DEBUG(7, ("could not find domain entry for domain %s. "
461 "Using primary domain\n", domname));
462 if ( (domain = find_our_domain()) == NULL ) {
463 DEBUG(0,("Cannot find my primary domain structure!\n"));
464 request_error(state);
465 return;
469 if (strequal(domname, lp_workgroup()) &&
470 lp_winbind_trusted_domains_only() ) {
471 DEBUG(7,("winbindd_getpwnam: My domain -- "
472 "rejecting getpwnam() for %s\\%s.\n",
473 domname, username));
474 request_error(state);
475 return;
478 /* Get rid and name type from name. The following costs 1 packet */
480 winbindd_lookupname_async(state->mem_ctx, domname, username,
481 getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
482 state);
485 static void getpwnam_name2sid_recv(void *private_data, bool success,
486 const DOM_SID *sid, enum lsa_SidType type)
488 struct winbindd_cli_state *state =
489 (struct winbindd_cli_state *)private_data;
490 fstring domname, username;
491 char *domuser = state->request.data.username;
493 if (!success) {
494 DEBUG(5, ("Could not lookup name for user %s\n", domuser));
495 request_error(state);
496 return;
499 if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
500 DEBUG(5, ("%s is not a user\n", domuser));
501 request_error(state);
502 return;
505 if (parse_domain_user(domuser, domname, username)) {
506 check_domain_trusted(domname, sid);
509 winbindd_getpwsid(state, sid);
512 static void getpwuid_recv(void *private_data, bool success, const char *sid)
514 struct winbindd_cli_state *state =
515 (struct winbindd_cli_state *)private_data;
516 DOM_SID user_sid;
518 if (!success) {
519 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
520 (unsigned long)(state->request.data.uid)));
521 request_error(state);
522 return;
525 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
526 (unsigned long)(state->request.data.uid), sid));
528 if (!string_to_sid(&user_sid, sid)) {
529 DEBUG(1,("uid2sid_recv: Could not convert sid %s "
530 "from string\n,", sid));
531 request_error(state);
532 return;
535 winbindd_getpwsid(state, &user_sid);
538 /* Return a password structure given a uid number */
539 void winbindd_getpwuid(struct winbindd_cli_state *state)
541 uid_t uid = state->request.data.uid;
543 DEBUG(3, ("[%5lu]: getpwuid %lu\n",
544 (unsigned long)state->pid,
545 (unsigned long)uid));
547 /* always query idmap via the async interface */
548 /* if this turns to be too slow we will add here
549 * a direct query to the cache */
550 winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state);
554 * set/get/endpwent functions
557 /* Rewind file pointer for ntdom passwd database */
559 static bool winbindd_setpwent_internal(struct winbindd_cli_state *state)
561 struct winbindd_domain *domain;
563 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
565 /* Check user has enabled this */
567 if (!lp_winbind_enum_users()) {
568 return False;
571 /* Free old static data if it exists */
573 if (state->getpwent_state != NULL) {
574 free_getent_state(state->getpwent_state);
575 state->getpwent_state = NULL;
578 /* Create sam pipes for each domain we know about */
580 for(domain = domain_list(); domain != NULL; domain = domain->next) {
581 struct getent_state *domain_state;
584 /* don't add our domaina if we are a PDC or if we
585 are a member of a Samba domain */
587 if ((IS_DC || lp_winbind_trusted_domains_only())
588 && strequal(domain->name, lp_workgroup())) {
589 continue;
592 /* Create a state record for this domain */
594 domain_state = SMB_MALLOC_P(struct getent_state);
595 if (!domain_state) {
596 DEBUG(0, ("malloc failed\n"));
597 return False;
600 ZERO_STRUCTP(domain_state);
602 fstrcpy(domain_state->domain_name, domain->name);
604 /* Add to list of open domains */
606 DLIST_ADD(state->getpwent_state, domain_state);
609 state->getpwent_initialized = True;
610 return True;
613 void winbindd_setpwent(struct winbindd_cli_state *state)
615 if (winbindd_setpwent_internal(state)) {
616 request_ok(state);
617 } else {
618 request_error(state);
622 /* Close file pointer to ntdom passwd database */
624 void winbindd_endpwent(struct winbindd_cli_state *state)
626 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
628 free_getent_state(state->getpwent_state);
629 state->getpwent_initialized = False;
630 state->getpwent_state = NULL;
631 request_ok(state);
634 /* Get partial list of domain users for a domain. We fill in the sam_entries,
635 and num_sam_entries fields with domain user information. The dispinfo_ndx
636 field is incremented to the index of the next user to fetch. Return True if
637 some users were returned, False otherwise. */
639 static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
641 NTSTATUS status;
642 uint32 num_entries;
643 WINBIND_USERINFO *info;
644 struct getpwent_user *name_list = NULL;
645 struct winbindd_domain *domain;
646 struct winbindd_methods *methods;
647 unsigned int i;
649 if (ent->num_sam_entries)
650 return False;
652 if (!(domain = find_domain_from_name(ent->domain_name))) {
653 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
654 ent->domain_name));
655 return False;
658 methods = domain->methods;
660 /* Free any existing user info */
662 SAFE_FREE(ent->sam_entries);
663 ent->num_sam_entries = 0;
665 /* Call query_user_list to get a list of usernames and user rids */
667 num_entries = 0;
669 status = methods->query_user_list(domain, mem_ctx, &num_entries, &info);
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(10,("get_sam_user_entries: "
673 "query_user_list failed with %s\n",
674 nt_errstr(status)));
675 return False;
678 if (num_entries) {
679 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user,
680 ent->num_sam_entries + num_entries);
681 if (!name_list) {
682 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
683 return False;
687 for (i = 0; i < num_entries; i++) {
688 /* Store account name and gecos */
689 if (!info[i].acct_name) {
690 fstrcpy(name_list[ent->num_sam_entries + i].name, "");
691 } else {
692 fstrcpy(name_list[ent->num_sam_entries + i].name,
693 info[i].acct_name);
695 if (!info[i].full_name) {
696 fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
697 } else {
698 fstrcpy(name_list[ent->num_sam_entries + i].gecos,
699 info[i].full_name);
701 if (!info[i].homedir) {
702 fstrcpy(name_list[ent->num_sam_entries + i].homedir,"");
703 } else {
704 fstrcpy(name_list[ent->num_sam_entries + i].homedir,
705 info[i].homedir);
707 if (!info[i].shell) {
708 fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
709 } else {
710 fstrcpy(name_list[ent->num_sam_entries + i].shell,
711 info[i].shell);
715 /* User and group ids */
716 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
717 &info[i].user_sid);
718 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
719 &info[i].group_sid);
722 ent->num_sam_entries += num_entries;
724 /* Fill in remaining fields */
726 ent->sam_entries = name_list;
727 ent->sam_entry_index = 0;
728 return ent->num_sam_entries > 0;
731 /* Fetch next passwd entry from ntdom database */
733 #define MAX_GETPWENT_USERS 500
735 void winbindd_getpwent(struct winbindd_cli_state *state)
737 struct getent_state *ent;
738 struct winbindd_pw *user_list;
739 int num_users, user_list_ndx;
741 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
743 /* Check user has enabled this */
745 if (!lp_winbind_enum_users()) {
746 request_error(state);
747 return;
750 /* Allocate space for returning a chunk of users */
752 num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
754 if (num_users == 0) {
755 request_error(state);
756 return;
759 user_list = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users);
760 if (!user_list) {
761 request_error(state);
762 return;
764 /* will be freed by process_request() */
765 state->response.extra_data.data = user_list;
767 memset(user_list, 0, num_users * sizeof(struct winbindd_pw));
769 if (!state->getpwent_initialized)
770 winbindd_setpwent_internal(state);
772 if (!(ent = state->getpwent_state)) {
773 request_error(state);
774 return;
777 /* Start sending back users */
779 for (user_list_ndx = 0; user_list_ndx < num_users; ) {
780 struct getpwent_user *name_list = NULL;
781 uint32 result;
783 /* Do we need to fetch another chunk of users? */
785 if (ent->num_sam_entries == ent->sam_entry_index) {
787 while(ent &&
788 !get_sam_user_entries(ent, state->mem_ctx)) {
789 struct getent_state *next_ent;
791 /* Free state information for this domain */
793 SAFE_FREE(ent->sam_entries);
795 next_ent = ent->next;
796 DLIST_REMOVE(state->getpwent_state, ent);
798 SAFE_FREE(ent);
799 ent = next_ent;
802 /* No more domains */
804 if (!ent)
805 break;
808 name_list = (struct getpwent_user *)ent->sam_entries;
810 /* Lookup user info */
812 result = winbindd_fill_pwent(
813 state->mem_ctx,
814 ent->domain_name,
815 name_list[ent->sam_entry_index].name,
816 &name_list[ent->sam_entry_index].user_sid,
817 &name_list[ent->sam_entry_index].group_sid,
818 name_list[ent->sam_entry_index].gecos,
819 name_list[ent->sam_entry_index].homedir,
820 name_list[ent->sam_entry_index].shell,
821 &user_list[user_list_ndx]);
823 /* Add user to return list */
825 if (result) {
827 user_list_ndx++;
828 state->response.data.num_entries++;
829 state->response.length += sizeof(struct winbindd_pw);
831 } else
832 DEBUG(1, ("could not lookup domain user %s\n",
833 name_list[ent->sam_entry_index].name));
835 ent->sam_entry_index++;
839 /* Out of domains */
841 if (user_list_ndx > 0)
842 request_ok(state);
843 else
844 request_error(state);
847 /* List domain users without mapping to unix ids */
848 void winbindd_list_users(struct winbindd_cli_state *state)
850 winbindd_list_ent(state, LIST_USERS);