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