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