if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / nsswitch / winbind_nss.c
blob250e2df59beb91c9f774e5a5ed2385a934ab5915
1 /*
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"
27 #ifdef HAVE_NS_API_H
28 #undef VOLATILE
30 #include <ns_daemon.h>
31 #endif
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);
52 #ifdef HAVE_NS_API_H
53 /* IRIX version */
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 {
63 int xid;
64 nsd_file_t *rq;
65 struct winbindd_request *request;
66 struct winbind_xid *next;
67 } winbind_xid_t;
69 static winbind_xid_t *winbind_xids = (winbind_xid_t *)0;
71 static int
72 winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request)
74 winbind_xid_t *new;
76 nsd_logprintf(NSD_LOG_LOW,
77 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
78 xid, rq, request);
79 new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t));
80 if (!new) {
81 nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n");
82 return NSD_ERROR;
85 new->xid = xid;
86 new->rq = rq;
87 new->request = request;
88 new->next = winbind_xids;
89 winbind_xids = new;
91 return NSD_CONTINUE;
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.
98 nsd_file_t *
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);
106 if (dx) {
107 *last = dx->next;
108 result = dx->rq;
109 *requestp = dx->request;
110 SAFE_FREE(dx);
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);
116 return result;
119 static int
120 winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to)
122 nsd_file_t *rq;
123 struct winbindd_request *request;
125 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n");
126 rq = to->t_file;
127 *rqp = rq;
128 nsd_timeout_remove(rq);
129 request = to->t_clientdata;
130 return(send_next_request(rq, request));
133 static void
134 dequeue_request()
136 nsd_file_t *rq;
137 struct winbindd_request *request;
140 * Check for queued requests
142 if (winbind_xids) {
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);
151 static int
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));
161 } else {
163 * Just queue it up for now - previous callout or timout
164 * will start it up
166 nsd_logprintf(NSD_LOG_MIN,
167 "lookup (winbind): queue request xid = %d\n",
168 next_winbind_xid);
169 return(winbind_xid_new(next_winbind_xid++, rq, request));
173 static int
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;
179 nsd_file_t *rq;
180 NSS_STATUS status;
181 fstring result;
182 char *members;
183 int i, maxlen;
185 dequeue_request();
187 nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n");
189 rq = current_rq;
190 *rqp = rq;
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",
203 status);
204 rq->f_status = NS_NOTFOUND;
205 return NSD_NEXT;
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);
214 break;
215 case WINBINDD_GETPWUID:
216 case WINBINDD_GETPWNAM:
217 snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s\n",
218 pw->pw_name,
219 pw->pw_passwd,
220 pw->pw_uid,
221 pw->pw_gid,
222 pw->pw_gecos,
223 pw->pw_dir,
224 pw->pw_shell);
225 break;
226 case WINBINDD_GETGRNAM:
227 case WINBINDD_GETGRGID:
228 if (gr->num_gr_mem && response.extra_data)
229 members = response.extra_data;
230 else
231 members = "";
232 snprintf(result,maxlen,"%s:%s:%d:%s\n",
233 gr->gr_name, gr->gr_passwd, gr->gr_gid, members);
234 break;
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;
246 if (! gr ) {
247 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
248 free_response(&response);
249 return NSD_ERROR;
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));
259 gr++;
262 i = response.data.num_entries;
263 free_response(&response);
264 if (i < MAX_GETPWENT_USERS)
265 return(do_list(2,rq));
266 else
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;
274 if (! pw ) {
275 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
276 free_response(&response);
277 return NSD_ERROR;
279 for (i = 0; i < response.data.num_entries; i++) {
280 snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s",
281 pw->pw_name,
282 pw->pw_passwd,
283 pw->pw_uid,
284 pw->pw_gid,
285 pw->pw_gecos,
286 pw->pw_dir,
287 pw->pw_shell);
288 nsd_logprintf(NSD_LOG_MIN, " GETPWENT %s\n",result);
289 nsd_append_element(rq,NS_SUCCESS,result,strlen(result));
290 pw++;
293 i = response.data.num_entries;
294 free_response(&response);
295 if (i < MAX_GETPWENT_USERS)
296 return(do_list(2,rq));
297 else
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);
304 return NSD_NEXT;
305 default:
306 free_response(&response);
307 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - no valid command\n");
308 return NSD_NEXT;
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);
314 return NSD_OK;
317 static int
318 winbind_timeout(nsd_file_t **rqp, nsd_times_t *to)
320 nsd_file_t *rq;
322 dequeue_request();
324 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n");
326 rq = to->t_file;
327 *rqp = rq;
329 /* Remove the callback and timeout */
330 nsd_callback_remove(winbindd_fd);
331 nsd_timeout_remove(rq);
333 rq->f_status = NS_NOTFOUND;
334 return NSD_NEXT;
337 static int
338 send_next_request(nsd_file_t *rq, struct winbindd_request *request)
340 NSS_STATUS status;
341 long timeout;
343 timeout = 1000;
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);
348 SAFE_FREE(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;
354 return NSD_NEXT;
357 current_rq = rq;
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);
365 return NSD_CONTINUE;
368 int init(void)
370 nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n");
371 return(NSD_OK);
374 int lookup(nsd_file_t *rq)
376 char *map;
377 char *key;
378 struct winbindd_request *request;
380 nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n");
381 if (! rq)
382 return NSD_ERROR;
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;
389 return NSD_ERROR;
392 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map);
394 request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
395 if (! request) {
396 nsd_logprintf(NSD_LOG_RESOURCE,
397 "lookup (winbind): failed malloc\n");
398 return NSD_ERROR;
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;
425 } else {
427 * Don't understand this map - just return not found
429 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n");
430 SAFE_FREE(request);
431 rq->f_status = NS_NOTFOUND;
432 return NSD_NEXT;
435 return(do_request(rq, request));
438 int list(nsd_file_t *rq)
440 char *map;
442 nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n");
443 if (! rq)
444 return NSD_ERROR;
446 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
447 if (! map ) {
448 nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n");
449 rq->f_status = NS_BADREQ;
450 return NSD_ERROR;
453 nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map);
455 return (do_list(0,rq));
458 static int
459 do_list(int state, nsd_file_t *rq)
461 char *map;
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));
468 if (! request) {
469 nsd_logprintf(NSD_LOG_RESOURCE,
470 "do_list (winbind): failed malloc\n");
471 return NSD_ERROR;
474 if (strcasecmp(map,"passwd.byname") == 0) {
475 switch (state) {
476 case 0:
477 rq->f_cmd_data = (void *)WINBINDD_SETPWENT;
478 break;
479 case 1:
480 request->data.num_entries = MAX_GETPWENT_USERS;
481 rq->f_cmd_data = (void *)WINBINDD_GETPWENT;
482 break;
483 case 2:
484 rq->f_cmd_data = (void *)WINBINDD_ENDPWENT;
485 break;
486 default:
487 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
488 SAFE_FREE(request);
489 rq->f_status = NS_NOTFOUND;
490 return NSD_NEXT;
492 } else if (strcasecmp(map,"group.byname") == 0) {
493 switch (state) {
494 case 0:
495 rq->f_cmd_data = (void *)WINBINDD_SETGRENT;
496 break;
497 case 1:
498 request->data.num_entries = MAX_GETGRENT_USERS;
499 rq->f_cmd_data = (void *)WINBINDD_GETGRENT;
500 break;
501 case 2:
502 rq->f_cmd_data = (void *)WINBINDD_ENDGRENT;
503 break;
504 default:
505 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
506 SAFE_FREE(request);
507 rq->f_status = NS_NOTFOUND;
508 return NSD_NEXT;
510 } else {
512 * Don't understand this map - just return not found
514 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n");
515 SAFE_FREE(request);
516 rq->f_status = NS_NOTFOUND;
517 return NSD_NEXT;
520 return(do_request(rq, request));
523 #else
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_*
527 functions. */
529 static char *get_static(char **buffer, int *buflen, int len)
531 char *result;
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)) {
537 return NULL;
540 /* Return an index into the static buffer */
542 result = *buffer;
543 *buffer += len;
544 *buflen -= len;
546 return result;
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)
555 char *s;
556 BOOL quoted;
557 size_t len=1;
559 if (!ptr) return(False);
561 s = *ptr;
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++;
569 /* nothing left? */
570 if (! *s) return(False);
572 /* copy over the token */
573 for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
574 if (*s == '\"') {
575 quoted = !quoted;
576 } else {
577 len++;
578 *buff++ = *s;
582 *ptr = (*s) ? s+1 : s;
583 *buff = 0;
585 return(True);
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)
597 /* User name */
599 if ((result->pw_name =
600 get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
602 /* Out of memory */
604 return NSS_STATUS_TRYAGAIN;
607 strcpy(result->pw_name, pw->pw_name);
609 /* Password */
611 if ((result->pw_passwd =
612 get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
614 /* Out of memory */
616 return NSS_STATUS_TRYAGAIN;
619 strcpy(result->pw_passwd, pw->pw_passwd);
621 /* [ug]id */
623 result->pw_uid = pw->pw_uid;
624 result->pw_gid = pw->pw_gid;
626 /* GECOS */
628 if ((result->pw_gecos =
629 get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
631 /* Out of memory */
633 return NSS_STATUS_TRYAGAIN;
636 strcpy(result->pw_gecos, pw->pw_gecos);
638 /* Home directory */
640 if ((result->pw_dir =
641 get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
643 /* Out of memory */
645 return NSS_STATUS_TRYAGAIN;
648 strcpy(result->pw_dir, pw->pw_dir);
650 /* Logon shell */
652 if ((result->pw_shell =
653 get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
655 /* Out of memory */
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 = "";
667 #endif
669 #if HAVE_PASSWD_PW_AGE
670 result->pw_age = "";
671 #endif
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)
683 fstring name;
684 int i;
685 char *tst;
687 /* Group name */
689 if ((result->gr_name =
690 get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
692 /* Out of memory */
694 return NSS_STATUS_TRYAGAIN;
697 strcpy(result->gr_name, gr->gr_name);
699 /* Password */
701 if ((result->gr_passwd =
702 get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
704 /* Out of memory */
706 return NSS_STATUS_TRYAGAIN;
709 strcpy(result->gr_passwd, gr->gr_passwd);
711 /* gid */
713 result->gr_gid = gr->gr_gid;
715 /* Group membership */
717 if ((gr->num_gr_mem < 0) || !gr_mem) {
718 gr->num_gr_mem = 0;
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) {
730 /* Out of memory */
732 return NSS_STATUS_TRYAGAIN;
734 result->gr_mem = (char **)(tst + i);
736 if (gr->num_gr_mem == 0) {
738 /* Group is empty */
740 *(result->gr_mem) = NULL;
741 return NSS_STATUS_SUCCESS;
744 /* Start looking at extra data */
746 i = 0;
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) {
755 /* Out of memory */
757 return NSS_STATUS_TRYAGAIN;
760 strcpy((result->gr_mem)[i], name);
761 i++;
764 /* Terminate list */
766 (result->gr_mem)[i] = NULL;
768 return NSS_STATUS_SUCCESS;
772 * NSS user functions
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 */
782 NSS_STATUS
783 _nss_winbind_setpwent(void)
785 #ifdef DEBUG_NSS
786 fprintf(stderr, "[%5d]: setpwent\n", getpid());
787 #endif
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" */
799 NSS_STATUS
800 _nss_winbind_endpwent(void)
802 #ifdef DEBUG_NSS
803 fprintf(stderr, "[%5d]: endpwent\n", getpid());
804 #endif
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 */
816 NSS_STATUS
817 _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
818 size_t buflen, int *errnop)
820 NSS_STATUS ret;
821 struct winbindd_request request;
822 static int called_again;
824 #ifdef DEBUG_NSS
825 fprintf(stderr, "[%5d]: getpwent\n", getpid());
826 #endif
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) {
832 goto return_result;
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,
847 &getpwent_response);
849 if (ret == NSS_STATUS_SUCCESS) {
850 struct winbindd_pw *pw_cache;
852 /* Fill cache */
854 ndx_pw_cache = 0;
855 num_pw_cache = getpwent_response.data.num_entries;
857 /* Return a result */
859 return_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) {
875 called_again = True;
876 *errnop = errno = ERANGE;
877 return ret;
880 *errnop = errno = 0;
881 called_again = False;
882 ndx_pw_cache++;
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);
892 return ret;
895 /* Return passwd struct from uid */
897 NSS_STATUS
898 _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
899 size_t buflen, int *errnop)
901 NSS_STATUS ret;
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;
925 return ret;
929 } else {
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;
938 return ret;
941 keep_response = False;
942 *errnop = errno = 0;
945 free_response(&response);
946 return ret;
949 /* Return passwd struct from username */
951 NSS_STATUS
952 _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
953 size_t buflen, int *errnop)
955 NSS_STATUS ret;
956 static struct winbindd_response response;
957 struct winbindd_request request;
958 static int keep_response;
960 #ifdef DEBUG_NSS
961 fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
962 #endif
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,
982 (int *)&buflen);
984 if (ret == NSS_STATUS_TRYAGAIN) {
985 keep_response = True;
986 *errnop = errno = ERANGE;
987 return ret;
991 } else {
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;
1000 return ret;
1003 keep_response = False;
1004 *errnop = errno = 0;
1007 free_response(&response);
1008 return ret;
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 */
1022 NSS_STATUS
1023 _nss_winbind_setgrent(void)
1025 #ifdef DEBUG_NSS
1026 fprintf(stderr, "[%5d]: setgrent\n", getpid());
1027 #endif
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 */
1039 NSS_STATUS
1040 _nss_winbind_endgrent(void)
1042 #ifdef DEBUG_NSS
1043 fprintf(stderr, "[%5d]: endgrent\n", getpid());
1044 #endif
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 */
1056 NSS_STATUS
1057 _nss_winbind_getgrent_r(struct group *result,
1058 char *buffer, size_t buflen, int *errnop)
1060 NSS_STATUS ret;
1061 static struct winbindd_request request;
1062 static int called_again;
1064 #ifdef DEBUG_NSS
1065 fprintf(stderr, "[%5d]: getgrent\n", getpid());
1066 #endif
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) {
1072 goto return_result;
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;
1091 int mem_ofs;
1093 /* Fill cache */
1095 ndx_gr_cache = 0;
1096 num_gr_cache = getgrent_response.data.num_entries;
1098 /* Return a result */
1100 return_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;
1126 return ret;
1129 *errnop = 0;
1130 called_again = False;
1131 ndx_gr_cache++;
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);
1141 return ret;
1144 /* Return group struct from group name */
1146 NSS_STATUS
1147 _nss_winbind_getgrnam_r(const char *name,
1148 struct group *result, char *buffer,
1149 size_t buflen, int *errnop)
1151 NSS_STATUS ret;
1152 static struct winbindd_response response;
1153 struct winbindd_request request;
1154 static int keep_response;
1156 #ifdef DEBUG_NSS
1157 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
1158 #endif
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;
1184 return ret;
1188 } else {
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;
1198 return ret;
1201 keep_response = False;
1202 *errnop = 0;
1205 free_response(&response);
1206 return ret;
1209 /* Return group struct from gid */
1211 NSS_STATUS
1212 _nss_winbind_getgrgid_r(gid_t gid,
1213 struct group *result, char *buffer,
1214 size_t buflen, int *errnop)
1216 NSS_STATUS ret;
1217 static struct winbindd_response response;
1218 struct winbindd_request request;
1219 static int keep_response;
1221 #ifdef DEBUG_NSS
1222 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
1223 #endif
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;
1247 return ret;
1251 } else {
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;
1261 return ret;
1264 keep_response = False;
1265 *errnop = 0;
1268 free_response(&response);
1269 return ret;
1272 /* Initialise supplementary groups */
1274 NSS_STATUS
1275 _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
1276 long int *size, gid_t **groups, long int limit,
1277 int *errnop)
1279 NSS_STATUS ret;
1280 struct winbindd_request request;
1281 struct winbindd_response response;
1282 int i;
1284 #ifdef DEBUG_NSS
1285 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
1286 user, group);
1287 #endif
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;
1309 /* Add to buffer */
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];
1321 *start += 1;
1323 /* Filled buffer? */
1325 if (*start == limit) goto done;
1329 /* Back to your regularly scheduled programming */
1331 done:
1332 return ret;
1335 #endif