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