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/>.
28 #define DBGC_CLASS DBGC_WINBIND
30 static bool fillup_pw_field(const char *lp_template
,
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
,
54 templ
= talloc_sub_specified(NULL
, lp_template
,
62 safe_strcpy(out
, templ
, sizeof(fstring
) - 1);
68 /* Fill a pwent structure with information we have obtained */
70 static bool winbindd_fill_pwent(TALLOC_CTX
*ctx
, char *dom_name
, char *user_name
,
71 DOM_SID
*user_sid
, DOM_SID
*group_sid
,
72 char *full_name
, char *homedir
, char *shell
,
73 struct winbindd_pw
*pw
)
75 fstring output_username
;
76 char *mapped_name
= NULL
;
77 struct winbindd_domain
*domain
= NULL
;
78 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
80 if (!pw
|| !dom_name
|| !user_name
)
83 domain
= find_domain_from_name_noinit(dom_name
);
85 DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s.\n",
87 nt_status
= NT_STATUS_NO_SUCH_DOMAIN
;
91 /* Resolve the uid number */
93 if (!NT_STATUS_IS_OK(idmap_sid_to_uid(domain
->have_idmap_config
?
94 dom_name
: "", user_sid
,
96 DEBUG(1, ("error getting user id for sid %s\n",
97 sid_string_dbg(user_sid
)));
101 /* Resolve the gid number */
103 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain
->have_idmap_config
?
104 dom_name
: "", group_sid
,
106 DEBUG(1, ("error getting group id for sid %s\n",
107 sid_string_dbg(group_sid
)));
113 strlower_m(user_name
);
114 nt_status
= normalize_name_map(ctx
, domain
, user_name
, &mapped_name
);
116 /* Basic removal of whitespace */
117 if (NT_STATUS_IS_OK(nt_status
)) {
118 fill_domain_username(output_username
, dom_name
, mapped_name
, True
);
120 /* Complete name replacement */
121 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
122 fstrcpy(output_username
, mapped_name
);
124 /* No change at all */
126 fill_domain_username(output_username
, dom_name
, user_name
, True
);
129 safe_strcpy(pw
->pw_name
, output_username
, sizeof(pw
->pw_name
) - 1);
131 /* Full name (gecos) */
133 safe_strcpy(pw
->pw_gecos
, full_name
, sizeof(pw
->pw_gecos
) - 1);
135 /* Home directory and shell */
137 if (!fillup_pw_field(lp_template_homedir(), user_name
, dom_name
,
138 pw
->pw_uid
, pw
->pw_gid
, homedir
, pw
->pw_dir
))
141 if (!fillup_pw_field(lp_template_shell(), user_name
, dom_name
,
142 pw
->pw_uid
, pw
->pw_gid
, shell
, pw
->pw_shell
))
145 /* Password - set to "*" as we can't generate anything useful here.
146 Authentication can be done using the pam_winbind module. */
148 safe_strcpy(pw
->pw_passwd
, "*", sizeof(pw
->pw_passwd
) - 1);
153 /* Wrapper for domain->methods->query_user, only on the parent->child pipe */
155 enum winbindd_result
winbindd_dual_userinfo(struct winbindd_domain
*domain
,
156 struct winbindd_cli_state
*state
)
159 WINBIND_USERINFO user_info
;
162 /* Ensure null termination */
163 state
->request
->data
.sid
[sizeof(state
->request
->data
.sid
)-1]='\0';
165 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state
->pid
,
166 state
->request
->data
.sid
));
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
;
173 status
= domain
->methods
->query_user(domain
, state
->mem_ctx
,
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
;
181 fstrcpy(state
->response
->data
.user_info
.acct_name
,
182 user_info
.acct_name
);
183 fstrcpy(state
->response
->data
.user_info
.full_name
,
184 user_info
.full_name
);
185 fstrcpy(state
->response
->data
.user_info
.homedir
, user_info
.homedir
);
186 fstrcpy(state
->response
->data
.user_info
.shell
, user_info
.shell
);
187 state
->response
->data
.user_info
.primary_gid
= user_info
.primary_gid
;
188 if (!sid_peek_check_rid(&domain
->sid
, &user_info
.group_sid
,
189 &state
->response
->data
.user_info
.group_rid
)) {
190 DEBUG(1, ("Could not extract group rid out of %s\n",
191 sid_string_dbg(&sid
)));
192 return WINBINDD_ERROR
;
198 struct getpwsid_state
{
199 struct winbindd_cli_state
*state
;
200 struct winbindd_domain
*domain
;
209 bool username_mapped
;
212 static void getpwsid_queryuser_recv(void *private_data
, bool success
,
213 const char *acct_name
,
214 const char *full_name
,
219 static void getpwsid_sid2uid_recv(void *private_data
, bool success
, uid_t uid
);
220 static void getpwsid_sid2gid_recv(void *private_data
, bool success
, gid_t gid
);
222 static void getpwsid_queryuser(struct winbindd_cli_state
*state
,
225 struct getpwsid_state
*s
;
227 s
= TALLOC_ZERO_P(state
->mem_ctx
, struct getpwsid_state
);
229 DEBUG(0, ("talloc failed\n"));
234 s
->domain
= find_domain_from_sid_noinit(sid
);
235 if (s
->domain
== NULL
) {
236 DEBUG(3, ("Could not find domain for sid %s\n",
237 sid_string_dbg(sid
)));
241 sid_copy(&s
->user_sid
, sid
);
243 query_user_async(s
->state
->mem_ctx
, s
->domain
, sid
,
244 getpwsid_queryuser_recv
, s
);
248 request_error(state
);
251 static void getpwsid_queryuser_recv(void *private_data
, bool success
,
252 const char *acct_name
,
253 const char *full_name
,
260 struct getpwsid_state
*s
=
261 talloc_get_type_abort(private_data
, struct getpwsid_state
);
263 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
266 DEBUG(5, ("Could not query domain %s SID %s\n",
267 s
->domain
->name
, sid_string_dbg(&s
->user_sid
)));
268 request_error(s
->state
);
272 if ( acct_name
&& *acct_name
) {
273 fstrcpy( username
, acct_name
);
275 char *domain_name
= NULL
;
276 enum lsa_SidType type
;
277 char *user_name
= NULL
;
278 struct winbindd_domain
*domain
= NULL
;
280 domain
= find_lookup_domain_from_sid(&s
->user_sid
);
281 if (domain
== NULL
) {
282 DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
283 sid_string_dbg(&s
->user_sid
)));
284 request_error(s
->state
);
287 winbindd_lookup_name_by_sid(s
->state
->mem_ctx
, domain
,
288 &s
->user_sid
, &domain_name
,
291 /* If this still fails we ar4e done. Just error out */
293 DEBUG(5,("Could not obtain a name for SID %s\n",
294 sid_string_dbg(&s
->user_sid
)));
295 request_error(s
->state
);
299 fstrcpy( username
, user_name
);
302 strlower_m( username
);
303 s
->username
= talloc_strdup(s
->state
->mem_ctx
, username
);
305 nt_status
= normalize_name_map(s
->state
->mem_ctx
, s
->domain
,
306 s
->username
, &mapped_name
);
308 /* Basic removal of whitespace */
309 if (NT_STATUS_IS_OK(nt_status
)) {
310 s
->username
= mapped_name
;
311 s
->username_mapped
= false;
313 /* Complete name replacement */
314 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
)) {
315 s
->username
= mapped_name
;
316 s
->username_mapped
= true;
318 /* No change at all */
320 s
->username_mapped
= false;
323 s
->fullname
= talloc_strdup(s
->state
->mem_ctx
, full_name
);
324 s
->homedir
= talloc_strdup(s
->state
->mem_ctx
, homedir
);
325 s
->shell
= talloc_strdup(s
->state
->mem_ctx
, shell
);
327 sid_copy(&s
->group_sid
, &s
->domain
->sid
);
328 sid_append_rid(&s
->group_sid
, group_rid
);
330 winbindd_sid2uid_async(s
->state
->mem_ctx
, &s
->user_sid
,
331 getpwsid_sid2uid_recv
, s
);
334 static void getpwsid_sid2uid_recv(void *private_data
, bool success
, uid_t uid
)
336 struct getpwsid_state
*s
=
337 talloc_get_type_abort(private_data
, struct getpwsid_state
);
340 DEBUG(5, ("Could not query uid for user %s\\%s\n",
341 s
->domain
->name
, s
->username
));
342 request_error(s
->state
);
347 winbindd_sid2gid_async(s
->state
->mem_ctx
, &s
->group_sid
,
348 getpwsid_sid2gid_recv
, s
);
351 static void getpwsid_sid2gid_recv(void *private_data
, bool success
, gid_t gid
)
353 struct getpwsid_state
*s
=
354 talloc_get_type_abort(private_data
, struct getpwsid_state
);
355 struct winbindd_pw
*pw
;
356 fstring output_username
;
358 /* allow the nss backend to override the primary group ID.
359 If the gid has already been set, then keep it.
360 This makes me feel dirty. If the nss backend already
361 gave us a gid, we don't really care whether the sid2gid()
362 call worked or not. --jerry */
364 if ( s
->gid
== (gid_t
)-1 ) {
367 DEBUG(5, ("Could not query gid for user %s\\%s\n",
368 s
->domain
->name
, s
->username
));
372 /* take what the sid2gid() call gave us */
376 pw
= &s
->state
->response
->data
.pw
;
380 /* allow username to be overridden by the alias mapping */
382 if ( s
->username_mapped
) {
383 fstrcpy( output_username
, s
->username
);
385 fill_domain_username(output_username
, s
->domain
->name
,
389 safe_strcpy(pw
->pw_name
, output_username
, sizeof(pw
->pw_name
) - 1);
390 safe_strcpy(pw
->pw_gecos
, s
->fullname
, sizeof(pw
->pw_gecos
) - 1);
392 if (!fillup_pw_field(lp_template_homedir(), s
->username
,
393 s
->domain
->name
, pw
->pw_uid
, pw
->pw_gid
,
394 s
->homedir
, pw
->pw_dir
)) {
395 DEBUG(5, ("Could not compose homedir\n"));
399 if (!fillup_pw_field(lp_template_shell(), s
->username
,
400 s
->domain
->name
, pw
->pw_uid
, pw
->pw_gid
,
401 s
->shell
, pw
->pw_shell
)) {
402 DEBUG(5, ("Could not compose shell\n"));
406 /* Password - set to "*" as we can't generate anything useful here.
407 Authentication can be done using the pam_winbind module. */
409 safe_strcpy(pw
->pw_passwd
, "*", sizeof(pw
->pw_passwd
) - 1);
411 request_ok(s
->state
);
415 request_error(s
->state
);
418 /* Return a password structure from a username. */
420 static void getpwnam_name2sid_recv(void *private_data
, bool success
,
421 const DOM_SID
*sid
, enum lsa_SidType type
);
423 void winbindd_getpwnam(struct winbindd_cli_state
*state
)
425 struct winbindd_domain
*domain
;
426 fstring domname
, username
;
427 char *mapped_user
= NULL
;
430 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
432 domuser
= state
->request
->data
.username
;
433 dusize
= sizeof(state
->request
->data
.username
);
435 /* Ensure null termination (it's an fstring) */
436 domuser
[dusize
-1] = '\0';
438 DEBUG(3, ("[%5lu]: getpwnam %s\n",
439 (unsigned long)state
->pid
,
442 nt_status
= normalize_name_unmap(state
->mem_ctx
, domuser
,
445 /* If we could not convert from an aliased name or a
446 normalized name, then just use the original name */
448 if (!NT_STATUS_IS_OK(nt_status
) &&
449 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
451 mapped_user
= domuser
;
454 if (!parse_domain_user(mapped_user
, domname
, username
)) {
455 DEBUG(5, ("Could not parse domain user: %s\n", domuser
));
456 request_error(state
);
460 /* Get info for the domain */
462 domain
= find_domain_from_name_noinit(domname
);
464 if (domain
== NULL
) {
465 DEBUG(7, ("could not find domain entry for domain %s. "
466 "Using primary domain\n", domname
));
467 if ( (domain
= find_our_domain()) == NULL
) {
468 DEBUG(0,("Cannot find my primary domain structure!\n"));
469 request_error(state
);
474 if (strequal(domname
, lp_workgroup()) &&
475 lp_winbind_trusted_domains_only() ) {
476 DEBUG(7,("winbindd_getpwnam: My domain -- "
477 "rejecting getpwnam() for %s\\%s.\n",
479 request_error(state
);
483 /* Get rid and name type from name. The following costs 1 packet */
485 winbindd_lookupname_async(state
->mem_ctx
, domname
, username
,
486 getpwnam_name2sid_recv
, WINBINDD_GETPWNAM
,
490 static void getpwnam_name2sid_recv(void *private_data
, bool success
,
491 const DOM_SID
*sid
, enum lsa_SidType type
)
493 struct winbindd_cli_state
*state
=
494 (struct winbindd_cli_state
*)private_data
;
495 fstring domname
, username
;
496 char *domuser
= state
->request
->data
.username
;
499 DEBUG(5, ("Could not lookup name for user %s\n", domuser
));
500 request_error(state
);
504 if ((type
!= SID_NAME_USER
) && (type
!= SID_NAME_COMPUTER
)) {
505 DEBUG(5, ("%s is not a user\n", domuser
));
506 request_error(state
);
510 if (parse_domain_user(domuser
, domname
, username
)) {
511 check_domain_trusted(domname
, sid
);
514 getpwsid_queryuser(state
, sid
);
517 static void getpwuid_recv(void *private_data
, bool success
, const char *sid
)
519 struct winbindd_cli_state
*state
=
520 (struct winbindd_cli_state
*)private_data
;
524 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
525 (unsigned long)(state
->request
->data
.uid
)));
526 request_error(state
);
530 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
531 (unsigned long)(state
->request
->data
.uid
), sid
));
533 if (!string_to_sid(&user_sid
, sid
)) {
534 DEBUG(1,("uid2sid_recv: Could not convert sid %s "
535 "from string\n,", sid
));
536 request_error(state
);
540 getpwsid_queryuser(state
, &user_sid
);
543 /* Return a password structure given a uid number */
544 void winbindd_getpwuid(struct winbindd_cli_state
*state
)
546 uid_t uid
= state
->request
->data
.uid
;
548 DEBUG(3, ("[%5lu]: getpwuid %lu\n",
549 (unsigned long)state
->pid
,
550 (unsigned long)uid
));
552 /* always query idmap via the async interface */
553 /* if this turns to be too slow we will add here
554 * a direct query to the cache */
555 winbindd_uid2sid_async(state
->mem_ctx
, uid
, getpwuid_recv
, state
);
558 /* Return a password structure given a sid */
559 void winbindd_getpwsid(struct winbindd_cli_state
*state
)
563 /* Ensure null termination */
564 state
->request
->data
.sid
[sizeof(state
->request
->data
.sid
)-1]='\0';
566 DEBUG(3, ("[%5lu]: getpwsid %s\n", (unsigned long)state
->pid
,
567 state
->request
->data
.sid
));
569 if (!string_to_sid(&sid
, state
->request
->data
.sid
)) {
570 DEBUG(5, ("%s not a SID\n", state
->request
->data
.sid
));
571 request_error(state
);
575 getpwsid_queryuser(state
, &sid
);
579 * set/get/endpwent functions
582 /* Rewind file pointer for ntdom passwd database */
584 static bool winbindd_setpwent_internal(struct winbindd_cli_state
*state
)
586 struct winbindd_domain
*domain
;
588 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state
->pid
));
590 /* Check user has enabled this */
592 if (!lp_winbind_enum_users()) {
596 /* Free old static data if it exists */
598 if (state
->getpwent_state
!= NULL
) {
599 free_getent_state(state
->getpwent_state
);
600 state
->getpwent_state
= NULL
;
603 /* Create sam pipes for each domain we know about */
605 for(domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
606 struct getent_state
*domain_state
;
609 /* don't add our domaina if we are a PDC or if we
610 are a member of a Samba domain */
612 if ((IS_DC
|| lp_winbind_trusted_domains_only())
613 && strequal(domain
->name
, lp_workgroup())) {
617 /* Create a state record for this domain */
619 domain_state
= SMB_MALLOC_P(struct getent_state
);
621 DEBUG(0, ("malloc failed\n"));
625 ZERO_STRUCTP(domain_state
);
627 fstrcpy(domain_state
->domain_name
, domain
->name
);
629 /* Add to list of open domains */
631 DLIST_ADD(state
->getpwent_state
, domain_state
);
634 state
->getpwent_initialized
= True
;
638 void winbindd_setpwent(struct winbindd_cli_state
*state
)
640 if (winbindd_setpwent_internal(state
)) {
643 request_error(state
);
647 /* Close file pointer to ntdom passwd database */
649 void winbindd_endpwent(struct winbindd_cli_state
*state
)
651 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state
->pid
));
653 free_getent_state(state
->getpwent_state
);
654 state
->getpwent_initialized
= False
;
655 state
->getpwent_state
= NULL
;
659 /* Get partial list of domain users for a domain. We fill in the sam_entries,
660 and num_sam_entries fields with domain user information. The dispinfo_ndx
661 field is incremented to the index of the next user to fetch. Return True if
662 some users were returned, False otherwise. */
664 static bool get_sam_user_entries(struct getent_state
*ent
, TALLOC_CTX
*mem_ctx
)
668 WINBIND_USERINFO
*info
;
669 struct getpwent_user
*name_list
= NULL
;
670 struct winbindd_domain
*domain
;
671 struct winbindd_methods
*methods
;
674 if (ent
->num_sam_entries
)
677 if (!(domain
= find_domain_from_name(ent
->domain_name
))) {
678 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
683 methods
= domain
->methods
;
685 /* Free any existing user info */
687 SAFE_FREE(ent
->sam_entries
);
688 ent
->num_sam_entries
= 0;
690 /* Call query_user_list to get a list of usernames and user rids */
694 status
= methods
->query_user_list(domain
, mem_ctx
, &num_entries
, &info
);
696 if (!NT_STATUS_IS_OK(status
)) {
697 DEBUG(10,("get_sam_user_entries: "
698 "query_user_list failed with %s\n",
704 name_list
= SMB_REALLOC_ARRAY(name_list
, struct getpwent_user
,
705 ent
->num_sam_entries
+ num_entries
);
707 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
712 for (i
= 0; i
< num_entries
; i
++) {
713 /* Store account name and gecos */
714 if (!info
[i
].acct_name
) {
715 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].name
, "");
717 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].name
,
720 if (!info
[i
].full_name
) {
721 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].gecos
, "");
723 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].gecos
,
726 if (!info
[i
].homedir
) {
727 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].homedir
,"");
729 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].homedir
,
732 if (!info
[i
].shell
) {
733 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].shell
, "");
735 fstrcpy(name_list
[ent
->num_sam_entries
+ i
].shell
,
740 /* User and group ids */
741 sid_copy(&name_list
[ent
->num_sam_entries
+i
].user_sid
,
743 sid_copy(&name_list
[ent
->num_sam_entries
+i
].group_sid
,
747 ent
->num_sam_entries
+= num_entries
;
749 /* Fill in remaining fields */
751 ent
->sam_entries
= name_list
;
752 ent
->sam_entry_index
= 0;
753 return ent
->num_sam_entries
> 0;
756 /* Fetch next passwd entry from ntdom database */
758 #define MAX_GETPWENT_USERS 500
760 void winbindd_getpwent(struct winbindd_cli_state
*state
)
762 struct getent_state
*ent
;
763 struct winbindd_pw
*user_list
;
764 int num_users
, user_list_ndx
;
766 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state
->pid
));
768 /* Check user has enabled this */
770 if (!lp_winbind_enum_users()) {
771 request_error(state
);
775 /* Allocate space for returning a chunk of users */
777 num_users
= MIN(MAX_GETPWENT_USERS
, state
->request
->data
.num_entries
);
779 if (num_users
== 0) {
780 request_error(state
);
784 user_list
= talloc_zero_array(state
->mem_ctx
, struct winbindd_pw
,
787 request_error(state
);
790 state
->response
->extra_data
.data
= user_list
;
792 if (!state
->getpwent_initialized
)
793 winbindd_setpwent_internal(state
);
795 if (!(ent
= state
->getpwent_state
)) {
796 request_error(state
);
800 /* Start sending back users */
802 for (user_list_ndx
= 0; user_list_ndx
< num_users
; ) {
803 struct getpwent_user
*name_list
= NULL
;
806 /* Do we need to fetch another chunk of users? */
808 if (ent
->num_sam_entries
== ent
->sam_entry_index
) {
811 !get_sam_user_entries(ent
, state
->mem_ctx
)) {
812 struct getent_state
*next_ent
;
814 /* Free state information for this domain */
816 SAFE_FREE(ent
->sam_entries
);
818 next_ent
= ent
->next
;
819 DLIST_REMOVE(state
->getpwent_state
, ent
);
825 /* No more domains */
831 name_list
= (struct getpwent_user
*)ent
->sam_entries
;
833 /* Lookup user info */
835 result
= winbindd_fill_pwent(
838 name_list
[ent
->sam_entry_index
].name
,
839 &name_list
[ent
->sam_entry_index
].user_sid
,
840 &name_list
[ent
->sam_entry_index
].group_sid
,
841 name_list
[ent
->sam_entry_index
].gecos
,
842 name_list
[ent
->sam_entry_index
].homedir
,
843 name_list
[ent
->sam_entry_index
].shell
,
844 &user_list
[user_list_ndx
]);
846 /* Add user to return list */
851 state
->response
->data
.num_entries
++;
852 state
->response
->length
+= sizeof(struct winbindd_pw
);
855 DEBUG(1, ("could not lookup domain user %s\n",
856 name_list
[ent
->sam_entry_index
].name
));
858 ent
->sam_entry_index
++;
864 if (user_list_ndx
> 0)
867 request_error(state
);
870 /* List domain users without mapping to unix ids */
871 void winbindd_list_users(struct winbindd_cli_state
*state
)
873 winbindd_list_ent(state
, LIST_USERS
);