Memory leaks and other fixes found by Coverity
[Samba/bb.git] / source / winbindd / winbindd_user.c
blob5356e16a74d599b8e31f8dcece3ea15c4ca64fd5
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 /* Resolve the uid number */
85 if (!NT_STATUS_IS_OK(idmap_sid_to_uid(dom_name, user_sid,
86 &pw->pw_uid))) {
87 DEBUG(1, ("error getting user id for sid %s\n",
88 sid_string_dbg(user_sid)));
89 return False;
92 /* Resolve the gid number */
94 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(dom_name, group_sid,
95 &pw->pw_gid))) {
96 DEBUG(1, ("error getting group id for sid %s\n",
97 sid_string_dbg(group_sid)));
98 return False;
101 strlower_m(user_name);
103 /* Username */
105 domain = find_domain_from_name_noinit(dom_name);
106 if (domain) {
107 nt_status = normalize_name_map(ctx, domain, user_name,
108 &mapped_name);
109 } else {
110 DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s. "
111 "Disabling name alias support\n", dom_name));
112 nt_status = NT_STATUS_NO_SUCH_DOMAIN;
115 /* Basic removal of whitespace */
116 if (NT_STATUS_IS_OK(nt_status)) {
117 fill_domain_username(output_username, dom_name, mapped_name, True);
119 /* Complete name replacement */
120 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
121 fstrcpy(output_username, mapped_name);
123 /* No change at all */
124 else {
125 fill_domain_username(output_username, dom_name, user_name, True);
128 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
130 /* Full name (gecos) */
132 safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
134 /* Home directory and shell */
136 if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
137 pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
138 return False;
140 if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
141 pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
142 return False;
144 /* Password - set to "*" as we can't generate anything useful here.
145 Authentication can be done using the pam_winbind module. */
147 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
149 return True;
152 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
154 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
155 struct winbindd_cli_state *state)
157 DOM_SID sid;
158 WINBIND_USERINFO user_info;
159 NTSTATUS status;
161 /* Ensure null termination */
162 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
164 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
165 state->request.data.sid));
167 if (!string_to_sid(&sid, state->request.data.sid)) {
168 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
169 return WINBINDD_ERROR;
172 status = domain->methods->query_user(domain, state->mem_ctx,
173 &sid, &user_info);
174 if (!NT_STATUS_IS_OK(status)) {
175 DEBUG(1, ("error getting user info for sid %s\n",
176 sid_string_dbg(&sid)));
177 return WINBINDD_ERROR;
180 fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
181 fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
182 fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
183 fstrcpy(state->response.data.user_info.shell, user_info.shell);
184 state->response.data.user_info.primary_gid = user_info.primary_gid;
185 if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
186 &state->response.data.user_info.group_rid)) {
187 DEBUG(1, ("Could not extract group rid out of %s\n",
188 sid_string_dbg(&sid)));
189 return WINBINDD_ERROR;
192 return WINBINDD_OK;
195 struct getpwsid_state {
196 struct winbindd_cli_state *state;
197 struct winbindd_domain *domain;
198 char *username;
199 char *fullname;
200 char *homedir;
201 char *shell;
202 DOM_SID user_sid;
203 uid_t uid;
204 DOM_SID group_sid;
205 gid_t gid;
206 bool username_mapped;
209 static void getpwsid_queryuser_recv(void *private_data, bool success,
210 const char *acct_name,
211 const char *full_name,
212 const char *homedir,
213 const char *shell,
214 gid_t gid,
215 uint32 group_rid);
216 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid);
217 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid);
219 static void winbindd_getpwsid(struct winbindd_cli_state *state,
220 const DOM_SID *sid)
222 struct getpwsid_state *s;
224 s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
225 if (s == NULL) {
226 DEBUG(0, ("talloc failed\n"));
227 goto error;
230 s->state = state;
231 s->domain = find_domain_from_sid_noinit(sid);
232 if (s->domain == NULL) {
233 DEBUG(3, ("Could not find domain for sid %s\n",
234 sid_string_dbg(sid)));
235 goto error;
238 sid_copy(&s->user_sid, sid);
240 query_user_async(s->state->mem_ctx, s->domain, sid,
241 getpwsid_queryuser_recv, s);
242 return;
244 error:
245 request_error(state);
248 static void getpwsid_queryuser_recv(void *private_data, bool success,
249 const char *acct_name,
250 const char *full_name,
251 const char *homedir,
252 const char *shell,
253 gid_t gid,
254 uint32 group_rid)
256 fstring username;
257 struct getpwsid_state *s =
258 talloc_get_type_abort(private_data, struct getpwsid_state);
259 char *mapped_name;
260 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
262 if (!success) {
263 DEBUG(5, ("Could not query domain %s SID %s\n",
264 s->domain->name, sid_string_dbg(&s->user_sid)));
265 request_error(s->state);
266 return;
269 if ( acct_name && *acct_name ) {
270 fstrcpy( username, acct_name );
271 } else {
272 char *domain_name = NULL;
273 enum lsa_SidType type;
274 char *user_name = NULL;
275 struct winbindd_domain *domain = NULL;
277 domain = find_lookup_domain_from_sid(&s->user_sid);
278 if (domain == NULL) {
279 DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
280 sid_string_dbg(&s->user_sid)));
281 request_error(s->state);
282 return;
284 winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
285 &s->user_sid, &domain_name,
286 &user_name, &type );
288 /* If this still fails we ar4e done. Just error out */
289 if ( !user_name ) {
290 DEBUG(5,("Could not obtain a name for SID %s\n",
291 sid_string_dbg(&s->user_sid)));
292 request_error(s->state);
293 return;
296 fstrcpy( username, user_name );
299 strlower_m( username );
300 s->username = talloc_strdup(s->state->mem_ctx, username);
302 nt_status = normalize_name_map(s->state->mem_ctx, s->domain,
303 s->username, &mapped_name);
305 /* Basic removal of whitespace */
306 if (NT_STATUS_IS_OK(nt_status)) {
307 s->username = mapped_name;
308 s->username_mapped = false;
310 /* Complete name replacement */
311 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
312 s->username = mapped_name;
313 s->username_mapped = true;
315 /* No change at all */
316 else {
317 s->username_mapped = false;
320 s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
321 s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
322 s->shell = talloc_strdup(s->state->mem_ctx, shell);
323 s->gid = gid;
324 sid_copy(&s->group_sid, &s->domain->sid);
325 sid_append_rid(&s->group_sid, group_rid);
327 winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
328 getpwsid_sid2uid_recv, s);
331 static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid)
333 struct getpwsid_state *s =
334 talloc_get_type_abort(private_data, struct getpwsid_state);
336 if (!success) {
337 DEBUG(5, ("Could not query uid for user %s\\%s\n",
338 s->domain->name, s->username));
339 request_error(s->state);
340 return;
343 s->uid = uid;
344 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
345 getpwsid_sid2gid_recv, s);
348 static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
350 struct getpwsid_state *s =
351 talloc_get_type_abort(private_data, struct getpwsid_state);
352 struct winbindd_pw *pw;
353 fstring output_username;
355 /* allow the nss backend to override the primary group ID.
356 If the gid has already been set, then keep it.
357 This makes me feel dirty. If the nss backend already
358 gave us a gid, we don't really care whether the sid2gid()
359 call worked or not. --jerry */
361 if ( s->gid == (gid_t)-1 ) {
363 if (!success) {
364 DEBUG(5, ("Could not query gid for user %s\\%s\n",
365 s->domain->name, s->username));
366 goto failed;
369 /* take what the sid2gid() call gave us */
370 s->gid = gid;
373 pw = &s->state->response.data.pw;
374 pw->pw_uid = s->uid;
375 pw->pw_gid = s->gid;
377 /* allow username to be overridden by the alias mapping */
379 if ( s->username_mapped ) {
380 fstrcpy( output_username, s->username );
381 } else {
382 fill_domain_username(output_username, s->domain->name,
383 s->username, True);
386 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
387 safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
389 if (!fillup_pw_field(lp_template_homedir(), s->username,
390 s->domain->name, pw->pw_uid, pw->pw_gid,
391 s->homedir, pw->pw_dir)) {
392 DEBUG(5, ("Could not compose homedir\n"));
393 goto failed;
396 if (!fillup_pw_field(lp_template_shell(), s->username,
397 s->domain->name, pw->pw_uid, pw->pw_gid,
398 s->shell, pw->pw_shell)) {
399 DEBUG(5, ("Could not compose shell\n"));
400 goto failed;
403 /* Password - set to "*" as we can't generate anything useful here.
404 Authentication can be done using the pam_winbind module. */
406 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
408 request_ok(s->state);
409 return;
411 failed:
412 request_error(s->state);
415 /* Return a password structure from a username. */
417 static void getpwnam_name2sid_recv(void *private_data, bool success,
418 const DOM_SID *sid, enum lsa_SidType type);
420 void winbindd_getpwnam(struct winbindd_cli_state *state)
422 struct winbindd_domain *domain;
423 fstring domname, username;
424 char *mapped_user = NULL;
425 char *domuser;
426 size_t dusize;
427 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
429 domuser = state->request.data.username;
430 dusize = sizeof(state->request.data.username);
432 /* Ensure null termination (it's an fstring) */
433 domuser[dusize-1] = '\0';
435 DEBUG(3, ("[%5lu]: getpwnam %s\n",
436 (unsigned long)state->pid,
437 domuser));
439 nt_status = normalize_name_unmap(state->mem_ctx, domuser,
440 &mapped_user);
442 /* If we could not convert from an aliased name or a
443 normalized name, then just use the original name */
445 if (!NT_STATUS_IS_OK(nt_status) &&
446 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
448 mapped_user = domuser;
451 if (!parse_domain_user(mapped_user, domname, username)) {
452 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
453 request_error(state);
454 return;
457 /* Get info for the domain */
459 domain = find_domain_from_name_noinit(domname);
461 if (domain == NULL) {
462 DEBUG(7, ("could not find domain entry for domain %s. "
463 "Using primary domain\n", domname));
464 if ( (domain = find_our_domain()) == NULL ) {
465 DEBUG(0,("Cannot find my primary domain structure!\n"));
466 request_error(state);
467 return;
471 if (strequal(domname, lp_workgroup()) &&
472 lp_winbind_trusted_domains_only() ) {
473 DEBUG(7,("winbindd_getpwnam: My domain -- "
474 "rejecting getpwnam() for %s\\%s.\n",
475 domname, username));
476 request_error(state);
477 return;
480 /* Get rid and name type from name. The following costs 1 packet */
482 winbindd_lookupname_async(state->mem_ctx, domname, username,
483 getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
484 state);
487 static void getpwnam_name2sid_recv(void *private_data, bool success,
488 const DOM_SID *sid, enum lsa_SidType type)
490 struct winbindd_cli_state *state =
491 (struct winbindd_cli_state *)private_data;
492 fstring domname, username;
493 char *domuser = state->request.data.username;
495 if (!success) {
496 DEBUG(5, ("Could not lookup name for user %s\n", domuser));
497 request_error(state);
498 return;
501 if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
502 DEBUG(5, ("%s is not a user\n", domuser));
503 request_error(state);
504 return;
507 if (parse_domain_user(domuser, domname, username)) {
508 check_domain_trusted(domname, sid);
511 winbindd_getpwsid(state, sid);
514 static void getpwuid_recv(void *private_data, bool success, const char *sid)
516 struct winbindd_cli_state *state =
517 (struct winbindd_cli_state *)private_data;
518 DOM_SID user_sid;
520 if (!success) {
521 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
522 (unsigned long)(state->request.data.uid)));
523 request_error(state);
524 return;
527 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
528 (unsigned long)(state->request.data.uid), sid));
530 if (!string_to_sid(&user_sid, sid)) {
531 DEBUG(1,("uid2sid_recv: Could not convert sid %s "
532 "from string\n,", sid));
533 request_error(state);
534 return;
537 winbindd_getpwsid(state, &user_sid);
540 /* Return a password structure given a uid number */
541 void winbindd_getpwuid(struct winbindd_cli_state *state)
543 uid_t uid = state->request.data.uid;
545 DEBUG(3, ("[%5lu]: getpwuid %lu\n",
546 (unsigned long)state->pid,
547 (unsigned long)uid));
549 /* always query idmap via the async interface */
550 /* if this turns to be too slow we will add here
551 * a direct query to the cache */
552 winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state);
556 * set/get/endpwent functions
559 /* Rewind file pointer for ntdom passwd database */
561 static bool winbindd_setpwent_internal(struct winbindd_cli_state *state)
563 struct winbindd_domain *domain;
565 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
567 /* Check user has enabled this */
569 if (!lp_winbind_enum_users()) {
570 return False;
573 /* Free old static data if it exists */
575 if (state->getpwent_state != NULL) {
576 free_getent_state(state->getpwent_state);
577 state->getpwent_state = NULL;
580 /* Create sam pipes for each domain we know about */
582 for(domain = domain_list(); domain != NULL; domain = domain->next) {
583 struct getent_state *domain_state;
586 /* don't add our domaina if we are a PDC or if we
587 are a member of a Samba domain */
589 if ((IS_DC || lp_winbind_trusted_domains_only())
590 && strequal(domain->name, lp_workgroup())) {
591 continue;
594 /* Create a state record for this domain */
596 domain_state = SMB_MALLOC_P(struct getent_state);
597 if (!domain_state) {
598 DEBUG(0, ("malloc failed\n"));
599 return False;
602 ZERO_STRUCTP(domain_state);
604 fstrcpy(domain_state->domain_name, domain->name);
606 /* Add to list of open domains */
608 DLIST_ADD(state->getpwent_state, domain_state);
611 state->getpwent_initialized = True;
612 return True;
615 void winbindd_setpwent(struct winbindd_cli_state *state)
617 if (winbindd_setpwent_internal(state)) {
618 request_ok(state);
619 } else {
620 request_error(state);
624 /* Close file pointer to ntdom passwd database */
626 void winbindd_endpwent(struct winbindd_cli_state *state)
628 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
630 free_getent_state(state->getpwent_state);
631 state->getpwent_initialized = False;
632 state->getpwent_state = NULL;
633 request_ok(state);
636 /* Get partial list of domain users for a domain. We fill in the sam_entries,
637 and num_sam_entries fields with domain user information. The dispinfo_ndx
638 field is incremented to the index of the next user to fetch. Return True if
639 some users were returned, False otherwise. */
641 static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
643 NTSTATUS status;
644 uint32 num_entries;
645 WINBIND_USERINFO *info;
646 struct getpwent_user *name_list = NULL;
647 struct winbindd_domain *domain;
648 struct winbindd_methods *methods;
649 unsigned int i;
651 if (ent->num_sam_entries)
652 return False;
654 if (!(domain = find_domain_from_name(ent->domain_name))) {
655 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
656 ent->domain_name));
657 return False;
660 methods = domain->methods;
662 /* Free any existing user info */
664 SAFE_FREE(ent->sam_entries);
665 ent->num_sam_entries = 0;
667 /* Call query_user_list to get a list of usernames and user rids */
669 num_entries = 0;
671 status = methods->query_user_list(domain, mem_ctx, &num_entries, &info);
673 if (!NT_STATUS_IS_OK(status)) {
674 DEBUG(10,("get_sam_user_entries: "
675 "query_user_list failed with %s\n",
676 nt_errstr(status)));
677 return False;
680 if (num_entries) {
681 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user,
682 ent->num_sam_entries + num_entries);
683 if (!name_list) {
684 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
685 return False;
689 for (i = 0; i < num_entries; i++) {
690 /* Store account name and gecos */
691 if (!info[i].acct_name) {
692 fstrcpy(name_list[ent->num_sam_entries + i].name, "");
693 } else {
694 fstrcpy(name_list[ent->num_sam_entries + i].name,
695 info[i].acct_name);
697 if (!info[i].full_name) {
698 fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
699 } else {
700 fstrcpy(name_list[ent->num_sam_entries + i].gecos,
701 info[i].full_name);
703 if (!info[i].homedir) {
704 fstrcpy(name_list[ent->num_sam_entries + i].homedir,"");
705 } else {
706 fstrcpy(name_list[ent->num_sam_entries + i].homedir,
707 info[i].homedir);
709 if (!info[i].shell) {
710 fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
711 } else {
712 fstrcpy(name_list[ent->num_sam_entries + i].shell,
713 info[i].shell);
717 /* User and group ids */
718 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
719 &info[i].user_sid);
720 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
721 &info[i].group_sid);
724 ent->num_sam_entries += num_entries;
726 /* Fill in remaining fields */
728 ent->sam_entries = name_list;
729 ent->sam_entry_index = 0;
730 return ent->num_sam_entries > 0;
733 /* Fetch next passwd entry from ntdom database */
735 #define MAX_GETPWENT_USERS 500
737 void winbindd_getpwent(struct winbindd_cli_state *state)
739 struct getent_state *ent;
740 struct winbindd_pw *user_list;
741 int num_users, user_list_ndx;
743 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
745 /* Check user has enabled this */
747 if (!lp_winbind_enum_users()) {
748 request_error(state);
749 return;
752 /* Allocate space for returning a chunk of users */
754 num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
756 if (num_users == 0) {
757 request_error(state);
758 return;
761 user_list = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users);
762 if (!user_list) {
763 request_error(state);
764 return;
766 /* will be freed by process_request() */
767 state->response.extra_data.data = user_list;
769 memset(user_list, 0, num_users * sizeof(struct winbindd_pw));
771 if (!state->getpwent_initialized)
772 winbindd_setpwent_internal(state);
774 if (!(ent = state->getpwent_state)) {
775 request_error(state);
776 return;
779 /* Start sending back users */
781 for (user_list_ndx = 0; user_list_ndx < num_users; ) {
782 struct getpwent_user *name_list = NULL;
783 uint32 result;
785 /* Do we need to fetch another chunk of users? */
787 if (ent->num_sam_entries == ent->sam_entry_index) {
789 while(ent &&
790 !get_sam_user_entries(ent, state->mem_ctx)) {
791 struct getent_state *next_ent;
793 /* Free state information for this domain */
795 SAFE_FREE(ent->sam_entries);
797 next_ent = ent->next;
798 DLIST_REMOVE(state->getpwent_state, ent);
800 SAFE_FREE(ent);
801 ent = next_ent;
804 /* No more domains */
806 if (!ent)
807 break;
810 name_list = (struct getpwent_user *)ent->sam_entries;
812 /* Lookup user info */
814 result = winbindd_fill_pwent(
815 state->mem_ctx,
816 ent->domain_name,
817 name_list[ent->sam_entry_index].name,
818 &name_list[ent->sam_entry_index].user_sid,
819 &name_list[ent->sam_entry_index].group_sid,
820 name_list[ent->sam_entry_index].gecos,
821 name_list[ent->sam_entry_index].homedir,
822 name_list[ent->sam_entry_index].shell,
823 &user_list[user_list_ndx]);
825 /* Add user to return list */
827 if (result) {
829 user_list_ndx++;
830 state->response.data.num_entries++;
831 state->response.length += sizeof(struct winbindd_pw);
833 } else
834 DEBUG(1, ("could not lookup domain user %s\n",
835 name_list[ent->sam_entry_index].name));
837 ent->sam_entry_index++;
841 /* Out of domains */
843 if (user_list_ndx > 0)
844 request_ok(state);
845 else
846 request_error(state);
849 /* List domain users without mapping to unix ids */
850 void winbindd_list_users(struct winbindd_cli_state *state)
852 winbindd_list_ent(state, LIST_USERS);