r23798: updated old Temple Place FSF addresses to new URL
[nivanova/samba-autobuild/.git] / source3 / nsswitch / winbind_nss_solaris.c
1 /*
2   Solaris NSS wrapper for winbind 
3   - Shirish Kalele 2000
4   
5   Based on Luke Howard's ldap_nss module for Solaris 
6   */
7
8 /*
9   Copyright (C) 1997-2003 Luke Howard.
10   This file is part of the nss_ldap library.
11
12   The nss_ldap library is free software; you can redistribute it and/or
13   modify it under the terms of the GNU Library General Public License as
14   published by the Free Software Foundation; either version 3 of the
15   License, or (at your option) any later version.
16
17   The nss_ldap library is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20   Library General Public License for more details.
21
22   You should have received a copy of the GNU Library General Public
23   License along with the nss_ldap library; see the file COPYING.LIB.  If not,
24   see <http://www.gnu.org/licenses/>.
25 */
26
27 #undef DEVELOPER
28
29 #include "winbind_client.h"
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <string.h>
34 #include <pwd.h>
35 #include "includes.h"
36 #include <syslog.h>
37 #if !defined(HPUX)
38 #include <sys/syslog.h>
39 #endif /*hpux*/
40
41 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX) 
42
43 #undef NSS_DEBUG
44
45 #ifdef NSS_DEBUG
46 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
47 #else
48 #define NSS_DEBUG(str) ;
49 #endif
50
51 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
52
53 #ifdef HPUX
54
55 /*
56  * HP-UX 11 has no definiton of the nss_groupsbymem structure.   This
57  * definition is taken from the nss_ldap project at:
58  *  http://www.padl.com/OSS/nss_ldap.html
59  */
60
61 struct nss_groupsbymem {
62        const char *username;
63        gid_t *gid_array;
64        int maxgids;
65        int force_slow_way;
66        int (*str2ent)(const char *instr, int instr_len, void *ent, 
67                       char *buffer, int buflen);
68        nss_status_t (*process_cstr)(const char *instr, int instr_len, 
69                                     struct nss_groupsbymem *);
70        int numgids;
71 };
72
73 #endif /* HPUX */
74
75 #define make_pwent_str(dest, src)                                       \
76 {                                                                       \
77   if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL)        \
78     {                                                                   \
79       *errnop = ERANGE;                                                 \
80       NSS_DEBUG("ERANGE error");                                        \
81       return NSS_STATUS_TRYAGAIN;                                       \
82     }                                                                   \
83   strcpy(dest, src);                                                    \
84 }
85
86 static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
87 {
88         NSS_DEBUG("_nss_winbind_setpwent_solwrap");
89         return _nss_winbind_setpwent();
90 }
91
92 static NSS_STATUS
93 _nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
94 {
95         NSS_DEBUG("_nss_winbind_endpwent_solwrap");
96         return _nss_winbind_endpwent();
97 }
98
99 static NSS_STATUS
100 _nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
101 {
102         NSS_STATUS ret;
103         char* buffer = NSS_ARGS(args)->buf.buffer;
104         int buflen = NSS_ARGS(args)->buf.buflen;
105         struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
106         int* errnop = &NSS_ARGS(args)->erange;
107         char logmsg[80];
108
109         ret = _nss_winbind_getpwent_r(result, buffer, 
110                                       buflen, errnop);
111
112         if(ret == NSS_STATUS_SUCCESS)
113                 {
114                         snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
115                                  result->pw_name);
116                         NSS_DEBUG(logmsg);
117                         NSS_ARGS(args)->returnval = (void*) result;
118                 } else {
119                         snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
120                         NSS_DEBUG(logmsg);
121                 }
122     
123         return ret;
124 }
125
126 static NSS_STATUS
127 _nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
128 {
129         NSS_STATUS ret;
130         struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
131
132         NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
133
134         ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
135                                                 result,
136                                                 NSS_ARGS(args)->buf.buffer,
137                                                 NSS_ARGS(args)->buf.buflen,
138                                                 &NSS_ARGS(args)->erange);
139         if(ret == NSS_STATUS_SUCCESS)
140                 NSS_ARGS(args)->returnval = (void*) result;
141   
142         return ret;
143 }
144
145 static NSS_STATUS
146 _nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
147 {
148         NSS_STATUS ret;
149         struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
150   
151         NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
152         ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
153                                        result,
154                                        NSS_ARGS(args)->buf.buffer,
155                                        NSS_ARGS(args)->buf.buflen,
156                                        &NSS_ARGS(args)->erange);
157         if(ret == NSS_STATUS_SUCCESS)
158                 NSS_ARGS(args)->returnval = (void*) result;
159   
160         return ret;
161 }
162
163 static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
164 {
165         SAFE_FREE(be);
166         NSS_DEBUG("_nss_winbind_passwd_destr");
167         return NSS_STATUS_SUCCESS;
168 }
169
170 static nss_backend_op_t passwd_ops[] =
171 {
172         _nss_winbind_passwd_destr,
173         _nss_winbind_endpwent_solwrap,          /* NSS_DBOP_ENDENT */
174         _nss_winbind_setpwent_solwrap,          /* NSS_DBOP_SETENT */
175         _nss_winbind_getpwent_solwrap,          /* NSS_DBOP_GETENT */
176         _nss_winbind_getpwnam_solwrap,          /* NSS_DBOP_PASSWD_BYNAME */
177         _nss_winbind_getpwuid_solwrap           /* NSS_DBOP_PASSWD_BYUID */
178 };
179
180 nss_backend_t*
181 _nss_winbind_passwd_constr (const char* db_name,
182                             const char* src_name,
183                             const char* cfg_args)
184 {
185         nss_backend_t *be;
186   
187         if(!(be = SMB_MALLOC_P(nss_backend_t)) )
188                 return NULL;
189
190         be->ops = passwd_ops;
191         be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
192
193         NSS_DEBUG("Initialized nss_winbind passwd backend");
194         return be;
195 }
196
197 /*****************************************************************
198  GROUP database backend
199  *****************************************************************/
200
201 static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
202 {
203         NSS_DEBUG("_nss_winbind_setgrent_solwrap");
204         return _nss_winbind_setgrent();
205 }
206
207 static NSS_STATUS
208 _nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
209 {
210         NSS_DEBUG("_nss_winbind_endgrent_solwrap");
211         return _nss_winbind_endgrent();
212 }
213
214 static NSS_STATUS
215 _nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
216 {
217         NSS_STATUS ret;
218         char* buffer = NSS_ARGS(args)->buf.buffer;
219         int buflen = NSS_ARGS(args)->buf.buflen;
220         struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
221         int* errnop = &NSS_ARGS(args)->erange;
222         char logmsg[80];
223
224         ret = _nss_winbind_getgrent_r(result, buffer, 
225                                       buflen, errnop);
226
227         if(ret == NSS_STATUS_SUCCESS)
228                 {
229                         snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
230                         NSS_DEBUG(logmsg);
231                         NSS_ARGS(args)->returnval = (void*) result;
232                 } else {
233                         snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
234                         NSS_DEBUG(logmsg);
235                 }
236
237         return ret;
238         
239 }
240
241 static NSS_STATUS
242 _nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
243 {
244         NSS_STATUS ret;
245         struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
246
247         NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
248         ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
249                                       result,
250                                       NSS_ARGS(args)->buf.buffer,
251                                       NSS_ARGS(args)->buf.buflen,
252                                       &NSS_ARGS(args)->erange);
253
254         if(ret == NSS_STATUS_SUCCESS)
255                 NSS_ARGS(args)->returnval = (void*) result;
256   
257         return ret;
258 }
259   
260 static NSS_STATUS
261 _nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
262 {
263         NSS_STATUS ret;
264         struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
265
266         NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
267         ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
268                                        result,
269                                        NSS_ARGS(args)->buf.buffer,
270                                        NSS_ARGS(args)->buf.buflen,
271                                        &NSS_ARGS(args)->erange);
272
273         if(ret == NSS_STATUS_SUCCESS)
274                 NSS_ARGS(args)->returnval = (void*) result;
275
276         return ret;
277 }
278
279 static NSS_STATUS
280 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
281 {
282         int errnop;
283         struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
284
285         NSS_DEBUG("_nss_winbind_getgroupsbymember");
286
287         _nss_winbind_initgroups_dyn(gmem->username,
288                 gmem->gid_array[0], /* Primary Group */
289                 &gmem->numgids,
290                 &gmem->maxgids,
291                 &gmem->gid_array,
292                 gmem->maxgids,
293                 &errnop);
294
295         /*
296          * If the maximum number of gids have been found, return
297          * SUCCESS so the switch engine will stop searching. Otherwise
298          * return NOTFOUND so nsswitch will continue to get groups
299          * from the remaining database backends specified in the
300          * nsswitch.conf file.
301          */
302         return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
303 }
304
305 static NSS_STATUS
306 _nss_winbind_group_destr (nss_backend_t* be, void* args)
307 {
308         SAFE_FREE(be);
309         NSS_DEBUG("_nss_winbind_group_destr");
310         return NSS_STATUS_SUCCESS;
311 }
312
313 static nss_backend_op_t group_ops[] = 
314 {
315         _nss_winbind_group_destr,
316         _nss_winbind_endgrent_solwrap,
317         _nss_winbind_setgrent_solwrap,
318         _nss_winbind_getgrent_solwrap,
319         _nss_winbind_getgrnam_solwrap,
320         _nss_winbind_getgrgid_solwrap,
321         _nss_winbind_getgroupsbymember_solwrap
322 }; 
323
324 nss_backend_t*
325 _nss_winbind_group_constr (const char* db_name,
326                            const char* src_name,
327                            const char* cfg_args)
328 {
329         nss_backend_t* be;
330
331         if(!(be = SMB_MALLOC_P(nss_backend_t)) )
332                 return NULL;
333
334         be->ops = group_ops;
335         be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
336   
337         NSS_DEBUG("Initialized nss_winbind group backend");
338         return be;
339 }
340
341 /*****************************************************************
342  hosts and ipnodes backend
343  *****************************************************************/
344 #if defined(SUNOS5)     /* not compatible with HP-UX */
345
346 /* this parser is shared between get*byname and get*byaddr, as key type
347    in request is stored in different locations, I had to provide the
348    address family as an argument, caller must free the winbind response. */
349
350 static NSS_STATUS
351 parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
352 {
353         struct hostent *he = (struct hostent *)argp->buf.result;
354         char *buffer = argp->buf.buffer;
355         int buflen =  argp->buf.buflen;
356         NSS_STATUS ret;
357
358         char *p, *data;
359         int addrcount = 0;
360         int len = 0;
361         struct in_addr *addrp;
362         struct in6_addr *addrp6;
363         int i;
364
365         /* response is tab separated list of ip addresses with hostname
366            and newline at the end. so at first we will strip newline
367            then construct list of addresses for hostent.
368         */
369         p = strchr(response->data.winsresp, '\n');
370         if(p) *p = '\0';
371         else {/* it must be broken */
372                 argp->h_errno = NO_DATA;
373                 return NSS_STATUS_UNAVAIL;
374         }
375
376         for(; p != response->data.winsresp; p--) {
377                 if(*p == '\t') addrcount++;
378         }
379
380         if(addrcount == 0) {/* it must be broken */
381                 argp->h_errno = NO_DATA;
382                 return NSS_STATUS_UNAVAIL;
383         }
384
385         /* allocate space for addresses and h_addr_list */
386         he->h_addrtype = af;
387         if( he->h_addrtype == AF_INET) {
388                 he->h_length =  sizeof(struct in_addr);
389                 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
390                                                 sizeof(struct in_addr));
391                 addrp -= addrcount;
392                 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
393                 he->h_addr_list -= addrcount+1;
394         } else {
395                 he->h_length = sizeof(struct in6_addr);
396                 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
397                                                 sizeof(struct in6_addr));
398                 addrp6 -= addrcount;
399                 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
400                 he->h_addr_list -= addrcount+1;
401         }
402
403         /* buffer too small?! */
404         if((char *)he->h_addr_list < buffer ) {
405                 argp->erange = 1;
406                 return NSS_STR_PARSE_ERANGE;
407         }
408         
409         data = response->data.winsresp;
410         for( i = 0; i < addrcount; i++) {
411                 p = strchr(data, '\t');
412                 if(p == NULL) break; /* just in case... */
413
414                 *p = '\0'; /* terminate the string */
415                 if(he->h_addrtype == AF_INET) {
416                   he->h_addr_list[i] = (char *)&addrp[i];
417                   if ((addrp[i].s_addr = inet_addr(data)) == -1) {
418                     argp->erange = 1;
419                     return NSS_STR_PARSE_ERANGE;
420                   }
421                 } else {
422                   he->h_addr_list[i] = (char *)&addrp6[i];
423                   if (strchr(data, ':') != 0) {
424                         if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
425                           argp->erange = 1;
426                           return NSS_STR_PARSE_ERANGE;
427                         }
428                   } else {
429                         struct in_addr in4;
430                         if ((in4.s_addr = inet_addr(data)) == -1) {
431                           argp->erange = 1;
432                           return NSS_STR_PARSE_ERANGE;
433                         }
434                         IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
435                   }
436                 }
437                 data = p+1;
438         }
439
440         he->h_addr_list[i] = (char *)NULL;
441
442         len = strlen(data);
443         if(len > he->h_addr_list - (char**)argp->buf.buffer) {
444                 argp->erange = 1;
445                 return NSS_STR_PARSE_ERANGE;
446         }
447
448         /* this is a bit overkill to use _nss_netdb_aliases here since
449            there seems to be no aliases but it will create all data for us */
450         he->h_aliases = _nss_netdb_aliases(data, len, buffer,
451                                 ((char*) he->h_addr_list) - buffer);
452         if(he->h_aliases == NULL) {
453             argp->erange = 1;
454             ret = NSS_STR_PARSE_ERANGE;
455         } else {
456             he->h_name = he->h_aliases[0];
457             he->h_aliases++;
458             ret = NSS_STR_PARSE_SUCCESS;
459         }
460
461         argp->returnval = (void*)he;
462         return ret;
463 }
464
465 static NSS_STATUS
466 _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
467 {
468         nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
469         struct winbindd_response response;
470         struct winbindd_request request;
471         NSS_STATUS ret;
472         int af;
473
474         ZERO_STRUCT(response);
475         ZERO_STRUCT(request);
476
477         /* I assume there that AI_ADDRCONFIG cases are handled in nss
478            frontend code, at least it seems done so in solaris...
479
480            we will give NO_DATA for pure IPv6; IPv4 will be returned for
481            AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
482            IPv4 to IPv6.
483          */
484 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
485         af = argp->key.ipnode.af_family;
486         if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
487                 argp->h_errno = NO_DATA;
488                 return NSS_STATUS_UNAVAIL;
489         }
490 #else
491         /* I'm not that sure if this is correct, but... */
492         af = AF_INET6;
493 #endif
494
495         strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
496         request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
497
498         if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
499                 == NSS_STATUS_SUCCESS ) {
500           ret = parse_response(af, argp, &response);
501         }
502
503         free_response(&response);
504         return ret;
505 }
506
507 static NSS_STATUS
508 _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
509 {
510         nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
511         struct winbindd_response response;
512         struct winbindd_request request;
513         NSS_STATUS ret;
514
515         ZERO_STRUCT(response);
516         ZERO_STRUCT(request);
517         
518         strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
519         request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
520
521         if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
522                 == NSS_STATUS_SUCCESS ) {
523           ret = parse_response(AF_INET, argp, &response);
524         }
525
526         free_response(&response);
527         return ret;
528 }
529
530 static NSS_STATUS
531 _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
532 {
533         NSS_STATUS ret;
534         struct winbindd_response response;
535         struct winbindd_request request;
536         nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
537         const char *p;
538
539         ZERO_STRUCT(response);
540         ZERO_STRUCT(request);
541
542         /* winbindd currently does not resolve IPv6 */
543         if(argp->key.hostaddr.type == AF_INET6) {
544                 argp->h_errno = NO_DATA;
545                 return NSS_STATUS_UNAVAIL;
546         }
547
548         p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
549                         request.data.winsreq, INET6_ADDRSTRLEN);
550
551         ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
552
553         if( ret == NSS_STATUS_SUCCESS) {
554           parse_response(argp->key.hostaddr.type, argp, &response);
555         }
556         free_response(&response);
557         return ret;
558 }
559
560 /* winbind does not provide setent, getent, endent for wins */
561 static NSS_STATUS
562 _nss_winbind_common_endent(nss_backend_t* be, void *args)
563 {
564         return (NSS_STATUS_UNAVAIL);
565 }
566
567 static NSS_STATUS
568 _nss_winbind_common_setent(nss_backend_t* be, void *args)
569 {
570         return (NSS_STATUS_UNAVAIL);
571 }
572
573 static NSS_STATUS
574 _nss_winbind_common_getent(nss_backend_t* be, void *args)
575 {
576         return (NSS_STATUS_UNAVAIL);
577 }
578
579 static nss_backend_t*
580 _nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
581 {
582         nss_backend_t* be;
583
584         if(!(be = SMB_MALLOC_P(nss_backend_t)) )
585         return NULL;
586
587         be->ops = ops;
588         be->n_ops = n_ops;
589
590         return be;
591 }
592
593 static NSS_STATUS
594 _nss_winbind_common_destr (nss_backend_t* be, void* args)
595 {
596         SAFE_FREE(be);
597         return NSS_STATUS_SUCCESS;
598 }
599
600 static nss_backend_op_t ipnodes_ops[] = {
601         _nss_winbind_common_destr,
602         _nss_winbind_common_endent,
603         _nss_winbind_common_setent,
604         _nss_winbind_common_getent,
605         _nss_winbind_ipnodes_getbyname,
606         _nss_winbind_hosts_getbyaddr,
607 };
608
609 nss_backend_t *
610 _nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
611         const char      *dummy1, *dummy2, *dummy3;
612 {
613         return (_nss_winbind_common_constr(ipnodes_ops,
614                 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
615 }
616
617 static nss_backend_op_t host_ops[] = {
618         _nss_winbind_common_destr,
619         _nss_winbind_common_endent,
620         _nss_winbind_common_setent,
621         _nss_winbind_common_getent,
622         _nss_winbind_hosts_getbyname,
623         _nss_winbind_hosts_getbyaddr,
624 };
625
626 nss_backend_t *
627 _nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
628         const char      *dummy1, *dummy2, *dummy3;
629 {
630         return (_nss_winbind_common_constr(host_ops,
631                 sizeof (host_ops) / sizeof (host_ops[0])));
632 }
633
634 #endif  /* defined(SUNOS5) */
635 #endif  /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */