2 Unix SMB/CIFS implementation.
4 Windows NT Domain nsswitch module
6 Copyright (C) Tim Potter 2000
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with this library; if not, write to the
20 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 #include "winbind_client.h"
29 #include <ns_daemon.h>
32 #define MAX_GETPWENT_USERS 250
33 #define MAX_GETGRENT_USERS 250
35 /* Prototypes from wb_common.c */
37 extern int winbindd_fd
;
43 static int send_next_request(nsd_file_t
*, struct winbindd_request
*);
44 static int do_list(int state
, nsd_file_t
*rq
);
46 static nsd_file_t
*current_rq
= NULL
;
47 static int current_winbind_xid
= 0;
48 static int next_winbind_xid
= 0;
50 typedef struct winbind_xid
{
53 struct winbindd_request
*request
;
54 struct winbind_xid
*next
;
57 static winbind_xid_t
*winbind_xids
= (winbind_xid_t
*)0;
60 winbind_xid_new(int xid
, nsd_file_t
*rq
, struct winbindd_request
*request
)
64 nsd_logprintf(NSD_LOG_LOW
,
65 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
67 new = (winbind_xid_t
*)nsd_calloc(1,sizeof(winbind_xid_t
));
69 nsd_logprintf(NSD_LOG_RESOURCE
,"winbind_xid_new: failed malloc\n");
75 new->request
= request
;
76 new->next
= winbind_xids
;
83 ** This routine will look down the xid list and return the request
84 ** associated with an xid. We remove the record if it is found.
87 winbind_xid_lookup(int xid
, struct winbindd_request
**requestp
)
89 winbind_xid_t
**last
, *dx
;
92 for (last
= &winbind_xids
, dx
= winbind_xids
; dx
&& (dx
->xid
!= xid
);
93 last
= &dx
->next
, dx
= dx
->next
);
97 *requestp
= dx
->request
;
100 nsd_logprintf(NSD_LOG_LOW
,
101 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
102 xid
, result
, dx
->request
);
108 winbind_startnext_timeout(nsd_file_t
**rqp
, nsd_times_t
*to
)
111 struct winbindd_request
*request
;
113 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind startnext)\n");
116 nsd_timeout_remove(rq
);
117 request
= to
->t_clientdata
;
118 return(send_next_request(rq
, request
));
125 struct winbindd_request
*request
;
128 * Check for queued requests
131 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind) unqueue xid %d\n",
132 current_winbind_xid
);
133 rq
= winbind_xid_lookup(current_winbind_xid
++, &request
);
134 /* cause a timeout on the queued request so we can send it */
135 nsd_timeout_new(rq
,1,winbind_startnext_timeout
,request
);
140 do_request(nsd_file_t
*rq
, struct winbindd_request
*request
)
142 if (winbind_xids
== NULL
) {
144 * No outstanding requests.
145 * Send off the request to winbindd
147 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) sending request\n");
148 return(send_next_request(rq
, request
));
151 * Just queue it up for now - previous callout or timout
154 nsd_logprintf(NSD_LOG_MIN
,
155 "lookup (winbind): queue request xid = %d\n",
157 return(winbind_xid_new(next_winbind_xid
++, rq
, request
));
162 winbind_callback(nsd_file_t
**rqp
, int fd
)
164 struct winbindd_response response
;
165 struct winbindd_pw
*pw
= &response
.data
.pw
;
166 struct winbindd_gr
*gr
= &response
.data
.gr
;
175 nsd_logprintf(NSD_LOG_MIN
, "entering callback (winbind)\n");
180 nsd_timeout_remove(rq
);
181 nsd_callback_remove(fd
);
183 ZERO_STRUCT(response
);
184 status
= winbindd_get_response(&response
);
186 if (status
!= NSS_STATUS_SUCCESS
) {
187 /* free any extra data area in response structure */
188 free_response(&response
);
189 nsd_logprintf(NSD_LOG_MIN
,
190 "callback (winbind) returning not found, status = %d\n",
192 rq
->f_status
= NS_NOTFOUND
;
196 maxlen
= sizeof(result
) - 1;
198 switch ((int)rq
->f_cmd_data
) {
199 case WINBINDD_WINS_BYNAME
:
200 case WINBINDD_WINS_BYIP
:
201 snprintf(result
,maxlen
,"%s\n",response
.data
.winsresp
);
203 case WINBINDD_GETPWUID
:
204 case WINBINDD_GETPWNAM
:
205 snprintf(result
,maxlen
,"%s:%s:%d:%d:%s:%s:%s\n",
214 case WINBINDD_GETGRNAM
:
215 case WINBINDD_GETGRGID
:
216 if (gr
->num_gr_mem
&& response
.extra_data
)
217 members
= response
.extra_data
;
220 snprintf(result
,maxlen
,"%s:%s:%d:%s\n",
221 gr
->gr_name
, gr
->gr_passwd
, gr
->gr_gid
, members
);
223 case WINBINDD_SETGRENT
:
224 case WINBINDD_SETPWENT
:
225 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - SETPWENT/SETGRENT\n");
226 free_response(&response
);
227 return(do_list(1,rq
));
228 case WINBINDD_GETGRENT
:
229 case WINBINDD_GETGRLST
:
230 nsd_logprintf(NSD_LOG_MIN
,
231 "callback (winbind) - %d GETGRENT responses\n",
232 response
.data
.num_entries
);
233 if (response
.data
.num_entries
) {
234 gr
= (struct winbindd_gr
*)response
.extra_data
;
236 nsd_logprintf(NSD_LOG_MIN
, " no extra_data\n");
237 free_response(&response
);
240 members
= (char *)response
.extra_data
+
241 (response
.data
.num_entries
* sizeof(struct winbindd_gr
));
242 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
243 snprintf(result
,maxlen
,"%s:%s:%d:%s\n",
244 gr
->gr_name
, gr
->gr_passwd
, gr
->gr_gid
,
245 &members
[gr
->gr_mem_ofs
]);
246 nsd_logprintf(NSD_LOG_MIN
, " GETGRENT %s\n",result
);
247 nsd_append_element(rq
,NS_SUCCESS
,result
,strlen(result
));
251 i
= response
.data
.num_entries
;
252 free_response(&response
);
253 if (i
< MAX_GETPWENT_USERS
)
254 return(do_list(2,rq
));
256 return(do_list(1,rq
));
257 case WINBINDD_GETPWENT
:
258 nsd_logprintf(NSD_LOG_MIN
,
259 "callback (winbind) - %d GETPWENT responses\n",
260 response
.data
.num_entries
);
261 if (response
.data
.num_entries
) {
262 pw
= (struct winbindd_pw
*)response
.extra_data
;
264 nsd_logprintf(NSD_LOG_MIN
, " no extra_data\n");
265 free_response(&response
);
268 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
269 snprintf(result
,maxlen
,"%s:%s:%d:%d:%s:%s:%s",
277 nsd_logprintf(NSD_LOG_MIN
, " GETPWENT %s\n",result
);
278 nsd_append_element(rq
,NS_SUCCESS
,result
,strlen(result
));
282 i
= response
.data
.num_entries
;
283 free_response(&response
);
284 if (i
< MAX_GETPWENT_USERS
)
285 return(do_list(2,rq
));
287 return(do_list(1,rq
));
288 case WINBINDD_ENDGRENT
:
289 case WINBINDD_ENDPWENT
:
290 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - ENDPWENT/ENDGRENT\n");
291 nsd_append_element(rq
,NS_SUCCESS
,"\n",1);
292 free_response(&response
);
295 free_response(&response
);
296 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - no valid command\n");
299 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) %s\n", result
);
300 /* free any extra data area in response structure */
301 free_response(&response
);
302 nsd_set_result(rq
,NS_SUCCESS
,result
,strlen(result
),VOLATILE
);
307 winbind_timeout(nsd_file_t
**rqp
, nsd_times_t
*to
)
313 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind)\n");
318 /* Remove the callback and timeout */
319 nsd_callback_remove(winbindd_fd
);
320 nsd_timeout_remove(rq
);
322 rq
->f_status
= NS_NOTFOUND
;
327 send_next_request(nsd_file_t
*rq
, struct winbindd_request
*request
)
334 nsd_logprintf(NSD_LOG_MIN
, "send_next_request (winbind) %d to = %d\n",
335 rq
->f_cmd_data
, timeout
);
336 status
= winbindd_send_request((int)rq
->f_cmd_data
,request
);
339 if (status
!= NSS_STATUS_SUCCESS
) {
340 nsd_logprintf(NSD_LOG_MIN
,
341 "send_next_request (winbind) error status = %d\n",status
);
342 rq
->f_status
= status
;
349 * Set up callback and timeouts
351 nsd_logprintf(NSD_LOG_MIN
, "send_next_request (winbind) fd = %d\n",winbindd_fd
);
352 nsd_callback_new(winbindd_fd
,winbind_callback
,NSD_READ
);
353 nsd_timeout_new(rq
,timeout
,winbind_timeout
,(void *)0);
359 nsd_logprintf(NSD_LOG_MIN
, "entering init (winbind)\n");
363 int lookup(nsd_file_t
*rq
)
367 struct winbindd_request
*request
;
369 nsd_logprintf(NSD_LOG_MIN
, "entering lookup (winbind)\n");
373 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
374 key
= nsd_attr_fetch_string(rq
->f_attrs
, "key", (char*)0);
375 if (! map
|| ! key
) {
376 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) table or key not defined\n");
377 rq
->f_status
= NS_BADREQ
;
381 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind %s)\n",map
);
383 request
= (struct winbindd_request
*)nsd_calloc(1,sizeof(struct winbindd_request
));
385 nsd_logprintf(NSD_LOG_RESOURCE
,
386 "lookup (winbind): failed malloc\n");
390 if (strcasecmp(map
,"passwd.byuid") == 0) {
391 request
->data
.uid
= atoi(key
);
392 rq
->f_cmd_data
= (void *)WINBINDD_GETPWUID
;
393 } else if (strcasecmp(map
,"passwd.byname") == 0) {
394 strncpy(request
->data
.username
, key
,
395 sizeof(request
->data
.username
) - 1);
396 request
->data
.username
[sizeof(request
->data
.username
) - 1] = '\0';
397 rq
->f_cmd_data
= (void *)WINBINDD_GETPWNAM
;
398 } else if (strcasecmp(map
,"group.byname") == 0) {
399 strncpy(request
->data
.groupname
, key
,
400 sizeof(request
->data
.groupname
) - 1);
401 request
->data
.groupname
[sizeof(request
->data
.groupname
) - 1] = '\0';
402 rq
->f_cmd_data
= (void *)WINBINDD_GETGRNAM
;
403 } else if (strcasecmp(map
,"group.bygid") == 0) {
404 request
->data
.gid
= atoi(key
);
405 rq
->f_cmd_data
= (void *)WINBINDD_GETGRGID
;
406 } else if (strcasecmp(map
,"hosts.byname") == 0) {
407 strncpy(request
->data
.winsreq
, key
, sizeof(request
->data
.winsreq
) - 1);
408 request
->data
.winsreq
[sizeof(request
->data
.winsreq
) - 1] = '\0';
409 rq
->f_cmd_data
= (void *)WINBINDD_WINS_BYNAME
;
410 } else if (strcasecmp(map
,"hosts.byaddr") == 0) {
411 strncpy(request
->data
.winsreq
, key
, sizeof(request
->data
.winsreq
) - 1);
412 request
->data
.winsreq
[sizeof(request
->data
.winsreq
) - 1] = '\0';
413 rq
->f_cmd_data
= (void *)WINBINDD_WINS_BYIP
;
416 * Don't understand this map - just return not found
418 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) unknown table\n");
420 rq
->f_status
= NS_NOTFOUND
;
424 return(do_request(rq
, request
));
427 int list(nsd_file_t
*rq
)
431 nsd_logprintf(NSD_LOG_MIN
, "entering list (winbind)\n");
435 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
437 nsd_logprintf(NSD_LOG_MIN
, "list (winbind) table not defined\n");
438 rq
->f_status
= NS_BADREQ
;
442 nsd_logprintf(NSD_LOG_MIN
, "list (winbind %s)\n",map
);
444 return (do_list(0,rq
));
448 do_list(int state
, nsd_file_t
*rq
)
451 struct winbindd_request
*request
;
453 nsd_logprintf(NSD_LOG_MIN
, "entering do_list (winbind) state = %d\n",state
);
455 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
456 request
= (struct winbindd_request
*)nsd_calloc(1,sizeof(struct winbindd_request
));
458 nsd_logprintf(NSD_LOG_RESOURCE
,
459 "do_list (winbind): failed malloc\n");
463 if (strcasecmp(map
,"passwd.byname") == 0) {
466 rq
->f_cmd_data
= (void *)WINBINDD_SETPWENT
;
469 request
->data
.num_entries
= MAX_GETPWENT_USERS
;
470 rq
->f_cmd_data
= (void *)WINBINDD_GETPWENT
;
473 rq
->f_cmd_data
= (void *)WINBINDD_ENDPWENT
;
476 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown state\n");
478 rq
->f_status
= NS_NOTFOUND
;
481 } else if (strcasecmp(map
,"group.byname") == 0) {
484 rq
->f_cmd_data
= (void *)WINBINDD_SETGRENT
;
487 request
->data
.num_entries
= MAX_GETGRENT_USERS
;
488 rq
->f_cmd_data
= (void *)WINBINDD_GETGRENT
;
491 rq
->f_cmd_data
= (void *)WINBINDD_ENDGRENT
;
494 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown state\n");
496 rq
->f_status
= NS_NOTFOUND
;
501 * Don't understand this map - just return not found
503 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown table\n");
505 rq
->f_status
= NS_NOTFOUND
;
509 return(do_request(rq
, request
));
514 /* Allocate some space from the nss static buffer. The buffer and buflen
515 are the pointers passed in by the C library to the _nss_ntdom_*
518 static char *get_static(char **buffer
, int *buflen
, int len
)
522 /* Error check. We return false if things aren't set up right, or
523 there isn't enough buffer space left. */
525 if ((buffer
== NULL
) || (buflen
== NULL
) || (*buflen
< len
)) {
529 /* Return an index into the static buffer */
538 /* I've copied the strtok() replacement function next_token() from
539 lib/util_str.c as I really don't want to have to link in any other
540 objects if I can possibly avoid it. */
542 BOOL
next_token(char **ptr
,char *buff
,char *sep
, size_t bufsize
)
548 if (!ptr
) return(False
);
552 /* default to simple separators */
553 if (!sep
) sep
= " \t\n\r";
555 /* find the first non sep char */
556 while (*s
&& strchr(sep
,*s
)) s
++;
559 if (! *s
) return(False
);
561 /* copy over the token */
562 for (quoted
= False
; len
< bufsize
&& *s
&& (quoted
|| !strchr(sep
,*s
)); s
++) {
571 *ptr
= (*s
) ? s
+1 : s
;
578 /* Fill a pwent structure from a winbindd_response structure. We use
579 the static data passed to us by libc to put strings and stuff in.
580 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
582 static NSS_STATUS
fill_pwent(struct passwd
*result
,
583 struct winbindd_pw
*pw
,
584 char **buffer
, size_t *buflen
)
588 if ((result
->pw_name
=
589 get_static(buffer
, buflen
, strlen(pw
->pw_name
) + 1)) == NULL
) {
593 return NSS_STATUS_TRYAGAIN
;
596 strcpy(result
->pw_name
, pw
->pw_name
);
600 if ((result
->pw_passwd
=
601 get_static(buffer
, buflen
, strlen(pw
->pw_passwd
) + 1)) == NULL
) {
605 return NSS_STATUS_TRYAGAIN
;
608 strcpy(result
->pw_passwd
, pw
->pw_passwd
);
612 result
->pw_uid
= pw
->pw_uid
;
613 result
->pw_gid
= pw
->pw_gid
;
617 if ((result
->pw_gecos
=
618 get_static(buffer
, buflen
, strlen(pw
->pw_gecos
) + 1)) == NULL
) {
622 return NSS_STATUS_TRYAGAIN
;
625 strcpy(result
->pw_gecos
, pw
->pw_gecos
);
629 if ((result
->pw_dir
=
630 get_static(buffer
, buflen
, strlen(pw
->pw_dir
) + 1)) == NULL
) {
634 return NSS_STATUS_TRYAGAIN
;
637 strcpy(result
->pw_dir
, pw
->pw_dir
);
641 if ((result
->pw_shell
=
642 get_static(buffer
, buflen
, strlen(pw
->pw_shell
) + 1)) == NULL
) {
646 return NSS_STATUS_TRYAGAIN
;
649 strcpy(result
->pw_shell
, pw
->pw_shell
);
651 /* The struct passwd for Solaris has some extra fields which must
652 be initialised or nscd crashes. */
654 #if HAVE_PASSWD_PW_COMMENT
655 result
->pw_comment
= "";
658 #if HAVE_PASSWD_PW_AGE
662 return NSS_STATUS_SUCCESS
;
665 /* Fill a grent structure from a winbindd_response structure. We use
666 the static data passed to us by libc to put strings and stuff in.
667 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
669 static NSS_STATUS
fill_grent(struct group
*result
, struct winbindd_gr
*gr
,
670 char *gr_mem
, char **buffer
, size_t *buflen
)
678 if ((result
->gr_name
=
679 get_static(buffer
, buflen
, strlen(gr
->gr_name
) + 1)) == NULL
) {
683 return NSS_STATUS_TRYAGAIN
;
686 strcpy(result
->gr_name
, gr
->gr_name
);
690 if ((result
->gr_passwd
=
691 get_static(buffer
, buflen
, strlen(gr
->gr_passwd
) + 1)) == NULL
) {
695 return NSS_STATUS_TRYAGAIN
;
698 strcpy(result
->gr_passwd
, gr
->gr_passwd
);
702 result
->gr_gid
= gr
->gr_gid
;
704 /* Group membership */
706 if ((gr
->num_gr_mem
< 0) || !gr_mem
) {
710 /* this next value is a pointer to a pointer so let's align it */
712 /* Calculate number of extra bytes needed to align on pointer size boundry */
713 if ((i
= (unsigned long)(*buffer
) % sizeof(char*)) != 0)
714 i
= sizeof(char*) - i
;
716 if ((tst
= get_static(buffer
, buflen
, ((gr
->num_gr_mem
+ 1) *
717 sizeof(char *)+i
))) == NULL
) {
721 return NSS_STATUS_TRYAGAIN
;
723 result
->gr_mem
= (char **)(tst
+ i
);
725 if (gr
->num_gr_mem
== 0) {
729 *(result
->gr_mem
) = NULL
;
730 return NSS_STATUS_SUCCESS
;
733 /* Start looking at extra data */
737 while(next_token((char **)&gr_mem
, name
, ",", sizeof(fstring
))) {
739 /* Allocate space for member */
741 if (((result
->gr_mem
)[i
] =
742 get_static(buffer
, buflen
, strlen(name
) + 1)) == NULL
) {
746 return NSS_STATUS_TRYAGAIN
;
749 strcpy((result
->gr_mem
)[i
], name
);
755 (result
->gr_mem
)[i
] = NULL
;
757 return NSS_STATUS_SUCCESS
;
764 static struct winbindd_response getpwent_response
;
766 static int ndx_pw_cache
; /* Current index into pwd cache */
767 static int num_pw_cache
; /* Current size of pwd cache */
769 /* Rewind "file pointer" to start of ntdom password database */
772 _nss_winbind_setpwent(void)
775 fprintf(stderr
, "[%5d]: setpwent\n", getpid());
778 if (num_pw_cache
> 0) {
779 ndx_pw_cache
= num_pw_cache
= 0;
780 free_response(&getpwent_response
);
783 return winbindd_request(WINBINDD_SETPWENT
, NULL
, NULL
);
786 /* Close ntdom password database "file pointer" */
789 _nss_winbind_endpwent(void)
792 fprintf(stderr
, "[%5d]: endpwent\n", getpid());
795 if (num_pw_cache
> 0) {
796 ndx_pw_cache
= num_pw_cache
= 0;
797 free_response(&getpwent_response
);
800 return winbindd_request(WINBINDD_ENDPWENT
, NULL
, NULL
);
803 /* Fetch the next password entry from ntdom password database */
806 _nss_winbind_getpwent_r(struct passwd
*result
, char *buffer
,
807 size_t buflen
, int *errnop
)
810 struct winbindd_request request
;
811 static int called_again
;
814 fprintf(stderr
, "[%5d]: getpwent\n", getpid());
817 /* Return an entry from the cache if we have one, or if we are
818 called again because we exceeded our static buffer. */
820 if ((ndx_pw_cache
< num_pw_cache
) || called_again
) {
824 /* Else call winbindd to get a bunch of entries */
826 if (num_pw_cache
> 0) {
827 free_response(&getpwent_response
);
830 ZERO_STRUCT(request
);
831 ZERO_STRUCT(getpwent_response
);
833 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
835 ret
= winbindd_request(WINBINDD_GETPWENT
, &request
,
838 if (ret
== NSS_STATUS_SUCCESS
) {
839 struct winbindd_pw
*pw_cache
;
844 num_pw_cache
= getpwent_response
.data
.num_entries
;
846 /* Return a result */
850 pw_cache
= getpwent_response
.extra_data
;
852 /* Check data is valid */
854 if (pw_cache
== NULL
) {
855 return NSS_STATUS_NOTFOUND
;
858 ret
= fill_pwent(result
, &pw_cache
[ndx_pw_cache
],
861 /* Out of memory - try again */
863 if (ret
== NSS_STATUS_TRYAGAIN
) {
865 *errnop
= errno
= ERANGE
;
870 called_again
= False
;
873 /* If we've finished with this lot of results free cache */
875 if (ndx_pw_cache
== num_pw_cache
) {
876 ndx_pw_cache
= num_pw_cache
= 0;
877 free_response(&getpwent_response
);
884 /* Return passwd struct from uid */
887 _nss_winbind_getpwuid_r(uid_t uid
, struct passwd
*result
, char *buffer
,
888 size_t buflen
, int *errnop
)
891 static struct winbindd_response response
;
892 struct winbindd_request request
;
893 static int keep_response
=0;
895 /* If our static buffer needs to be expanded we are called again */
896 if (!keep_response
) {
898 /* Call for the first time */
900 ZERO_STRUCT(response
);
901 ZERO_STRUCT(request
);
903 request
.data
.uid
= uid
;
905 ret
= winbindd_request(WINBINDD_GETPWUID
, &request
, &response
);
907 if (ret
== NSS_STATUS_SUCCESS
) {
908 ret
= fill_pwent(result
, &response
.data
.pw
,
911 if (ret
== NSS_STATUS_TRYAGAIN
) {
912 keep_response
= True
;
913 *errnop
= errno
= ERANGE
;
920 /* We've been called again */
922 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
, &buflen
);
924 if (ret
== NSS_STATUS_TRYAGAIN
) {
925 keep_response
= True
;
926 *errnop
= errno
= ERANGE
;
930 keep_response
= False
;
934 free_response(&response
);
938 /* Return passwd struct from username */
941 _nss_winbind_getpwnam_r(const char *name
, struct passwd
*result
, char *buffer
,
942 size_t buflen
, int *errnop
)
945 static struct winbindd_response response
;
946 struct winbindd_request request
;
947 static int keep_response
;
950 fprintf(stderr
, "[%5d]: getpwnam %s\n", getpid(), name
);
953 /* If our static buffer needs to be expanded we are called again */
955 if (!keep_response
) {
957 /* Call for the first time */
959 ZERO_STRUCT(response
);
960 ZERO_STRUCT(request
);
962 strncpy(request
.data
.username
, name
,
963 sizeof(request
.data
.username
) - 1);
964 request
.data
.username
965 [sizeof(request
.data
.username
) - 1] = '\0';
967 ret
= winbindd_request(WINBINDD_GETPWNAM
, &request
, &response
);
969 if (ret
== NSS_STATUS_SUCCESS
) {
970 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
,
973 if (ret
== NSS_STATUS_TRYAGAIN
) {
974 keep_response
= True
;
975 *errnop
= errno
= ERANGE
;
982 /* We've been called again */
984 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
, &buflen
);
986 if (ret
== NSS_STATUS_TRYAGAIN
) {
987 keep_response
= True
;
988 *errnop
= errno
= ERANGE
;
992 keep_response
= False
;
996 free_response(&response
);
1001 * NSS group functions
1004 static struct winbindd_response getgrent_response
;
1006 static int ndx_gr_cache
; /* Current index into grp cache */
1007 static int num_gr_cache
; /* Current size of grp cache */
1009 /* Rewind "file pointer" to start of ntdom group database */
1012 _nss_winbind_setgrent(void)
1015 fprintf(stderr
, "[%5d]: setgrent\n", getpid());
1018 if (num_gr_cache
> 0) {
1019 ndx_gr_cache
= num_gr_cache
= 0;
1020 free_response(&getgrent_response
);
1023 return winbindd_request(WINBINDD_SETGRENT
, NULL
, NULL
);
1026 /* Close "file pointer" for ntdom group database */
1029 _nss_winbind_endgrent(void)
1032 fprintf(stderr
, "[%5d]: endgrent\n", getpid());
1035 if (num_gr_cache
> 0) {
1036 ndx_gr_cache
= num_gr_cache
= 0;
1037 free_response(&getgrent_response
);
1040 return winbindd_request(WINBINDD_ENDGRENT
, NULL
, NULL
);
1043 /* Get next entry from ntdom group database */
1046 winbind_getgrent(enum winbindd_cmd cmd
,
1047 struct group
*result
,
1048 char *buffer
, size_t buflen
, int *errnop
)
1051 static struct winbindd_request request
;
1052 static int called_again
;
1056 fprintf(stderr
, "[%5d]: getgrent\n", getpid());
1059 /* Return an entry from the cache if we have one, or if we are
1060 called again because we exceeded our static buffer. */
1062 if ((ndx_gr_cache
< num_gr_cache
) || called_again
) {
1066 /* Else call winbindd to get a bunch of entries */
1068 if (num_gr_cache
> 0) {
1069 free_response(&getgrent_response
);
1072 ZERO_STRUCT(request
);
1073 ZERO_STRUCT(getgrent_response
);
1075 request
.data
.num_entries
= MAX_GETGRENT_USERS
;
1077 ret
= winbindd_request(cmd
, &request
,
1078 &getgrent_response
);
1080 if (ret
== NSS_STATUS_SUCCESS
) {
1081 struct winbindd_gr
*gr_cache
;
1087 num_gr_cache
= getgrent_response
.data
.num_entries
;
1089 /* Return a result */
1093 gr_cache
= getgrent_response
.extra_data
;
1095 /* Check data is valid */
1097 if (gr_cache
== NULL
) {
1098 return NSS_STATUS_NOTFOUND
;
1101 /* Fill group membership. The offset into the extra data
1102 for the group membership is the reported offset plus the
1103 size of all the winbindd_gr records returned. */
1105 mem_ofs
= gr_cache
[ndx_gr_cache
].gr_mem_ofs
+
1106 num_gr_cache
* sizeof(struct winbindd_gr
);
1108 ret
= fill_grent(result
, &gr_cache
[ndx_gr_cache
],
1109 ((char *)getgrent_response
.extra_data
)+mem_ofs
,
1112 /* Out of memory - try again */
1114 if (ret
== NSS_STATUS_TRYAGAIN
) {
1115 called_again
= True
;
1116 *errnop
= errno
= ERANGE
;
1121 called_again
= False
;
1124 /* If we've finished with this lot of results free cache */
1126 if (ndx_gr_cache
== num_gr_cache
) {
1127 ndx_gr_cache
= num_gr_cache
= 0;
1128 free_response(&getgrent_response
);
1137 _nss_winbind_getgrent_r(struct group
*result
,
1138 char *buffer
, size_t buflen
, int *errnop
)
1140 return winbind_getgrent(WINBINDD_GETGRENT
, result
, buffer
, buflen
, errnop
);
1144 _nss_winbind_getgrlst_r(struct group
*result
,
1145 char *buffer
, size_t buflen
, int *errnop
)
1147 return winbind_getgrent(WINBINDD_GETGRLST
, result
, buffer
, buflen
, errnop
);
1150 /* Return group struct from group name */
1153 _nss_winbind_getgrnam_r(const char *name
,
1154 struct group
*result
, char *buffer
,
1155 size_t buflen
, int *errnop
)
1158 static struct winbindd_response response
;
1159 struct winbindd_request request
;
1160 static int keep_response
;
1163 fprintf(stderr
, "[%5d]: getgrnam %s\n", getpid(), name
);
1166 /* If our static buffer needs to be expanded we are called again */
1168 if (!keep_response
) {
1170 /* Call for the first time */
1172 ZERO_STRUCT(request
);
1173 ZERO_STRUCT(response
);
1175 strncpy(request
.data
.groupname
, name
,
1176 sizeof(request
.data
.groupname
));
1177 request
.data
.groupname
1178 [sizeof(request
.data
.groupname
) - 1] = '\0';
1180 ret
= winbindd_request(WINBINDD_GETGRNAM
, &request
, &response
);
1182 if (ret
== NSS_STATUS_SUCCESS
) {
1183 ret
= fill_grent(result
, &response
.data
.gr
,
1184 response
.extra_data
,
1187 if (ret
== NSS_STATUS_TRYAGAIN
) {
1188 keep_response
= True
;
1189 *errnop
= errno
= ERANGE
;
1196 /* We've been called again */
1198 ret
= fill_grent(result
, &response
.data
.gr
,
1199 response
.extra_data
, &buffer
, &buflen
);
1201 if (ret
== NSS_STATUS_TRYAGAIN
) {
1202 keep_response
= True
;
1203 *errnop
= errno
= ERANGE
;
1207 keep_response
= False
;
1211 free_response(&response
);
1215 /* Return group struct from gid */
1218 _nss_winbind_getgrgid_r(gid_t gid
,
1219 struct group
*result
, char *buffer
,
1220 size_t buflen
, int *errnop
)
1223 static struct winbindd_response response
;
1224 struct winbindd_request request
;
1225 static int keep_response
;
1228 fprintf(stderr
, "[%5d]: getgrgid %d\n", getpid(), gid
);
1231 /* If our static buffer needs to be expanded we are called again */
1233 if (!keep_response
) {
1235 /* Call for the first time */
1237 ZERO_STRUCT(request
);
1238 ZERO_STRUCT(response
);
1240 request
.data
.gid
= gid
;
1242 ret
= winbindd_request(WINBINDD_GETGRGID
, &request
, &response
);
1244 if (ret
== NSS_STATUS_SUCCESS
) {
1246 ret
= fill_grent(result
, &response
.data
.gr
,
1247 response
.extra_data
,
1250 if (ret
== NSS_STATUS_TRYAGAIN
) {
1251 keep_response
= True
;
1252 *errnop
= errno
= ERANGE
;
1259 /* We've been called again */
1261 ret
= fill_grent(result
, &response
.data
.gr
,
1262 response
.extra_data
, &buffer
, &buflen
);
1264 if (ret
== NSS_STATUS_TRYAGAIN
) {
1265 keep_response
= True
;
1266 *errnop
= errno
= ERANGE
;
1270 keep_response
= False
;
1274 free_response(&response
);
1278 /* Initialise supplementary groups */
1281 _nss_winbind_initgroups_dyn(char *user
, gid_t group
, long int *start
,
1282 long int *size
, gid_t
**groups
, long int limit
,
1286 struct winbindd_request request
;
1287 struct winbindd_response response
;
1291 fprintf(stderr
, "[%5d]: initgroups %s (%d)\n", getpid(),
1295 ZERO_STRUCT(request
);
1296 ZERO_STRUCT(response
);
1298 strncpy(request
.data
.username
, user
,
1299 sizeof(request
.data
.username
) - 1);
1301 ret
= winbindd_request(WINBINDD_GETGROUPS
, &request
, &response
);
1303 if (ret
== NSS_STATUS_SUCCESS
) {
1304 int num_gids
= response
.data
.num_entries
;
1305 gid_t
*gid_list
= (gid_t
*)response
.extra_data
;
1307 /* Copy group list to client */
1309 for (i
= 0; i
< num_gids
; i
++) {
1311 /* Skip primary group */
1313 if (gid_list
[i
] == group
) continue;
1317 if (*start
== *size
&& limit
<= 0) {
1318 (*groups
) = realloc(
1319 (*groups
), (2 * (*size
) + 1) * sizeof(**groups
));
1320 if (! *groups
) goto done
;
1321 *size
= 2 * (*size
) + 1;
1324 if (*start
== *size
) goto done
;
1326 (*groups
)[*start
] = gid_list
[i
];
1329 /* Filled buffer? */
1331 if (*start
== limit
) goto done
;
1335 /* Back to your regularly scheduled programming */