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_nss_config.h"
25 #include "winbindd_nss.h"
30 #include <ns_daemon.h>
33 #define MAX_GETPWENT_USERS 250
34 #define MAX_GETGRENT_USERS 250
36 /* Prototypes from wb_common.c */
38 extern int winbindd_fd
;
40 void init_request(struct winbindd_request
*req
,int rq_type
);
41 NSS_STATUS
winbindd_send_request(int req_type
,
42 struct winbindd_request
*request
);
43 NSS_STATUS
winbindd_get_response(struct winbindd_response
*response
);
44 NSS_STATUS
winbindd_request(int req_type
,
45 struct winbindd_request
*request
,
46 struct winbindd_response
*response
);
47 int winbind_open_pipe_sock(void);
48 int write_sock(void *buffer
, int count
);
49 int read_reply(struct winbindd_response
*response
);
50 void free_response(struct winbindd_response
*response
);
55 static int send_next_request(nsd_file_t
*, struct winbindd_request
*);
56 static int do_list(int state
, nsd_file_t
*rq
);
58 static nsd_file_t
*current_rq
= NULL
;
59 static int current_winbind_xid
= 0;
60 static int next_winbind_xid
= 0;
62 typedef struct winbind_xid
{
65 struct winbindd_request
*request
;
66 struct winbind_xid
*next
;
69 static winbind_xid_t
*winbind_xids
= (winbind_xid_t
*)0;
72 winbind_xid_new(int xid
, nsd_file_t
*rq
, struct winbindd_request
*request
)
76 nsd_logprintf(NSD_LOG_LOW
,
77 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
79 new = (winbind_xid_t
*)nsd_calloc(1,sizeof(winbind_xid_t
));
81 nsd_logprintf(NSD_LOG_RESOURCE
,"winbind_xid_new: failed malloc\n");
87 new->request
= request
;
88 new->next
= winbind_xids
;
95 ** This routine will look down the xid list and return the request
96 ** associated with an xid. We remove the record if it is found.
99 winbind_xid_lookup(int xid
, struct winbindd_request
**requestp
)
101 winbind_xid_t
**last
, *dx
;
102 nsd_file_t
*result
=0;
104 for (last
= &winbind_xids
, dx
= winbind_xids
; dx
&& (dx
->xid
!= xid
);
105 last
= &dx
->next
, dx
= dx
->next
);
109 *requestp
= dx
->request
;
112 nsd_logprintf(NSD_LOG_LOW
,
113 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
114 xid
, result
, dx
->request
);
120 winbind_startnext_timeout(nsd_file_t
**rqp
, nsd_times_t
*to
)
123 struct winbindd_request
*request
;
125 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind startnext)\n");
128 nsd_timeout_remove(rq
);
129 request
= to
->t_clientdata
;
130 return(send_next_request(rq
, request
));
137 struct winbindd_request
*request
;
140 * Check for queued requests
143 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind) unqueue xid %d\n",
144 current_winbind_xid
);
145 rq
= winbind_xid_lookup(current_winbind_xid
++, &request
);
146 /* cause a timeout on the queued request so we can send it */
147 nsd_timeout_new(rq
,1,winbind_startnext_timeout
,request
);
152 do_request(nsd_file_t
*rq
, struct winbindd_request
*request
)
154 if (winbind_xids
== NULL
) {
156 * No outstanding requests.
157 * Send off the request to winbindd
159 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) sending request\n");
160 return(send_next_request(rq
, request
));
163 * Just queue it up for now - previous callout or timout
166 nsd_logprintf(NSD_LOG_MIN
,
167 "lookup (winbind): queue request xid = %d\n",
169 return(winbind_xid_new(next_winbind_xid
++, rq
, request
));
174 winbind_callback(nsd_file_t
**rqp
, int fd
)
176 struct winbindd_response response
;
177 struct winbindd_pw
*pw
= &response
.data
.pw
;
178 struct winbindd_gr
*gr
= &response
.data
.gr
;
187 nsd_logprintf(NSD_LOG_MIN
, "entering callback (winbind)\n");
192 nsd_timeout_remove(rq
);
193 nsd_callback_remove(fd
);
195 ZERO_STRUCT(response
);
196 status
= winbindd_get_response(&response
);
198 if (status
!= NSS_STATUS_SUCCESS
) {
199 /* free any extra data area in response structure */
200 free_response(&response
);
201 nsd_logprintf(NSD_LOG_MIN
,
202 "callback (winbind) returning not found, status = %d\n",
204 rq
->f_status
= NS_NOTFOUND
;
208 maxlen
= sizeof(result
) - 1;
210 switch ((int)rq
->f_cmd_data
) {
211 case WINBINDD_WINS_BYNAME
:
212 case WINBINDD_WINS_BYIP
:
213 snprintf(result
,maxlen
,"%s\n",response
.data
.winsresp
);
215 case WINBINDD_GETPWUID
:
216 case WINBINDD_GETPWNAM
:
217 snprintf(result
,maxlen
,"%s:%s:%d:%d:%s:%s:%s\n",
226 case WINBINDD_GETGRNAM
:
227 case WINBINDD_GETGRGID
:
228 if (gr
->num_gr_mem
&& response
.extra_data
)
229 members
= response
.extra_data
;
232 snprintf(result
,maxlen
,"%s:%s:%d:%s\n",
233 gr
->gr_name
, gr
->gr_passwd
, gr
->gr_gid
, members
);
235 case WINBINDD_SETGRENT
:
236 case WINBINDD_SETPWENT
:
237 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - SETPWENT/SETGRENT\n");
238 free_response(&response
);
239 return(do_list(1,rq
));
240 case WINBINDD_GETGRENT
:
241 nsd_logprintf(NSD_LOG_MIN
,
242 "callback (winbind) - %d GETGRENT responses\n",
243 response
.data
.num_entries
);
244 if (response
.data
.num_entries
) {
245 gr
= (struct winbindd_gr
*)response
.extra_data
;
247 nsd_logprintf(NSD_LOG_MIN
, " no extra_data\n");
248 free_response(&response
);
251 members
= (char *)response
.extra_data
+
252 (response
.data
.num_entries
* sizeof(struct winbindd_gr
));
253 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
254 snprintf(result
,maxlen
,"%s:%s:%d:%s\n",
255 gr
->gr_name
, gr
->gr_passwd
, gr
->gr_gid
,
256 &members
[gr
->gr_mem_ofs
]);
257 nsd_logprintf(NSD_LOG_MIN
, " GETGRENT %s\n",result
);
258 nsd_append_element(rq
,NS_SUCCESS
,result
,strlen(result
));
262 i
= response
.data
.num_entries
;
263 free_response(&response
);
264 if (i
< MAX_GETPWENT_USERS
)
265 return(do_list(2,rq
));
267 return(do_list(1,rq
));
268 case WINBINDD_GETPWENT
:
269 nsd_logprintf(NSD_LOG_MIN
,
270 "callback (winbind) - %d GETPWENT responses\n",
271 response
.data
.num_entries
);
272 if (response
.data
.num_entries
) {
273 pw
= (struct winbindd_pw
*)response
.extra_data
;
275 nsd_logprintf(NSD_LOG_MIN
, " no extra_data\n");
276 free_response(&response
);
279 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
280 snprintf(result
,maxlen
,"%s:%s:%d:%d:%s:%s:%s",
288 nsd_logprintf(NSD_LOG_MIN
, " GETPWENT %s\n",result
);
289 nsd_append_element(rq
,NS_SUCCESS
,result
,strlen(result
));
293 i
= response
.data
.num_entries
;
294 free_response(&response
);
295 if (i
< MAX_GETPWENT_USERS
)
296 return(do_list(2,rq
));
298 return(do_list(1,rq
));
299 case WINBINDD_ENDGRENT
:
300 case WINBINDD_ENDPWENT
:
301 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - ENDPWENT/ENDGRENT\n");
302 nsd_append_element(rq
,NS_SUCCESS
,"\n",1);
303 free_response(&response
);
306 free_response(&response
);
307 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) - no valid command\n");
310 nsd_logprintf(NSD_LOG_MIN
, "callback (winbind) %s\n", result
);
311 /* free any extra data area in response structure */
312 free_response(&response
);
313 nsd_set_result(rq
,NS_SUCCESS
,result
,strlen(result
),VOLATILE
);
318 winbind_timeout(nsd_file_t
**rqp
, nsd_times_t
*to
)
324 nsd_logprintf(NSD_LOG_MIN
, "timeout (winbind)\n");
329 /* Remove the callback and timeout */
330 nsd_callback_remove(winbindd_fd
);
331 nsd_timeout_remove(rq
);
333 rq
->f_status
= NS_NOTFOUND
;
338 send_next_request(nsd_file_t
*rq
, struct winbindd_request
*request
)
345 nsd_logprintf(NSD_LOG_MIN
, "send_next_request (winbind) %d to = %d\n",
346 rq
->f_cmd_data
, timeout
);
347 status
= winbindd_send_request((int)rq
->f_cmd_data
,request
);
350 if (status
!= NSS_STATUS_SUCCESS
) {
351 nsd_logprintf(NSD_LOG_MIN
,
352 "send_next_request (winbind) error status = %d\n",status
);
353 rq
->f_status
= status
;
360 * Set up callback and timeouts
362 nsd_logprintf(NSD_LOG_MIN
, "send_next_request (winbind) fd = %d\n",winbindd_fd
);
363 nsd_callback_new(winbindd_fd
,winbind_callback
,NSD_READ
);
364 nsd_timeout_new(rq
,timeout
,winbind_timeout
,(void *)0);
370 nsd_logprintf(NSD_LOG_MIN
, "entering init (winbind)\n");
374 int lookup(nsd_file_t
*rq
)
378 struct winbindd_request
*request
;
380 nsd_logprintf(NSD_LOG_MIN
, "entering lookup (winbind)\n");
384 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
385 key
= nsd_attr_fetch_string(rq
->f_attrs
, "key", (char*)0);
386 if (! map
|| ! key
) {
387 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) table or key not defined\n");
388 rq
->f_status
= NS_BADREQ
;
392 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind %s)\n",map
);
394 request
= (struct winbindd_request
*)nsd_calloc(1,sizeof(struct winbindd_request
));
396 nsd_logprintf(NSD_LOG_RESOURCE
,
397 "lookup (winbind): failed malloc\n");
401 if (strcasecmp(map
,"passwd.byuid") == 0) {
402 request
->data
.uid
= atoi(key
);
403 rq
->f_cmd_data
= (void *)WINBINDD_GETPWUID
;
404 } else if (strcasecmp(map
,"passwd.byname") == 0) {
405 strncpy(request
->data
.username
, key
,
406 sizeof(request
->data
.username
) - 1);
407 request
->data
.username
[sizeof(request
->data
.username
) - 1] = '\0';
408 rq
->f_cmd_data
= (void *)WINBINDD_GETPWNAM
;
409 } else if (strcasecmp(map
,"group.byname") == 0) {
410 strncpy(request
->data
.groupname
, key
,
411 sizeof(request
->data
.groupname
) - 1);
412 request
->data
.groupname
[sizeof(request
->data
.groupname
) - 1] = '\0';
413 rq
->f_cmd_data
= (void *)WINBINDD_GETGRNAM
;
414 } else if (strcasecmp(map
,"group.bygid") == 0) {
415 request
->data
.gid
= atoi(key
);
416 rq
->f_cmd_data
= (void *)WINBINDD_GETGRGID
;
417 } else if (strcasecmp(map
,"hosts.byname") == 0) {
418 strncpy(request
->data
.winsreq
, key
, sizeof(request
->data
.winsreq
) - 1);
419 request
->data
.winsreq
[sizeof(request
->data
.winsreq
) - 1] = '\0';
420 rq
->f_cmd_data
= (void *)WINBINDD_WINS_BYNAME
;
421 } else if (strcasecmp(map
,"hosts.byaddr") == 0) {
422 strncpy(request
->data
.winsreq
, key
, sizeof(request
->data
.winsreq
) - 1);
423 request
->data
.winsreq
[sizeof(request
->data
.winsreq
) - 1] = '\0';
424 rq
->f_cmd_data
= (void *)WINBINDD_WINS_BYIP
;
427 * Don't understand this map - just return not found
429 nsd_logprintf(NSD_LOG_MIN
, "lookup (winbind) unknown table\n");
431 rq
->f_status
= NS_NOTFOUND
;
435 return(do_request(rq
, request
));
438 int list(nsd_file_t
*rq
)
442 nsd_logprintf(NSD_LOG_MIN
, "entering list (winbind)\n");
446 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
448 nsd_logprintf(NSD_LOG_MIN
, "list (winbind) table not defined\n");
449 rq
->f_status
= NS_BADREQ
;
453 nsd_logprintf(NSD_LOG_MIN
, "list (winbind %s)\n",map
);
455 return (do_list(0,rq
));
459 do_list(int state
, nsd_file_t
*rq
)
462 struct winbindd_request
*request
;
464 nsd_logprintf(NSD_LOG_MIN
, "entering do_list (winbind) state = %d\n",state
);
466 map
= nsd_attr_fetch_string(rq
->f_attrs
, "table", (char*)0);
467 request
= (struct winbindd_request
*)nsd_calloc(1,sizeof(struct winbindd_request
));
469 nsd_logprintf(NSD_LOG_RESOURCE
,
470 "do_list (winbind): failed malloc\n");
474 if (strcasecmp(map
,"passwd.byname") == 0) {
477 rq
->f_cmd_data
= (void *)WINBINDD_SETPWENT
;
480 request
->data
.num_entries
= MAX_GETPWENT_USERS
;
481 rq
->f_cmd_data
= (void *)WINBINDD_GETPWENT
;
484 rq
->f_cmd_data
= (void *)WINBINDD_ENDPWENT
;
487 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown state\n");
489 rq
->f_status
= NS_NOTFOUND
;
492 } else if (strcasecmp(map
,"group.byname") == 0) {
495 rq
->f_cmd_data
= (void *)WINBINDD_SETGRENT
;
498 request
->data
.num_entries
= MAX_GETGRENT_USERS
;
499 rq
->f_cmd_data
= (void *)WINBINDD_GETGRENT
;
502 rq
->f_cmd_data
= (void *)WINBINDD_ENDGRENT
;
505 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown state\n");
507 rq
->f_status
= NS_NOTFOUND
;
512 * Don't understand this map - just return not found
514 nsd_logprintf(NSD_LOG_MIN
, "do_list (winbind) unknown table\n");
516 rq
->f_status
= NS_NOTFOUND
;
520 return(do_request(rq
, request
));
525 /* Allocate some space from the nss static buffer. The buffer and buflen
526 are the pointers passed in by the C library to the _nss_ntdom_*
529 static char *get_static(char **buffer
, int *buflen
, int len
)
533 /* Error check. We return false if things aren't set up right, or
534 there isn't enough buffer space left. */
536 if ((buffer
== NULL
) || (buflen
== NULL
) || (*buflen
< len
)) {
540 /* Return an index into the static buffer */
549 /* I've copied the strtok() replacement function next_token() from
550 lib/util_str.c as I really don't want to have to link in any other
551 objects if I can possibly avoid it. */
553 BOOL
next_token(char **ptr
,char *buff
,char *sep
, size_t bufsize
)
559 if (!ptr
) return(False
);
563 /* default to simple separators */
564 if (!sep
) sep
= " \t\n\r";
566 /* find the first non sep char */
567 while (*s
&& strchr(sep
,*s
)) s
++;
570 if (! *s
) return(False
);
572 /* copy over the token */
573 for (quoted
= False
; len
< bufsize
&& *s
&& (quoted
|| !strchr(sep
,*s
)); s
++) {
582 *ptr
= (*s
) ? s
+1 : s
;
589 /* Fill a pwent structure from a winbindd_response structure. We use
590 the static data passed to us by libc to put strings and stuff in.
591 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
593 static NSS_STATUS
fill_pwent(struct passwd
*result
,
594 struct winbindd_pw
*pw
,
595 char **buffer
, size_t *buflen
)
599 if ((result
->pw_name
=
600 get_static(buffer
, buflen
, strlen(pw
->pw_name
) + 1)) == NULL
) {
604 return NSS_STATUS_TRYAGAIN
;
607 strcpy(result
->pw_name
, pw
->pw_name
);
611 if ((result
->pw_passwd
=
612 get_static(buffer
, buflen
, strlen(pw
->pw_passwd
) + 1)) == NULL
) {
616 return NSS_STATUS_TRYAGAIN
;
619 strcpy(result
->pw_passwd
, pw
->pw_passwd
);
623 result
->pw_uid
= pw
->pw_uid
;
624 result
->pw_gid
= pw
->pw_gid
;
628 if ((result
->pw_gecos
=
629 get_static(buffer
, buflen
, strlen(pw
->pw_gecos
) + 1)) == NULL
) {
633 return NSS_STATUS_TRYAGAIN
;
636 strcpy(result
->pw_gecos
, pw
->pw_gecos
);
640 if ((result
->pw_dir
=
641 get_static(buffer
, buflen
, strlen(pw
->pw_dir
) + 1)) == NULL
) {
645 return NSS_STATUS_TRYAGAIN
;
648 strcpy(result
->pw_dir
, pw
->pw_dir
);
652 if ((result
->pw_shell
=
653 get_static(buffer
, buflen
, strlen(pw
->pw_shell
) + 1)) == NULL
) {
657 return NSS_STATUS_TRYAGAIN
;
660 strcpy(result
->pw_shell
, pw
->pw_shell
);
662 /* The struct passwd for Solaris has some extra fields which must
663 be initialised or nscd crashes. */
665 #if HAVE_PASSWD_PW_COMMENT
666 result
->pw_comment
= "";
669 #if HAVE_PASSWD_PW_AGE
673 return NSS_STATUS_SUCCESS
;
676 /* Fill a grent structure from a winbindd_response structure. We use
677 the static data passed to us by libc to put strings and stuff in.
678 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
680 static int fill_grent(struct group
*result
, struct winbindd_gr
*gr
,
681 char *gr_mem
, char **buffer
, size_t *buflen
)
689 if ((result
->gr_name
=
690 get_static(buffer
, buflen
, strlen(gr
->gr_name
) + 1)) == NULL
) {
694 return NSS_STATUS_TRYAGAIN
;
697 strcpy(result
->gr_name
, gr
->gr_name
);
701 if ((result
->gr_passwd
=
702 get_static(buffer
, buflen
, strlen(gr
->gr_passwd
) + 1)) == NULL
) {
706 return NSS_STATUS_TRYAGAIN
;
709 strcpy(result
->gr_passwd
, gr
->gr_passwd
);
713 result
->gr_gid
= gr
->gr_gid
;
715 /* Group membership */
717 if ((gr
->num_gr_mem
< 0) || !gr_mem
) {
721 /* this next value is a pointer to a pointer so let's align it */
723 /* Calculate number of extra bytes needed to align on pointer size boundry */
724 if ((i
= (unsigned long)(*buffer
) % sizeof(char*)) != 0)
725 i
= sizeof(char*) - i
;
727 if ((tst
= get_static(buffer
, buflen
, ((gr
->num_gr_mem
+ 1) *
728 sizeof(char *)+i
))) == NULL
) {
732 return NSS_STATUS_TRYAGAIN
;
734 result
->gr_mem
= (char **)(tst
+ i
);
736 if (gr
->num_gr_mem
== 0) {
740 *(result
->gr_mem
) = NULL
;
741 return NSS_STATUS_SUCCESS
;
744 /* Start looking at extra data */
748 while(next_token((char **)&gr_mem
, name
, ",", sizeof(fstring
))) {
750 /* Allocate space for member */
752 if (((result
->gr_mem
)[i
] =
753 get_static(buffer
, buflen
, strlen(name
) + 1)) == NULL
) {
757 return NSS_STATUS_TRYAGAIN
;
760 strcpy((result
->gr_mem
)[i
], name
);
766 (result
->gr_mem
)[i
] = NULL
;
768 return NSS_STATUS_SUCCESS
;
775 static struct winbindd_response getpwent_response
;
777 static int ndx_pw_cache
; /* Current index into pwd cache */
778 static int num_pw_cache
; /* Current size of pwd cache */
780 /* Rewind "file pointer" to start of ntdom password database */
783 _nss_winbind_setpwent(void)
786 fprintf(stderr
, "[%5d]: setpwent\n", getpid());
789 if (num_pw_cache
> 0) {
790 ndx_pw_cache
= num_pw_cache
= 0;
791 free_response(&getpwent_response
);
794 return winbindd_request(WINBINDD_SETPWENT
, NULL
, NULL
);
797 /* Close ntdom password database "file pointer" */
800 _nss_winbind_endpwent(void)
803 fprintf(stderr
, "[%5d]: endpwent\n", getpid());
806 if (num_pw_cache
> 0) {
807 ndx_pw_cache
= num_pw_cache
= 0;
808 free_response(&getpwent_response
);
811 return winbindd_request(WINBINDD_ENDPWENT
, NULL
, NULL
);
814 /* Fetch the next password entry from ntdom password database */
817 _nss_winbind_getpwent_r(struct passwd
*result
, char *buffer
,
818 size_t buflen
, int *errnop
)
821 struct winbindd_request request
;
822 static int called_again
;
825 fprintf(stderr
, "[%5d]: getpwent\n", getpid());
828 /* Return an entry from the cache if we have one, or if we are
829 called again because we exceeded our static buffer. */
831 if ((ndx_pw_cache
< num_pw_cache
) || called_again
) {
835 /* Else call winbindd to get a bunch of entries */
837 if (num_pw_cache
> 0) {
838 free_response(&getpwent_response
);
841 ZERO_STRUCT(request
);
842 ZERO_STRUCT(getpwent_response
);
844 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
846 ret
= winbindd_request(WINBINDD_GETPWENT
, &request
,
849 if (ret
== NSS_STATUS_SUCCESS
) {
850 struct winbindd_pw
*pw_cache
;
855 num_pw_cache
= getpwent_response
.data
.num_entries
;
857 /* Return a result */
861 pw_cache
= getpwent_response
.extra_data
;
863 /* Check data is valid */
865 if (pw_cache
== NULL
) {
866 return NSS_STATUS_NOTFOUND
;
869 ret
= fill_pwent(result
, &pw_cache
[ndx_pw_cache
],
870 &buffer
, (int *)&buflen
);
872 /* Out of memory - try again */
874 if (ret
== NSS_STATUS_TRYAGAIN
) {
876 *errnop
= errno
= ERANGE
;
881 called_again
= False
;
884 /* If we've finished with this lot of results free cache */
886 if (ndx_pw_cache
== num_pw_cache
) {
887 ndx_pw_cache
= num_pw_cache
= 0;
888 free_response(&getpwent_response
);
895 /* Return passwd struct from uid */
898 _nss_winbind_getpwuid_r(uid_t uid
, struct passwd
*result
, char *buffer
,
899 size_t buflen
, int *errnop
)
902 static struct winbindd_response response
;
903 struct winbindd_request request
;
904 static int keep_response
=0;
906 /* If our static buffer needs to be expanded we are called again */
907 if (!keep_response
) {
909 /* Call for the first time */
911 ZERO_STRUCT(response
);
912 ZERO_STRUCT(request
);
914 request
.data
.uid
= uid
;
916 ret
= winbindd_request(WINBINDD_GETPWUID
, &request
, &response
);
918 if (ret
== NSS_STATUS_SUCCESS
) {
919 ret
= fill_pwent(result
, &response
.data
.pw
,
920 &buffer
, (int *)&buflen
);
922 if (ret
== NSS_STATUS_TRYAGAIN
) {
923 keep_response
= True
;
924 *errnop
= errno
= ERANGE
;
931 /* We've been called again */
933 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
, (int *)&buflen
);
935 if (ret
== NSS_STATUS_TRYAGAIN
) {
936 keep_response
= True
;
937 *errnop
= errno
= ERANGE
;
941 keep_response
= False
;
945 free_response(&response
);
949 /* Return passwd struct from username */
952 _nss_winbind_getpwnam_r(const char *name
, struct passwd
*result
, char *buffer
,
953 size_t buflen
, int *errnop
)
956 static struct winbindd_response response
;
957 struct winbindd_request request
;
958 static int keep_response
;
961 fprintf(stderr
, "[%5d]: getpwnam %s\n", getpid(), name
);
964 /* If our static buffer needs to be expanded we are called again */
966 if (!keep_response
) {
968 /* Call for the first time */
970 ZERO_STRUCT(response
);
971 ZERO_STRUCT(request
);
973 strncpy(request
.data
.username
, name
,
974 sizeof(request
.data
.username
) - 1);
975 request
.data
.username
976 [sizeof(request
.data
.username
) - 1] = '\0';
978 ret
= winbindd_request(WINBINDD_GETPWNAM
, &request
, &response
);
980 if (ret
== NSS_STATUS_SUCCESS
) {
981 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
,
984 if (ret
== NSS_STATUS_TRYAGAIN
) {
985 keep_response
= True
;
986 *errnop
= errno
= ERANGE
;
993 /* We've been called again */
995 ret
= fill_pwent(result
, &response
.data
.pw
, &buffer
, (int *)&buflen
);
997 if (ret
== NSS_STATUS_TRYAGAIN
) {
998 keep_response
= True
;
999 *errnop
= errno
= ERANGE
;
1003 keep_response
= False
;
1004 *errnop
= errno
= 0;
1007 free_response(&response
);
1012 * NSS group functions
1015 static struct winbindd_response getgrent_response
;
1017 static int ndx_gr_cache
; /* Current index into grp cache */
1018 static int num_gr_cache
; /* Current size of grp cache */
1020 /* Rewind "file pointer" to start of ntdom group database */
1023 _nss_winbind_setgrent(void)
1026 fprintf(stderr
, "[%5d]: setgrent\n", getpid());
1029 if (num_gr_cache
> 0) {
1030 ndx_gr_cache
= num_gr_cache
= 0;
1031 free_response(&getgrent_response
);
1034 return winbindd_request(WINBINDD_SETGRENT
, NULL
, NULL
);
1037 /* Close "file pointer" for ntdom group database */
1040 _nss_winbind_endgrent(void)
1043 fprintf(stderr
, "[%5d]: endgrent\n", getpid());
1046 if (num_gr_cache
> 0) {
1047 ndx_gr_cache
= num_gr_cache
= 0;
1048 free_response(&getgrent_response
);
1051 return winbindd_request(WINBINDD_ENDGRENT
, NULL
, NULL
);
1054 /* Get next entry from ntdom group database */
1057 _nss_winbind_getgrent_r(struct group
*result
,
1058 char *buffer
, size_t buflen
, int *errnop
)
1061 static struct winbindd_request request
;
1062 static int called_again
;
1065 fprintf(stderr
, "[%5d]: getgrent\n", getpid());
1068 /* Return an entry from the cache if we have one, or if we are
1069 called again because we exceeded our static buffer. */
1071 if ((ndx_gr_cache
< num_gr_cache
) || called_again
) {
1075 /* Else call winbindd to get a bunch of entries */
1077 if (num_gr_cache
> 0) {
1078 free_response(&getgrent_response
);
1081 ZERO_STRUCT(request
);
1082 ZERO_STRUCT(getgrent_response
);
1084 request
.data
.num_entries
= MAX_GETGRENT_USERS
;
1086 ret
= winbindd_request(WINBINDD_GETGRENT
, &request
,
1087 &getgrent_response
);
1089 if (ret
== NSS_STATUS_SUCCESS
) {
1090 struct winbindd_gr
*gr_cache
;
1096 num_gr_cache
= getgrent_response
.data
.num_entries
;
1098 /* Return a result */
1102 gr_cache
= getgrent_response
.extra_data
;
1104 /* Check data is valid */
1106 if (gr_cache
== NULL
) {
1107 return NSS_STATUS_NOTFOUND
;
1110 /* Fill group membership. The offset into the extra data
1111 for the group membership is the reported offset plus the
1112 size of all the winbindd_gr records returned. */
1114 mem_ofs
= gr_cache
[ndx_gr_cache
].gr_mem_ofs
+
1115 num_gr_cache
* sizeof(struct winbindd_gr
);
1117 ret
= fill_grent(result
, &gr_cache
[ndx_gr_cache
],
1118 ((char *)getgrent_response
.extra_data
)+mem_ofs
,
1119 &buffer
, (int *)&buflen
);
1121 /* Out of memory - try again */
1123 if (ret
== NSS_STATUS_TRYAGAIN
) {
1124 called_again
= True
;
1125 *errnop
= errno
= ERANGE
;
1130 called_again
= False
;
1133 /* If we've finished with this lot of results free cache */
1135 if (ndx_gr_cache
== num_gr_cache
) {
1136 ndx_gr_cache
= num_gr_cache
= 0;
1137 free_response(&getgrent_response
);
1144 /* Return group struct from group name */
1147 _nss_winbind_getgrnam_r(const char *name
,
1148 struct group
*result
, char *buffer
,
1149 size_t buflen
, int *errnop
)
1152 static struct winbindd_response response
;
1153 struct winbindd_request request
;
1154 static int keep_response
;
1157 fprintf(stderr
, "[%5d]: getgrnam %s\n", getpid(), name
);
1160 /* If our static buffer needs to be expanded we are called again */
1162 if (!keep_response
) {
1164 /* Call for the first time */
1166 ZERO_STRUCT(request
);
1167 ZERO_STRUCT(response
);
1169 strncpy(request
.data
.groupname
, name
,
1170 sizeof(request
.data
.groupname
));
1171 request
.data
.groupname
1172 [sizeof(request
.data
.groupname
) - 1] = '\0';
1174 ret
= winbindd_request(WINBINDD_GETGRNAM
, &request
, &response
);
1176 if (ret
== NSS_STATUS_SUCCESS
) {
1177 ret
= fill_grent(result
, &response
.data
.gr
,
1178 response
.extra_data
,
1179 &buffer
, (int *)&buflen
);
1181 if (ret
== NSS_STATUS_TRYAGAIN
) {
1182 keep_response
= True
;
1183 *errnop
= errno
= ERANGE
;
1190 /* We've been called again */
1192 ret
= fill_grent(result
, &response
.data
.gr
,
1193 response
.extra_data
, &buffer
, (int *)&buflen
);
1195 if (ret
== NSS_STATUS_TRYAGAIN
) {
1196 keep_response
= True
;
1197 *errnop
= errno
= ERANGE
;
1201 keep_response
= False
;
1205 free_response(&response
);
1209 /* Return group struct from gid */
1212 _nss_winbind_getgrgid_r(gid_t gid
,
1213 struct group
*result
, char *buffer
,
1214 size_t buflen
, int *errnop
)
1217 static struct winbindd_response response
;
1218 struct winbindd_request request
;
1219 static int keep_response
;
1222 fprintf(stderr
, "[%5d]: getgrgid %d\n", getpid(), gid
);
1225 /* If our static buffer needs to be expanded we are called again */
1227 if (!keep_response
) {
1229 /* Call for the first time */
1231 ZERO_STRUCT(request
);
1232 ZERO_STRUCT(response
);
1234 request
.data
.gid
= gid
;
1236 ret
= winbindd_request(WINBINDD_GETGRGID
, &request
, &response
);
1238 if (ret
== NSS_STATUS_SUCCESS
) {
1240 ret
= fill_grent(result
, &response
.data
.gr
,
1241 response
.extra_data
,
1242 &buffer
, (int *)&buflen
);
1244 if (ret
== NSS_STATUS_TRYAGAIN
) {
1245 keep_response
= True
;
1246 *errnop
= errno
= ERANGE
;
1253 /* We've been called again */
1255 ret
= fill_grent(result
, &response
.data
.gr
,
1256 response
.extra_data
, &buffer
, (int *)&buflen
);
1258 if (ret
== NSS_STATUS_TRYAGAIN
) {
1259 keep_response
= True
;
1260 *errnop
= errno
= ERANGE
;
1264 keep_response
= False
;
1268 free_response(&response
);
1272 /* Initialise supplementary groups */
1275 _nss_winbind_initgroups_dyn(char *user
, gid_t group
, long int *start
,
1276 long int *size
, gid_t
**groups
, long int limit
,
1280 struct winbindd_request request
;
1281 struct winbindd_response response
;
1285 fprintf(stderr
, "[%5d]: initgroups %s (%d)\n", getpid(),
1289 ZERO_STRUCT(request
);
1290 ZERO_STRUCT(response
);
1292 strncpy(request
.data
.username
, user
,
1293 sizeof(request
.data
.username
) - 1);
1295 ret
= winbindd_request(WINBINDD_GETGROUPS
, &request
, &response
);
1297 if (ret
== NSS_STATUS_SUCCESS
) {
1298 int num_gids
= response
.data
.num_entries
;
1299 gid_t
*gid_list
= (gid_t
*)response
.extra_data
;
1301 /* Copy group list to client */
1303 for (i
= 0; i
< num_gids
; i
++) {
1305 /* Skip primary group */
1307 if (gid_list
[i
] == group
) continue;
1311 if (*start
== *size
&& limit
<= 0) {
1312 (*groups
) = realloc(
1313 (*groups
), (2 * (*size
) + 1) * sizeof(**groups
));
1314 if (! *groups
) goto done
;
1315 *size
= 2 * (*size
) + 1;
1318 if (*start
== *size
) goto done
;
1320 (*groups
)[*start
] = gid_list
[i
];
1323 /* Filled buffer? */
1325 if (*start
== limit
) goto done
;
1329 /* Back to your regularly scheduled programming */