source: branches/samba-3.2.x/source/winbindd/winbindd_user.c

Last change on this file was 228, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.6

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