r23800: LGPL is now called GNU Lesser General Public License
[nivanova/samba-autobuild/.git] / source3 / nsswitch / winbind_nss_irix.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Windows NT Domain nsswitch module
5
6    Copyright (C) Tim Potter 2000
7    Copyright (C) James Peach 2006
8    
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 3 of the License, or (at your option) any later version.
13    
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18    
19    You should have received a copy of the GNU Lesser General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "winbind_client.h"
24
25 #ifndef PRINTF_ATTRIBUTE
26 #define PRINTF_ATTRIBUTE(m, n)
27 #endif
28
29 #ifndef HAVE_ASPRINTF_DECL
30 /*PRINTFLIKE2 */
31 int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
32 #endif
33
34 #ifdef HAVE_NS_API_H
35 #undef VOLATILE
36 #undef STATIC
37 #undef DYNAMIC
38 #include <ns_daemon.h>
39 #endif
40
41 /* Maximum number of users to pass back over the unix domain socket
42    per call. This is not a static limit on the total number of users 
43    or groups returned in total. */
44
45 #define MAX_GETPWENT_USERS 250
46 #define MAX_GETGRENT_USERS 250
47
48 /* Prototypes from wb_common.c */
49
50 extern int winbindd_fd;
51
52 #ifdef HAVE_NS_API_H
53
54 /* IRIX version */
55
56 static int send_next_request(nsd_file_t *, struct winbindd_request *);
57 static int do_list(int state, nsd_file_t *rq);
58
59 static nsd_file_t *current_rq = NULL;
60 static int current_winbind_xid = 0;
61 static int next_winbind_xid = 0;
62
63 typedef struct winbind_xid {
64         int                     xid;
65         nsd_file_t              *rq;
66         struct winbindd_request *request;
67         struct winbind_xid      *next;
68 } winbind_xid_t;
69
70 static winbind_xid_t *winbind_xids = (winbind_xid_t *)0;
71
72 static int
73 winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request)
74 {
75         winbind_xid_t *new;
76
77         nsd_logprintf(NSD_LOG_LOW,
78                 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
79                 xid, rq, request);
80         new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t));
81         if (!new) {
82                 nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n");
83                 return NSD_ERROR;
84         }
85
86         new->xid = xid;
87         new->rq = rq;
88         new->request = request;
89         new->next = winbind_xids;
90         winbind_xids = new;
91
92         return NSD_CONTINUE;
93 }
94
95 /*
96 ** This routine will look down the xid list and return the request
97 ** associated with an xid.  We remove the record if it is found.
98 */
99 nsd_file_t *
100 winbind_xid_lookup(int xid, struct winbindd_request **requestp)
101 {
102         winbind_xid_t **last, *dx;
103         nsd_file_t *result=0;
104
105         for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid);
106             last = &dx->next, dx = dx->next);
107         if (dx) {
108                 *last = dx->next;
109                 result = dx->rq;
110                 *requestp = dx->request;
111                 SAFE_FREE(dx);
112         }
113         nsd_logprintf(NSD_LOG_LOW,
114                 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
115                 xid, result, dx->request);
116
117         return result;
118 }
119
120 static int
121 winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to)
122 {
123         nsd_file_t *rq;
124         struct winbindd_request *request;
125
126         nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n");
127         rq = to->t_file;
128         *rqp = rq;
129         nsd_timeout_remove(rq);
130         request = to->t_clientdata;
131         return(send_next_request(rq, request));
132 }
133
134 static void
135 dequeue_request(void)
136 {
137         nsd_file_t *rq;
138         struct winbindd_request *request;
139
140         /*
141          * Check for queued requests
142          */
143         if (winbind_xids) {
144             nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n",
145                         current_winbind_xid);
146             rq = winbind_xid_lookup(current_winbind_xid++, &request);
147             /* cause a timeout on the queued request so we can send it */
148             nsd_timeout_new(rq,1,winbind_startnext_timeout,request);
149         }
150 }
151
152 static int
153 do_request(nsd_file_t *rq, struct winbindd_request *request)
154 {
155         if (winbind_xids == NULL) {
156                 /*
157                  * No outstanding requests.
158                  * Send off the request to winbindd
159                  */
160                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n");
161                 return(send_next_request(rq, request));
162         } else {
163                 /*
164                  * Just queue it up for now - previous callout or timout
165                  * will start it up
166                  */
167                 nsd_logprintf(NSD_LOG_MIN,
168                         "lookup (winbind): queue request xid = %d\n",
169                         next_winbind_xid);
170                 return(winbind_xid_new(next_winbind_xid++, rq, request));
171         }
172 }
173
174 static int 
175 winbind_callback(nsd_file_t **rqp, int fd)
176 {
177         struct winbindd_response response;
178         nsd_file_t *rq;
179         NSS_STATUS status;
180         char * result = NULL;
181         size_t rlen;
182
183         dequeue_request();
184
185         nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n");
186
187         rq = current_rq;
188         *rqp = rq;
189
190         nsd_timeout_remove(rq);
191         nsd_callback_remove(fd);
192
193         ZERO_STRUCT(response);
194         status = winbindd_get_response(&response);
195
196         if (status != NSS_STATUS_SUCCESS) {
197                 /* free any extra data area in response structure */
198                 free_response(&response);
199                 nsd_logprintf(NSD_LOG_MIN, 
200                         "callback (winbind) returning not found, status = %d\n",
201                         status);
202
203                 switch (status) {
204                     case NSS_STATUS_UNAVAIL:
205                         rq->f_status = NS_UNAVAIL;
206                         break;
207                     case NSS_STATUS_TRYAGAIN:
208                         rq->f_status = NS_TRYAGAIN;
209                         break;
210                     case NSS_STATUS_NOTFOUND:
211                         /* FALLTHRU */
212                     default:
213                         rq->f_status = NS_NOTFOUND;
214                 }
215
216                 return NSD_NEXT;
217         }
218
219         switch ((int)rq->f_cmd_data) {
220             case WINBINDD_WINS_BYNAME:
221             case WINBINDD_WINS_BYIP:
222                 nsd_logprintf(NSD_LOG_MIN,
223                         "callback (winbind) WINS_BYNAME | WINS_BYIP\n");
224
225                 rlen = asprintf(&result, "%s\n", response.data.winsresp);
226                 if (rlen == 0 || result == NULL) {
227                         return NSD_ERROR;
228                 }
229                 
230                 free_response(&response);
231                 
232                 nsd_logprintf(NSD_LOG_MIN, "    %s\n", result);
233                 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
234                 return NSD_OK;
235
236             case WINBINDD_GETPWUID:
237             case WINBINDD_GETPWNAM:
238             {
239                 struct winbindd_pw *pw = &response.data.pw;
240             
241                 nsd_logprintf(NSD_LOG_MIN,
242                         "callback (winbind) GETPWUID | GETPWUID\n");
243
244                 rlen = asprintf(&result,"%s:%s:%d:%d:%s:%s:%s\n",
245                                 pw->pw_name,
246                                 pw->pw_passwd,
247                                 pw->pw_uid,
248                                 pw->pw_gid,
249                                 pw->pw_gecos,
250                                 pw->pw_dir,
251                                 pw->pw_shell);
252                 if (rlen == 0 || result == NULL)
253                     return NSD_ERROR;
254             
255                 free_response(&response);
256             
257                 nsd_logprintf(NSD_LOG_MIN, "    %s\n", result);
258                 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
259                 return NSD_OK;
260             }
261
262             case WINBINDD_GETGRNAM:
263             case WINBINDD_GETGRGID:
264             {
265                 const struct winbindd_gr *gr = &response.data.gr;
266                 const char * members;
267             
268                 nsd_logprintf(NSD_LOG_MIN,
269                         "callback (winbind) GETGRNAM | GETGRGID\n");
270
271                 if (gr->num_gr_mem && response.extra_data.data) {
272                         members = response.extra_data.data;
273                 } else {
274                         members = "";
275                 }
276             
277                 rlen = asprintf(&result, "%s:%s:%d:%s\n",
278                             gr->gr_name, gr->gr_passwd, gr->gr_gid, members);
279                 if (rlen == 0 || result == NULL)
280                     return NSD_ERROR;
281             
282                 free_response(&response);
283             
284                 nsd_logprintf(NSD_LOG_MIN, "    %s\n", result);
285                 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
286                 return NSD_OK;
287             }
288
289             case WINBINDD_SETGRENT:
290             case WINBINDD_SETPWENT:
291                 nsd_logprintf(NSD_LOG_MIN,
292                         "callback (winbind) SETGRENT | SETPWENT\n");
293                 free_response(&response);
294                 return(do_list(1,rq));
295
296             case WINBINDD_GETGRENT:
297             case WINBINDD_GETGRLST:
298             {
299                 int entries;
300             
301                 nsd_logprintf(NSD_LOG_MIN,
302                     "callback (winbind) GETGRENT | GETGRLIST %d responses\n",
303                     response.data.num_entries);
304             
305                 if (response.data.num_entries) {
306                     const struct winbindd_gr *gr = &response.data.gr;
307                     const char * members;
308                     fstring grp_name;
309                     int     i;
310             
311                     gr = (struct winbindd_gr *)response.extra_data.data;
312                     if (! gr ) {
313                         nsd_logprintf(NSD_LOG_MIN, "     no extra_data\n");
314                         free_response(&response);
315                         return NSD_ERROR;
316                     }
317             
318                     members = (char *)response.extra_data.data +
319                         (response.data.num_entries * sizeof(struct winbindd_gr));
320             
321                     for (i = 0; i < response.data.num_entries; i++) {
322                         snprintf(grp_name, sizeof(grp_name) - 1, "%s:%s:%d:",
323                                     gr->gr_name, gr->gr_passwd, gr->gr_gid);
324             
325                         nsd_append_element(rq, NS_SUCCESS, result, rlen);
326                         nsd_append_result(rq, NS_SUCCESS,
327                                 &members[gr->gr_mem_ofs],
328                                 strlen(&members[gr->gr_mem_ofs]));
329             
330                         /* Don't log the whole list, because it might be
331                          * _really_ long and we probably don't want to clobber
332                          * the log with it.
333                          */
334                         nsd_logprintf(NSD_LOG_MIN, "    %s (...)\n", grp_name);
335             
336                         gr++;
337                     }
338                 }
339             
340                 entries = response.data.num_entries;
341                 free_response(&response);
342                 if (entries < MAX_GETPWENT_USERS)
343                     return(do_list(2,rq));
344                 else
345                     return(do_list(1,rq));
346             }
347
348             case WINBINDD_GETPWENT:
349             {
350                 int entries;
351
352                 nsd_logprintf(NSD_LOG_MIN,
353                         "callback (winbind) GETPWENT  %d responses\n",
354                         response.data.num_entries);
355
356                 if (response.data.num_entries) {
357                     struct winbindd_pw *pw = &response.data.pw;
358                     int i;
359
360                     pw = (struct winbindd_pw *)response.extra_data.data;
361                     if (! pw ) {
362                         nsd_logprintf(NSD_LOG_MIN, "     no extra_data\n");
363                         free_response(&response);
364                         return NSD_ERROR;
365                     }
366                     for (i = 0; i < response.data.num_entries; i++) {
367                         result = NULL;
368                         rlen = asprintf(&result, "%s:%s:%d:%d:%s:%s:%s",
369                                         pw->pw_name,
370                                         pw->pw_passwd,
371                                         pw->pw_uid,
372                                         pw->pw_gid,
373                                         pw->pw_gecos,
374                                         pw->pw_dir,
375                                         pw->pw_shell);
376
377                         if (rlen != 0 && result != NULL) {
378                             nsd_logprintf(NSD_LOG_MIN, "    %s\n",result);
379                             nsd_append_element(rq, NS_SUCCESS, result, rlen);
380                             free(result);
381                         }
382
383                         pw++;
384                     }
385                 }
386
387                 entries = response.data.num_entries;
388                 free_response(&response);
389                 if (entries < MAX_GETPWENT_USERS)
390                     return(do_list(2,rq));
391                 else
392                     return(do_list(1,rq));
393             }
394
395             case WINBINDD_ENDGRENT:
396             case WINBINDD_ENDPWENT:
397                 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) ENDGRENT | ENDPWENT\n");
398                 nsd_append_element(rq, NS_SUCCESS, "\n", 1);
399                 free_response(&response);
400                 return NSD_NEXT;
401
402             default:
403                 free_response(&response);
404                 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) invalid command %d\n", (int)rq->f_cmd_data);
405                 return NSD_NEXT;
406         }
407 }
408
409 static int 
410 winbind_timeout(nsd_file_t **rqp, nsd_times_t *to)
411 {
412         nsd_file_t *rq;
413
414         dequeue_request();
415
416         nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n");
417
418         rq = to->t_file;
419         *rqp = rq;
420
421         /* Remove the callback and timeout */
422         nsd_callback_remove(winbindd_fd);
423         nsd_timeout_remove(rq);
424
425         rq->f_status = NS_NOTFOUND;
426         return NSD_NEXT;
427 }
428
429 static int
430 send_next_request(nsd_file_t *rq, struct winbindd_request *request)
431 {
432         NSS_STATUS status;
433         long timeout;
434
435         switch (rq->f_index) {
436                 case LOOKUP:
437                         timeout = nsd_attr_fetch_long(rq->f_attrs,
438                                         "lookup_timeout", 10, 10);
439                         break;
440                 case LIST:
441                         timeout = nsd_attr_fetch_long(rq->f_attrs,
442                                         "list_timeout", 10, 10);
443                         break;
444                 default:
445                         nsd_logprintf(NSD_LOG_OPER,
446                                 "send_next_request (winbind) "
447                                 "invalid request type %d\n", rq->f_index);
448                         rq->f_status = NS_BADREQ;
449                         return NSD_NEXT;
450         }
451
452         nsd_logprintf(NSD_LOG_MIN,
453                 "send_next_request (winbind) %d, timeout = %d sec\n",
454                         rq->f_cmd_data, timeout);
455         status = winbindd_send_request((int)rq->f_cmd_data,0,request);
456         SAFE_FREE(request);
457
458         if (status != NSS_STATUS_SUCCESS) {
459                 nsd_logprintf(NSD_LOG_MIN, 
460                         "send_next_request (winbind) error status = %d\n",
461                         status);
462                 rq->f_status = status;
463                 return NSD_NEXT;
464         }
465
466         current_rq = rq;
467
468         /*
469          * Set up callback and timeouts
470          */
471         nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",
472                 winbindd_fd);
473
474         nsd_callback_new(winbindd_fd, winbind_callback, NSD_READ);
475         nsd_timeout_new(rq, timeout * 1000, winbind_timeout, NULL);
476         return NSD_CONTINUE;
477 }
478
479 int init(void)
480 {
481         nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n");
482         return(NSD_OK);
483 }
484
485 int lookup(nsd_file_t *rq)
486 {
487         char *map;
488         char *key;
489         struct winbindd_request *request;
490
491         nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n");
492         if (! rq)
493                 return NSD_ERROR;
494
495         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
496         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
497         if (! map || ! key) {
498                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n");
499                 rq->f_status = NS_BADREQ;
500                 return NSD_ERROR;
501         }
502
503         nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map);
504
505         request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
506         if (! request) {
507                 nsd_logprintf(NSD_LOG_RESOURCE,
508                         "lookup (winbind): failed malloc\n");
509                 return NSD_ERROR;
510         }
511
512         if (strcasecmp(map,"passwd.byuid") == 0) {
513             request->data.uid = atoi(key);
514             rq->f_cmd_data = (void *)WINBINDD_GETPWUID;
515         } else if (strcasecmp(map,"passwd.byname") == 0) {
516             strncpy(request->data.username, key, 
517                 sizeof(request->data.username) - 1);
518             request->data.username[sizeof(request->data.username) - 1] = '\0';
519             rq->f_cmd_data = (void *)WINBINDD_GETPWNAM; 
520         } else if (strcasecmp(map,"group.byname") == 0) {
521             strncpy(request->data.groupname, key, 
522                 sizeof(request->data.groupname) - 1);
523             request->data.groupname[sizeof(request->data.groupname) - 1] = '\0';
524             rq->f_cmd_data = (void *)WINBINDD_GETGRNAM; 
525         } else if (strcasecmp(map,"group.bygid") == 0) {
526             request->data.gid = atoi(key);
527             rq->f_cmd_data = (void *)WINBINDD_GETGRGID;
528         } else if (strcasecmp(map,"hosts.byname") == 0) {
529             strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
530             request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
531             rq->f_cmd_data = (void *)WINBINDD_WINS_BYNAME;
532         } else if (strcasecmp(map,"hosts.byaddr") == 0) {
533             strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
534             request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
535             rq->f_cmd_data = (void *)WINBINDD_WINS_BYIP;
536         } else {
537                 /*
538                  * Don't understand this map - just return not found
539                  */
540                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n");
541                 SAFE_FREE(request);
542                 rq->f_status = NS_NOTFOUND;
543                 return NSD_NEXT;
544         }
545
546         return(do_request(rq, request));
547 }
548
549 int list(nsd_file_t *rq)
550 {
551         char *map;
552
553         nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n");
554         if (! rq)
555                 return NSD_ERROR;
556
557         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
558         if (! map ) {
559                 nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n");
560                 rq->f_status = NS_BADREQ;
561                 return NSD_ERROR;
562         }
563
564         nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map);
565
566         return (do_list(0,rq));
567 }
568
569 static int
570 do_list(int state, nsd_file_t *rq)
571 {
572         char *map;
573         struct winbindd_request *request;
574
575         nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state);
576
577         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
578         request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
579         if (! request) {
580                 nsd_logprintf(NSD_LOG_RESOURCE,
581                         "do_list (winbind): failed malloc\n");
582                 return NSD_ERROR;
583         }
584
585         if (strcasecmp(map,"passwd.byname") == 0) {
586             switch (state) {
587                 case 0:
588                     rq->f_cmd_data = (void *)WINBINDD_SETPWENT;
589                     break;
590                 case 1:
591                     request->data.num_entries = MAX_GETPWENT_USERS;
592                     rq->f_cmd_data = (void *)WINBINDD_GETPWENT;
593                     break;
594                 case 2:
595                     rq->f_cmd_data = (void *)WINBINDD_ENDPWENT;
596                     break;
597                 default:
598                     nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
599                     SAFE_FREE(request);
600                     rq->f_status = NS_NOTFOUND;
601                     return NSD_NEXT;
602             }
603         } else if (strcasecmp(map,"group.byname") == 0) {
604             switch (state) {
605                 case 0:
606                     rq->f_cmd_data = (void *)WINBINDD_SETGRENT;
607                     break;
608                 case 1:
609                     request->data.num_entries = MAX_GETGRENT_USERS;
610                     rq->f_cmd_data = (void *)WINBINDD_GETGRENT;
611                     break;
612                 case 2:
613                     rq->f_cmd_data = (void *)WINBINDD_ENDGRENT;
614                     break;
615                 default:
616                     nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
617                     SAFE_FREE(request);
618                     rq->f_status = NS_NOTFOUND;
619                     return NSD_NEXT;
620             }
621         } else {
622                 /*
623                  * Don't understand this map - just return not found
624                  */
625                 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n");
626                 SAFE_FREE(request);
627                 rq->f_status = NS_NOTFOUND;
628                 return NSD_NEXT;
629         }
630
631         return(do_request(rq, request));
632 }
633
634 #endif /* HAVE_NS_API_H */