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

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

Update Samba 3.3 to 3.3.1

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