r15053: fix portabilities issues between 32-bit winbind clients and a 64-bit winbindd...
[tprouty/samba.git] / source / 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    
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.
12    
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.
17    
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.   
22 */
23
24 #include "winbind_client.h"
25
26 #ifdef HAVE_NS_API_H
27 #undef VOLATILE
28 #include <ns_daemon.h>
29 #endif
30
31 /* Maximum number of users to pass back over the unix domain socket
32    per call. This is not a static limit on the total number of users 
33    or groups returned in total. */
34
35 #define MAX_GETPWENT_USERS 250
36 #define MAX_GETGRENT_USERS 250
37
38 /* Prototypes from wb_common.c */
39
40 extern int winbindd_fd;
41
42 #ifdef HAVE_NS_API_H
43
44 /* IRIX version */
45
46 static int send_next_request(nsd_file_t *, struct winbindd_request *);
47 static int do_list(int state, nsd_file_t *rq);
48
49 static nsd_file_t *current_rq = NULL;
50 static int current_winbind_xid = 0;
51 static int next_winbind_xid = 0;
52
53 typedef struct winbind_xid {
54         int                     xid;
55         nsd_file_t              *rq;
56         struct winbindd_request *request;
57         struct winbind_xid      *next;
58 } winbind_xid_t;
59
60 static winbind_xid_t *winbind_xids = (winbind_xid_t *)0;
61
62 static int
63 winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request)
64 {
65         winbind_xid_t *new;
66
67         nsd_logprintf(NSD_LOG_LOW,
68                 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
69                 xid, rq, request);
70         new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t));
71         if (!new) {
72                 nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n");
73                 return NSD_ERROR;
74         }
75
76         new->xid = xid;
77         new->rq = rq;
78         new->request = request;
79         new->next = winbind_xids;
80         winbind_xids = new;
81
82         return NSD_CONTINUE;
83 }
84
85 /*
86 ** This routine will look down the xid list and return the request
87 ** associated with an xid.  We remove the record if it is found.
88 */
89 nsd_file_t *
90 winbind_xid_lookup(int xid, struct winbindd_request **requestp)
91 {
92         winbind_xid_t **last, *dx;
93         nsd_file_t *result=0;
94
95         for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid);
96             last = &dx->next, dx = dx->next);
97         if (dx) {
98                 *last = dx->next;
99                 result = dx->rq;
100                 *requestp = dx->request;
101                 SAFE_FREE(dx);
102         }
103         nsd_logprintf(NSD_LOG_LOW,
104                 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
105                 xid, result, dx->request);
106
107         return result;
108 }
109
110 static int
111 winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to)
112 {
113         nsd_file_t *rq;
114         struct winbindd_request *request;
115
116         nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n");
117         rq = to->t_file;
118         *rqp = rq;
119         nsd_timeout_remove(rq);
120         request = to->t_clientdata;
121         return(send_next_request(rq, request));
122 }
123
124 static void
125 dequeue_request(void)
126 {
127         nsd_file_t *rq;
128         struct winbindd_request *request;
129
130         /*
131          * Check for queued requests
132          */
133         if (winbind_xids) {
134             nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n",
135                         current_winbind_xid);
136             rq = winbind_xid_lookup(current_winbind_xid++, &request);
137             /* cause a timeout on the queued request so we can send it */
138             nsd_timeout_new(rq,1,winbind_startnext_timeout,request);
139         }
140 }
141
142 static int
143 do_request(nsd_file_t *rq, struct winbindd_request *request)
144 {
145         if (winbind_xids == NULL) {
146                 /*
147                  * No outstanding requests.
148                  * Send off the request to winbindd
149                  */
150                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n");
151                 return(send_next_request(rq, request));
152         } else {
153                 /*
154                  * Just queue it up for now - previous callout or timout
155                  * will start it up
156                  */
157                 nsd_logprintf(NSD_LOG_MIN,
158                         "lookup (winbind): queue request xid = %d\n",
159                         next_winbind_xid);
160                 return(winbind_xid_new(next_winbind_xid++, rq, request));
161         }
162 }
163
164 static int 
165 winbind_callback(nsd_file_t **rqp, int fd)
166 {
167         struct winbindd_response response;
168         struct winbindd_pw *pw = &response.data.pw;
169         struct winbindd_gr *gr = &response.data.gr;
170         nsd_file_t *rq;
171         NSS_STATUS status;
172         fstring result;
173         char *members;
174         int i, maxlen;
175
176         dequeue_request();
177
178         nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n");
179
180         rq = current_rq;
181         *rqp = rq;
182
183         nsd_timeout_remove(rq);
184         nsd_callback_remove(fd);
185
186         ZERO_STRUCT(response);
187         status = winbindd_get_response(&response);
188
189         if (status != NSS_STATUS_SUCCESS) {
190                 /* free any extra data area in response structure */
191                 free_response(&response);
192                 nsd_logprintf(NSD_LOG_MIN, 
193                         "callback (winbind) returning not found, status = %d\n",
194                         status);
195                 rq->f_status = NS_NOTFOUND;
196                 return NSD_NEXT;
197         }
198
199         maxlen = sizeof(result) - 1;
200
201         switch ((int)rq->f_cmd_data) {
202             case WINBINDD_WINS_BYNAME:
203             case WINBINDD_WINS_BYIP:
204                 snprintf(result,maxlen,"%s\n",response.data.winsresp);
205                 break;
206             case WINBINDD_GETPWUID:
207             case WINBINDD_GETPWNAM:
208                 snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s\n",
209                         pw->pw_name,
210                         pw->pw_passwd,
211                         pw->pw_uid,
212                         pw->pw_gid,
213                         pw->pw_gecos,
214                         pw->pw_dir,
215                         pw->pw_shell);
216                 break;
217             case WINBINDD_GETGRNAM:
218             case WINBINDD_GETGRGID:
219                 if (gr->num_gr_mem && response.extra_data.data)
220                         members = response.extra_data.data;
221                 else
222                         members = "";
223                 snprintf(result,maxlen,"%s:%s:%d:%s\n",
224                         gr->gr_name, gr->gr_passwd, gr->gr_gid, members);
225                 break;
226             case WINBINDD_SETGRENT:
227             case WINBINDD_SETPWENT:
228                 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - SETPWENT/SETGRENT\n");
229                 free_response(&response);
230                 return(do_list(1,rq));
231             case WINBINDD_GETGRENT:
232             case WINBINDD_GETGRLST:
233                 nsd_logprintf(NSD_LOG_MIN, 
234                         "callback (winbind) - %d GETGRENT responses\n",
235                         response.data.num_entries);
236                 if (response.data.num_entries) {
237                     gr = (struct winbindd_gr *)response.extra_data.data;
238                     if (! gr ) {
239                         nsd_logprintf(NSD_LOG_MIN, "     no extra_data.data\n");
240                         free_response(&response);
241                         return NSD_ERROR;
242                     }
243                     members = (char *)response.extra_data.data + 
244                                 (response.data.num_entries * sizeof(struct winbindd_gr));
245                     for (i = 0; i < response.data.num_entries; i++) {
246                         snprintf(result,maxlen,"%s:%s:%d:%s\n",
247                                 gr->gr_name, gr->gr_passwd, gr->gr_gid, 
248                                 &members[gr->gr_mem_ofs]);
249                         nsd_logprintf(NSD_LOG_MIN, "     GETGRENT %s\n",result);
250                         nsd_append_element(rq,NS_SUCCESS,result,strlen(result));
251                         gr++;
252                     }
253                 }
254                 i = response.data.num_entries;
255                 free_response(&response);
256                 if (i < MAX_GETPWENT_USERS)
257                     return(do_list(2,rq));
258                 else
259                     return(do_list(1,rq));
260             case WINBINDD_GETPWENT:
261                 nsd_logprintf(NSD_LOG_MIN, 
262                         "callback (winbind) - %d GETPWENT responses\n",
263                         response.data.num_entries);
264                 if (response.data.num_entries) {
265                     pw = (struct winbindd_pw *)response.extra_data.data;
266                     if (! pw ) {
267                         nsd_logprintf(NSD_LOG_MIN, "     no extra_data\n");
268                         free_response(&response);
269                         return NSD_ERROR;
270                     }
271                     for (i = 0; i < response.data.num_entries; i++) {
272                         snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s",
273                                 pw->pw_name,
274                                 pw->pw_passwd,
275                                 pw->pw_uid,
276                                 pw->pw_gid,
277                                 pw->pw_gecos,
278                                 pw->pw_dir,
279                                 pw->pw_shell);
280                         nsd_logprintf(NSD_LOG_MIN, "     GETPWENT %s\n",result);
281                         nsd_append_element(rq,NS_SUCCESS,result,strlen(result));
282                         pw++;
283                     }
284                 }
285                 i = response.data.num_entries;
286                 free_response(&response);
287                 if (i < MAX_GETPWENT_USERS)
288                     return(do_list(2,rq));
289                 else
290                     return(do_list(1,rq));
291             case WINBINDD_ENDGRENT:
292             case WINBINDD_ENDPWENT:
293                 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - ENDPWENT/ENDGRENT\n");
294                 nsd_append_element(rq,NS_SUCCESS,"\n",1);
295                 free_response(&response);
296                 return NSD_NEXT;
297             default:
298                 free_response(&response);
299                 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - no valid command\n");
300                 return NSD_NEXT;
301         }
302         nsd_logprintf(NSD_LOG_MIN, "callback (winbind) %s\n", result);
303         /* free any extra data area in response structure */
304         free_response(&response);
305         nsd_set_result(rq,NS_SUCCESS,result,strlen(result),VOLATILE);
306         return NSD_OK;
307 }
308
309 static int 
310 winbind_timeout(nsd_file_t **rqp, nsd_times_t *to)
311 {
312         nsd_file_t *rq;
313
314         dequeue_request();
315
316         nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n");
317
318         rq = to->t_file;
319         *rqp = rq;
320
321         /* Remove the callback and timeout */
322         nsd_callback_remove(winbindd_fd);
323         nsd_timeout_remove(rq);
324
325         rq->f_status = NS_NOTFOUND;
326         return NSD_NEXT;
327 }
328
329 static int
330 send_next_request(nsd_file_t *rq, struct winbindd_request *request)
331 {
332         NSS_STATUS status;
333         long timeout;
334
335         switch (rq->f_index) {
336                 case LOOKUP:
337                         timeout = nsd_attr_fetch_long(rq->f_attrs,
338                                         "lookup_timeout", 10, 10 * 1000);
339                         break;
340                 case LIST:
341                         timeout = nsd_attr_fetch_long(rq->f_attrs,
342                                         "list_timeout", 10, 10 * 1000);
343                         break;
344                 default:
345                         nsd_logprintf(NSD_LOG_OPER,
346                                 "send_next_request (winbind) "
347                                 "invalid request type %d\n", rq->f_index);
348                         rq->f_status = NS_BADREQ;
349                         return NSD_NEXT;
350         }
351
352         nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) %d to = %d\n",
353                         rq->f_cmd_data, timeout);
354         status = winbindd_send_request((int)rq->f_cmd_data,request);
355         SAFE_FREE(request);
356
357         if (status != NSS_STATUS_SUCCESS) {
358                 nsd_logprintf(NSD_LOG_MIN, 
359                         "send_next_request (winbind) error status = %d\n",status);
360                 rq->f_status = status;
361                 return NSD_NEXT;
362         }
363
364         current_rq = rq;
365
366         /*
367          * Set up callback and timeouts
368          */
369         nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",winbindd_fd);
370         nsd_callback_new(winbindd_fd,winbind_callback,NSD_READ);
371         nsd_timeout_new(rq,timeout,winbind_timeout,(void *)0);
372         return NSD_CONTINUE;
373 }
374
375 int init(void)
376 {
377         nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n");
378         return(NSD_OK);
379 }
380
381 int lookup(nsd_file_t *rq)
382 {
383         char *map;
384         char *key;
385         struct winbindd_request *request;
386
387         nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n");
388         if (! rq)
389                 return NSD_ERROR;
390
391         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
392         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
393         if (! map || ! key) {
394                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n");
395                 rq->f_status = NS_BADREQ;
396                 return NSD_ERROR;
397         }
398
399         nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map);
400
401         request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
402         if (! request) {
403                 nsd_logprintf(NSD_LOG_RESOURCE,
404                         "lookup (winbind): failed malloc\n");
405                 return NSD_ERROR;
406         }
407
408         if (strcasecmp(map,"passwd.byuid") == 0) {
409             request->data.uid = atoi(key);
410             rq->f_cmd_data = (void *)WINBINDD_GETPWUID;
411         } else if (strcasecmp(map,"passwd.byname") == 0) {
412             strncpy(request->data.username, key, 
413                 sizeof(request->data.username) - 1);
414             request->data.username[sizeof(request->data.username) - 1] = '\0';
415             rq->f_cmd_data = (void *)WINBINDD_GETPWNAM; 
416         } else if (strcasecmp(map,"group.byname") == 0) {
417             strncpy(request->data.groupname, key, 
418                 sizeof(request->data.groupname) - 1);
419             request->data.groupname[sizeof(request->data.groupname) - 1] = '\0';
420             rq->f_cmd_data = (void *)WINBINDD_GETGRNAM; 
421         } else if (strcasecmp(map,"group.bygid") == 0) {
422             request->data.gid = atoi(key);
423             rq->f_cmd_data = (void *)WINBINDD_GETGRGID;
424         } else if (strcasecmp(map,"hosts.byname") == 0) {
425             strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
426             request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
427             rq->f_cmd_data = (void *)WINBINDD_WINS_BYNAME;
428         } else if (strcasecmp(map,"hosts.byaddr") == 0) {
429             strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
430             request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
431             rq->f_cmd_data = (void *)WINBINDD_WINS_BYIP;
432         } else {
433                 /*
434                  * Don't understand this map - just return not found
435                  */
436                 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n");
437                 SAFE_FREE(request);
438                 rq->f_status = NS_NOTFOUND;
439                 return NSD_NEXT;
440         }
441
442         return(do_request(rq, request));
443 }
444
445 int list(nsd_file_t *rq)
446 {
447         char *map;
448
449         nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n");
450         if (! rq)
451                 return NSD_ERROR;
452
453         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
454         if (! map ) {
455                 nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n");
456                 rq->f_status = NS_BADREQ;
457                 return NSD_ERROR;
458         }
459
460         nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map);
461
462         return (do_list(0,rq));
463 }
464
465 static int
466 do_list(int state, nsd_file_t *rq)
467 {
468         char *map;
469         struct winbindd_request *request;
470
471         nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state);
472
473         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
474         request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
475         if (! request) {
476                 nsd_logprintf(NSD_LOG_RESOURCE,
477                         "do_list (winbind): failed malloc\n");
478                 return NSD_ERROR;
479         }
480
481         if (strcasecmp(map,"passwd.byname") == 0) {
482             switch (state) {
483                 case 0:
484                     rq->f_cmd_data = (void *)WINBINDD_SETPWENT;
485                     break;
486                 case 1:
487                     request->data.num_entries = MAX_GETPWENT_USERS;
488                     rq->f_cmd_data = (void *)WINBINDD_GETPWENT;
489                     break;
490                 case 2:
491                     rq->f_cmd_data = (void *)WINBINDD_ENDPWENT;
492                     break;
493                 default:
494                     nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
495                     SAFE_FREE(request);
496                     rq->f_status = NS_NOTFOUND;
497                     return NSD_NEXT;
498             }
499         } else if (strcasecmp(map,"group.byname") == 0) {
500             switch (state) {
501                 case 0:
502                     rq->f_cmd_data = (void *)WINBINDD_SETGRENT;
503                     break;
504                 case 1:
505                     request->data.num_entries = MAX_GETGRENT_USERS;
506                     rq->f_cmd_data = (void *)WINBINDD_GETGRENT;
507                     break;
508                 case 2:
509                     rq->f_cmd_data = (void *)WINBINDD_ENDGRENT;
510                     break;
511                 default:
512                     nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
513                     SAFE_FREE(request);
514                     rq->f_status = NS_NOTFOUND;
515                     return NSD_NEXT;
516             }
517         } else {
518                 /*
519                  * Don't understand this map - just return not found
520                  */
521                 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n");
522                 SAFE_FREE(request);
523                 rq->f_status = NS_NOTFOUND;
524                 return NSD_NEXT;
525         }
526
527         return(do_request(rq, request));
528 }
529
530 #endif /* HAVE_NS_API_H */