source: trunk-3.0/source/nsswitch/winbindd_user.c@ 101

Last change on this file since 101 was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

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