r24267: Fix the build farm
[Samba/gebeck_regimport.git] / source3 / nsswitch / winbindd_user.c
blobfac2832f564e37e82db7e117831cc8dc035288f1
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(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 fstring sid_string;
78 if (!pw || !dom_name || !user_name)
79 return False;
81 /* Resolve the uid number */
83 if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid))) {
84 DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid)));
85 return False;
88 /* Resolve the gid number */
90 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid))) {
91 DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid)));
92 return False;
95 strlower_m(user_name);
97 /* Username */
99 fill_domain_username(output_username, dom_name, user_name, True);
101 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
103 /* Full name (gecos) */
105 safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
107 /* Home directory and shell */
109 if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
110 pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
111 return False;
113 if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
114 pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
115 return False;
117 /* Password - set to "*" as we can't generate anything useful here.
118 Authentication can be done using the pam_winbind module. */
120 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
122 return True;
125 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
127 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
128 struct winbindd_cli_state *state)
130 DOM_SID sid;
131 WINBIND_USERINFO user_info;
132 NTSTATUS status;
134 /* Ensure null termination */
135 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
137 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
138 state->request.data.sid));
140 if (!string_to_sid(&sid, state->request.data.sid)) {
141 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
142 return WINBINDD_ERROR;
145 status = domain->methods->query_user(domain, state->mem_ctx,
146 &sid, &user_info);
147 if (!NT_STATUS_IS_OK(status)) {
148 DEBUG(1, ("error getting user info for sid %s\n",
149 sid_string_static(&sid)));
150 return WINBINDD_ERROR;
153 fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
154 fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
155 fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
156 fstrcpy(state->response.data.user_info.shell, user_info.shell);
157 state->response.data.user_info.primary_gid = user_info.primary_gid;
158 if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
159 &state->response.data.user_info.group_rid)) {
160 DEBUG(1, ("Could not extract group rid out of %s\n",
161 sid_string_static(&sid)));
162 return WINBINDD_ERROR;
165 return WINBINDD_OK;
168 struct getpwsid_state {
169 struct winbindd_cli_state *state;
170 struct winbindd_domain *domain;
171 char *username;
172 char *fullname;
173 char *homedir;
174 char *shell;
175 DOM_SID user_sid;
176 uid_t uid;
177 DOM_SID group_sid;
178 gid_t gid;
181 static void getpwsid_queryuser_recv(void *private_data, BOOL success,
182 const char *acct_name,
183 const char *full_name,
184 const char *homedir,
185 const char *shell,
186 uint32 gid,
187 uint32 group_rid);
188 static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid);
189 static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
191 static void winbindd_getpwsid(struct winbindd_cli_state *state,
192 const DOM_SID *sid)
194 struct getpwsid_state *s;
196 s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
197 if (s == NULL) {
198 DEBUG(0, ("talloc failed\n"));
199 goto error;
202 s->state = state;
203 s->domain = find_domain_from_sid_noinit(sid);
204 if (s->domain == NULL) {
205 DEBUG(3, ("Could not find domain for sid %s\n",
206 sid_string_static(sid)));
207 goto error;
210 sid_copy(&s->user_sid, sid);
212 query_user_async(s->state->mem_ctx, s->domain, sid,
213 getpwsid_queryuser_recv, s);
214 return;
216 error:
217 request_error(state);
220 static void getpwsid_queryuser_recv(void *private_data, BOOL success,
221 const char *acct_name,
222 const char *full_name,
223 const char *homedir,
224 const char *shell,
225 uint32 gid,
226 uint32 group_rid)
228 fstring username;
229 struct getpwsid_state *s =
230 talloc_get_type_abort(private_data, struct getpwsid_state);
232 if (!success) {
233 DEBUG(5, ("Could not query domain %s SID %s\n", s->domain->name,
234 sid_string_static(&s->user_sid)));
235 request_error(s->state);
236 return;
239 if ( acct_name && *acct_name ) {
240 fstrcpy( username, acct_name );
241 } else {
242 char *domain_name = NULL;
243 enum lsa_SidType type;
244 char *user_name = NULL;
245 struct winbindd_domain *domain = NULL;
247 domain = find_lookup_domain_from_sid(&s->user_sid);
248 if (domain == NULL) {
249 DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
250 sid_string_static(&s->user_sid)));
251 request_error(s->state);
252 return;
254 winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
255 &s->user_sid, &domain_name,
256 &user_name, &type );
258 /* If this still fails we ar4e done. Just error out */
259 if ( !user_name ) {
260 DEBUG(5,("Could not obtain a name for SID %s\n",
261 sid_string_static(&s->user_sid)));
262 request_error(s->state);
263 return;
266 fstrcpy( username, user_name );
269 strlower_m( username );
270 s->username = talloc_strdup(s->state->mem_ctx, username);
272 ws_name_replace( s->username, WB_REPLACE_CHAR );
274 s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
275 s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
276 s->shell = talloc_strdup(s->state->mem_ctx, shell);
277 s->gid = gid;
278 sid_copy(&s->group_sid, &s->domain->sid);
279 sid_append_rid(&s->group_sid, group_rid);
281 winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
282 getpwsid_sid2uid_recv, s);
285 static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid)
287 struct getpwsid_state *s =
288 talloc_get_type_abort(private_data, struct getpwsid_state);
290 if (!success) {
291 DEBUG(5, ("Could not query uid for user %s\\%s\n",
292 s->domain->name, s->username));
293 request_error(s->state);
294 return;
297 s->uid = uid;
298 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
299 getpwsid_sid2gid_recv, s);
302 static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
304 struct getpwsid_state *s =
305 talloc_get_type_abort(private_data, struct getpwsid_state);
306 struct winbindd_pw *pw;
307 fstring output_username;
309 /* allow the nss backend to override the primary group ID.
310 If the gid has already been set, then keep it.
311 This makes me feel dirty. If the nss backend already
312 gave us a gid, we don't really care whether the sid2gid()
313 call worked or not. --jerry */
315 if ( s->gid == (gid_t)-1 ) {
317 if (!success) {
318 DEBUG(5, ("Could not query gid for user %s\\%s\n",
319 s->domain->name, s->username));
320 goto failed;
323 /* take what the sid2gid() call gave us */
324 s->gid = gid;
327 pw = &s->state->response.data.pw;
328 pw->pw_uid = s->uid;
329 pw->pw_gid = s->gid;
330 fill_domain_username(output_username, s->domain->name, s->username, True);
331 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
332 safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
334 if (!fillup_pw_field(lp_template_homedir(), s->username, s->domain->name,
335 pw->pw_uid, pw->pw_gid, s->homedir, pw->pw_dir)) {
336 DEBUG(5, ("Could not compose homedir\n"));
337 goto failed;
340 if (!fillup_pw_field(lp_template_shell(), s->username, s->domain->name,
341 pw->pw_uid, pw->pw_gid, s->shell, pw->pw_shell)) {
342 DEBUG(5, ("Could not compose shell\n"));
343 goto failed;
346 /* Password - set to "*" as we can't generate anything useful here.
347 Authentication can be done using the pam_winbind module. */
349 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
351 request_ok(s->state);
352 return;
354 failed:
355 request_error(s->state);
358 /* Return a password structure from a username. */
360 static void getpwnam_name2sid_recv(void *private_data, BOOL success,
361 const DOM_SID *sid, enum lsa_SidType type);
363 void winbindd_getpwnam(struct winbindd_cli_state *state)
365 struct winbindd_domain *domain;
366 fstring domname, username;
368 /* Ensure null termination */
369 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
371 DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
372 state->request.data.username));
374 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
376 if (!parse_domain_user(state->request.data.username, domname,
377 username)) {
378 DEBUG(5, ("Could not parse domain user: %s\n",
379 state->request.data.username));
380 request_error(state);
381 return;
384 /* Get info for the domain */
386 domain = find_domain_from_name(domname);
388 if (domain == NULL) {
389 DEBUG(7, ("could not find domain entry for domain %s. "
390 "Using primary domain\n", domname));
391 if ( (domain = find_our_domain()) == NULL ) {
392 DEBUG(0,("Cannot find my primary domain structure!\n"));
393 request_error(state);
394 return;
398 if ( strequal(domname, lp_workgroup()) && lp_winbind_trusted_domains_only() ) {
399 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n",
400 domname, username));
401 request_error(state);
402 return;
405 /* Get rid and name type from name. The following costs 1 packet */
407 winbindd_lookupname_async(state->mem_ctx, domname, username,
408 getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
409 state);
412 static void getpwnam_name2sid_recv(void *private_data, BOOL success,
413 const DOM_SID *sid, enum lsa_SidType type)
415 struct winbindd_cli_state *state =
416 (struct winbindd_cli_state *)private_data;
417 fstring domname, username;
419 if (!success) {
420 DEBUG(5, ("Could not lookup name for user %s\n",
421 state->request.data.username));
422 request_error(state);
423 return;
426 if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
427 DEBUG(5, ("%s is not a user\n", state->request.data.username));
428 request_error(state);
429 return;
432 if ( parse_domain_user(state->request.data.username, domname, username) ) {
433 check_domain_trusted( domname, sid );
438 winbindd_getpwsid(state, sid);
441 static void getpwuid_recv(void *private_data, BOOL success, const char *sid)
443 struct winbindd_cli_state *state =
444 (struct winbindd_cli_state *)private_data;
445 DOM_SID user_sid;
447 if (!success) {
448 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
449 (unsigned long)(state->request.data.uid)));
450 request_error(state);
451 return;
454 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
455 (unsigned long)(state->request.data.uid), sid));
457 string_to_sid(&user_sid, sid);
458 winbindd_getpwsid(state, &user_sid);
461 /* Return a password structure given a uid number */
462 void winbindd_getpwuid(struct winbindd_cli_state *state)
464 DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
465 (unsigned long)state->request.data.uid));
467 /* always query idmap via the async interface */
468 /* if this turns to be too slow we will add here a direct query to the cache */
469 winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, getpwuid_recv, state);
473 * set/get/endpwent functions
476 /* Rewind file pointer for ntdom passwd database */
478 static BOOL winbindd_setpwent_internal(struct winbindd_cli_state *state)
480 struct winbindd_domain *domain;
482 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
484 /* Check user has enabled this */
486 if (!lp_winbind_enum_users()) {
487 return False;
490 /* Free old static data if it exists */
492 if (state->getpwent_state != NULL) {
493 free_getent_state(state->getpwent_state);
494 state->getpwent_state = NULL;
497 #if 0 /* JERRY */
498 /* add any local users we have */
500 if ( (domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL )
501 return False;
503 ZERO_STRUCTP(domain_state);
505 /* Add to list of open domains */
507 DLIST_ADD(state->getpwent_state, domain_state);
508 #endif
510 /* Create sam pipes for each domain we know about */
512 for(domain = domain_list(); domain != NULL; domain = domain->next) {
513 struct getent_state *domain_state;
516 /* don't add our domaina if we are a PDC or if we
517 are a member of a Samba domain */
519 if ( (IS_DC || lp_winbind_trusted_domains_only())
520 && strequal(domain->name, lp_workgroup()) )
522 continue;
525 /* Create a state record for this domain */
527 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
528 DEBUG(0, ("malloc failed\n"));
529 return False;
532 ZERO_STRUCTP(domain_state);
534 fstrcpy(domain_state->domain_name, domain->name);
536 /* Add to list of open domains */
538 DLIST_ADD(state->getpwent_state, domain_state);
541 state->getpwent_initialized = True;
542 return True;
545 void winbindd_setpwent(struct winbindd_cli_state *state)
547 if (winbindd_setpwent_internal(state)) {
548 request_ok(state);
549 } else {
550 request_error(state);
554 /* Close file pointer to ntdom passwd database */
556 void winbindd_endpwent(struct winbindd_cli_state *state)
558 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
560 free_getent_state(state->getpwent_state);
561 state->getpwent_initialized = False;
562 state->getpwent_state = NULL;
563 request_ok(state);
566 /* Get partial list of domain users for a domain. We fill in the sam_entries,
567 and num_sam_entries fields with domain user information. The dispinfo_ndx
568 field is incremented to the index of the next user to fetch. Return True if
569 some users were returned, False otherwise. */
571 static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
573 NTSTATUS status;
574 uint32 num_entries;
575 WINBIND_USERINFO *info;
576 struct getpwent_user *name_list = NULL;
577 struct winbindd_domain *domain;
578 struct winbindd_methods *methods;
579 unsigned int i;
581 if (ent->num_sam_entries)
582 return False;
584 if (!(domain = find_domain_from_name(ent->domain_name))) {
585 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
586 ent->domain_name));
587 return False;
590 methods = domain->methods;
592 /* Free any existing user info */
594 SAFE_FREE(ent->sam_entries);
595 ent->num_sam_entries = 0;
597 /* Call query_user_list to get a list of usernames and user rids */
599 num_entries = 0;
601 status = methods->query_user_list(domain, mem_ctx, &num_entries,
602 &info);
604 if (!NT_STATUS_IS_OK(status)) {
605 DEBUG(10,("get_sam_user_entries: query_user_list failed with %s\n",
606 nt_errstr(status) ));
607 return False;
610 if (num_entries) {
611 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user, ent->num_sam_entries + num_entries);
613 if (!name_list) {
614 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
615 return False;
619 for (i = 0; i < num_entries; i++) {
620 /* Store account name and gecos */
621 if (!info[i].acct_name) {
622 fstrcpy(name_list[ent->num_sam_entries + i].name, "");
623 } else {
624 fstrcpy(name_list[ent->num_sam_entries + i].name,
625 info[i].acct_name);
627 if (!info[i].full_name) {
628 fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
629 } else {
630 fstrcpy(name_list[ent->num_sam_entries + i].gecos,
631 info[i].full_name);
633 if (!info[i].homedir) {
634 fstrcpy(name_list[ent->num_sam_entries + i].homedir, "");
635 } else {
636 fstrcpy(name_list[ent->num_sam_entries + i].homedir,
637 info[i].homedir);
639 if (!info[i].shell) {
640 fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
641 } else {
642 fstrcpy(name_list[ent->num_sam_entries + i].shell,
643 info[i].shell);
647 /* User and group ids */
648 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
649 &info[i].user_sid);
650 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
651 &info[i].group_sid);
654 ent->num_sam_entries += num_entries;
656 /* Fill in remaining fields */
658 ent->sam_entries = name_list;
659 ent->sam_entry_index = 0;
660 return ent->num_sam_entries > 0;
663 /* Fetch next passwd entry from ntdom database */
665 #define MAX_GETPWENT_USERS 500
667 void winbindd_getpwent(struct winbindd_cli_state *state)
669 struct getent_state *ent;
670 struct winbindd_pw *user_list;
671 int num_users, user_list_ndx;
673 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
675 /* Check user has enabled this */
677 if (!lp_winbind_enum_users()) {
678 request_error(state);
679 return;
682 /* Allocate space for returning a chunk of users */
684 num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
686 if (num_users == 0) {
687 request_error(state);
688 return;
691 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users)) == NULL) {
692 request_error(state);
693 return;
696 memset(state->response.extra_data.data, 0, num_users *
697 sizeof(struct winbindd_pw));
699 user_list = (struct winbindd_pw *)state->response.extra_data.data;
701 if (!state->getpwent_initialized)
702 winbindd_setpwent_internal(state);
704 if (!(ent = state->getpwent_state)) {
705 request_error(state);
706 return;
709 /* Start sending back users */
711 for (user_list_ndx = 0; user_list_ndx < num_users; ) {
712 struct getpwent_user *name_list = NULL;
713 uint32 result;
715 /* Do we need to fetch another chunk of users? */
717 if (ent->num_sam_entries == ent->sam_entry_index) {
719 while(ent &&
720 !get_sam_user_entries(ent, state->mem_ctx)) {
721 struct getent_state *next_ent;
723 /* Free state information for this domain */
725 SAFE_FREE(ent->sam_entries);
727 next_ent = ent->next;
728 DLIST_REMOVE(state->getpwent_state, ent);
730 SAFE_FREE(ent);
731 ent = next_ent;
734 /* No more domains */
736 if (!ent)
737 break;
740 name_list = (struct getpwent_user *)ent->sam_entries;
742 /* Lookup user info */
744 result = winbindd_fill_pwent(
745 ent->domain_name,
746 name_list[ent->sam_entry_index].name,
747 &name_list[ent->sam_entry_index].user_sid,
748 &name_list[ent->sam_entry_index].group_sid,
749 name_list[ent->sam_entry_index].gecos,
750 name_list[ent->sam_entry_index].homedir,
751 name_list[ent->sam_entry_index].shell,
752 &user_list[user_list_ndx]);
754 /* Add user to return list */
756 if (result) {
758 user_list_ndx++;
759 state->response.data.num_entries++;
760 state->response.length +=
761 sizeof(struct winbindd_pw);
763 } else
764 DEBUG(1, ("could not lookup domain user %s\n",
765 name_list[ent->sam_entry_index].name));
767 ent->sam_entry_index++;
771 /* Out of domains */
773 if (user_list_ndx > 0)
774 request_ok(state);
775 else
776 request_error(state);
779 /* List domain users without mapping to unix ids */
781 void winbindd_list_users(struct winbindd_cli_state *state)
783 struct winbindd_domain *domain;
784 WINBIND_USERINFO *info;
785 const char *which_domain;
786 uint32 num_entries = 0, total_entries = 0;
787 char *extra_data = NULL;
788 int extra_data_len = 0;
789 enum winbindd_result rv = WINBINDD_ERROR;
791 DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
793 /* Ensure null termination */
794 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
795 which_domain = state->request.domain_name;
797 /* Enumerate over trusted domains */
799 for (domain = domain_list(); domain; domain = domain->next) {
800 NTSTATUS status;
801 struct winbindd_methods *methods;
802 unsigned int i;
804 /* if we have a domain name restricting the request and this
805 one in the list doesn't match, then just bypass the remainder
806 of the loop */
808 if ( *which_domain && !strequal(which_domain, domain->name) )
809 continue;
811 methods = domain->methods;
813 /* Query display info */
814 status = methods->query_user_list(domain, state->mem_ctx,
815 &num_entries, &info);
817 if (!NT_STATUS_IS_OK(status)) {
818 continue;
821 if (num_entries == 0)
822 continue;
824 /* Allocate some memory for extra data */
825 total_entries += num_entries;
827 extra_data = (char *)SMB_REALLOC(
828 extra_data, sizeof(fstring) * total_entries);
830 if (!extra_data) {
831 DEBUG(0,("failed to enlarge buffer!\n"));
832 goto done;
835 /* Pack user list into extra data fields */
837 for (i = 0; i < num_entries; i++) {
838 fstring acct_name, name;
840 if (!info[i].acct_name) {
841 fstrcpy(acct_name, "");
842 } else {
843 fstrcpy(acct_name, info[i].acct_name);
846 fill_domain_username(name, domain->name, acct_name, True);
848 /* Append to extra data */
849 memcpy(&extra_data[extra_data_len], name,
850 strlen(name));
851 extra_data_len += strlen(name);
852 extra_data[extra_data_len++] = ',';
856 /* Assign extra_data fields in response structure */
858 if (extra_data) {
859 extra_data[extra_data_len - 1] = '\0';
860 state->response.extra_data.data = extra_data;
861 state->response.length += extra_data_len;
864 /* No domains responded but that's still OK so don't return an
865 error. */
867 rv = WINBINDD_OK;
869 done:
871 if (rv == WINBINDD_OK)
872 request_ok(state);
873 else
874 request_error(state);