]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
f451cc541c05fcecb6711ac6ca245fc8c5441ee4
[openldap] / libraries / libldap / util-int.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2012 The OpenLDAP Foundation.
5  * Portions Copyright 1998 A. Hartgers.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Bart Hartgers for inclusion in
18  * OpenLDAP Software.
19  */
20
21 /*
22  * util-int.c   Various functions to replace missing threadsafe ones.
23  *                              Without the real *_r funcs, things will
24  *                              work, but might not be threadsafe. 
25  */
26
27 #include "portable.h"
28
29 #include <ac/stdlib.h>
30
31 #include <ac/errno.h>
32 #include <ac/socket.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35 #include <ac/unistd.h>
36
37 #include "ldap-int.h"
38
39 #ifndef h_errno
40 /* newer systems declare this in <netdb.h> for you, older ones don't.
41  * harmless to declare it again (unless defined by a macro).
42  */
43 extern int h_errno;
44 #endif
45
46 #ifdef HAVE_HSTRERROR
47 # define HSTRERROR(e)   hstrerror(e)
48 #else
49 # define HSTRERROR(e)   hp_strerror(e)
50 #endif
51
52 #ifndef LDAP_R_COMPILE
53 # undef HAVE_REENTRANT_FUNCTIONS
54 # undef HAVE_CTIME_R
55 # undef HAVE_GETHOSTBYNAME_R
56 # undef HAVE_GETHOSTBYADDR_R
57
58 #else
59 # include <ldap_pvt_thread.h>
60   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
61   ldap_pvt_thread_mutex_t ldap_int_hostname_mutex;
62
63 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
64          && defined( CTIME_R_NARGS )
65 #   define USE_CTIME_R
66 # else
67         static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
68 # endif
69
70 /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
71
72 #ifdef LDAP_DEVEL
73         /* to be released with 2.5 */
74 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
75         /* we use the same mutex for gmtime(3) and localtime(3)
76          * because implementations may use the same buffer
77          * for both functions */
78         static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
79 #endif
80 #else /* ! LDAP_DEVEL */
81         ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
82 #endif /* ! LDAP_DEVEL */
83
84 # if defined(HAVE_GETHOSTBYNAME_R) && \
85         (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
86         /* Don't know how to handle this version, pretend it's not there */
87 #       undef HAVE_GETHOSTBYNAME_R
88 # endif
89 # if defined(HAVE_GETHOSTBYADDR_R) && \
90         (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
91         /* Don't know how to handle this version, pretend it's not there */
92 #       undef HAVE_GETHOSTBYADDR_R
93 # endif
94 #endif /* LDAP_R_COMPILE */
95
96 char *ldap_pvt_ctime( const time_t *tp, char *buf )
97 {
98 #ifdef USE_CTIME_R
99 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
100 #       error "CTIME_R_NARGS should be 2 or 3"
101 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
102         return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
103 # elif CTIME_R_NARGS > 2
104         return ctime_r(tp,buf,26);
105 # else
106         return ctime_r(tp,buf);
107 # endif   
108
109 #else
110
111         LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
112         AC_MEMCPY( buf, ctime(tp), 26 );
113         LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
114
115         return buf;
116 #endif  
117 }
118
119 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
120 int
121 ldap_pvt_gmtime_lock( void )
122 {
123 # ifndef LDAP_R_COMPILE
124         return 0;
125 # else /* LDAP_R_COMPILE */
126         return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
127 # endif /* LDAP_R_COMPILE */
128 }
129
130 int
131 ldap_pvt_gmtime_unlock( void )
132 {
133 # ifndef LDAP_R_COMPILE
134         return 0;
135 # else /* LDAP_R_COMPILE */
136         return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
137 # endif /* LDAP_R_COMPILE */
138 }
139 #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
140
141 #ifndef USE_GMTIME_R
142 struct tm *
143 ldap_pvt_gmtime( const time_t *timep, struct tm *result )
144 {
145         struct tm *tm_ptr;
146
147         LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
148         tm_ptr = gmtime( timep );
149         if ( tm_ptr == NULL ) {
150                 result = NULL;
151
152         } else {
153                 *result = *tm_ptr;
154         }
155         LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
156
157         return result;
158 }
159 #endif /* !USE_GMTIME_R */
160
161 #ifndef USE_LOCALTIME_R
162 struct tm *
163 ldap_pvt_localtime( const time_t *timep, struct tm *result )
164 {
165         struct tm *tm_ptr;
166
167         LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
168         tm_ptr = localtime( timep );
169         if ( tm_ptr == NULL ) {
170                 result = NULL;
171
172         } else {
173                 *result = *tm_ptr;
174         }
175         LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
176
177         return result;
178 }
179 #endif /* !USE_LOCALTIME_R */
180
181 /* return a broken out time, with microseconds
182  * Must be mutex-protected.
183  */
184 #ifdef _WIN32
185 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
186  * also need to use a high resolution timer to get microseconds.
187  * This is pretty clunky.
188  */
189 void
190 ldap_pvt_gettime( struct lutil_tm *tm )
191 {
192         static LARGE_INTEGER cFreq;
193         static LARGE_INTEGER prevCount;
194         static int subs;
195         static int offset;
196         LARGE_INTEGER count;
197         SYSTEMTIME st;
198
199         GetSystemTime( &st );
200         QueryPerformanceCounter( &count );
201
202         /* It shouldn't ever go backwards, but multiple CPUs might
203          * be able to hit in the same tick.
204          */
205         if ( count.QuadPart <= prevCount.QuadPart ) {
206                 subs++;
207         } else {
208                 subs = 0;
209                 prevCount = count;
210         }
211
212         /* We assume Windows has at least a vague idea of
213          * when a second begins. So we align our microsecond count
214          * with the Windows millisecond count using this offset.
215          * We retain the submillisecond portion of our own count.
216          *
217          * Note - this also assumes that the relationship between
218          * the PerformanceCouunter and SystemTime stays constant;
219          * that assumption breaks if the SystemTime is adjusted by
220          * an external action.
221          */
222         if ( !cFreq.QuadPart ) {
223                 long long t;
224                 int usec;
225                 QueryPerformanceFrequency( &cFreq );
226
227                 /* just get sub-second portion of counter */
228                 t = count.QuadPart % cFreq.QuadPart;
229
230                 /* convert to microseconds */
231                 t *= 1000000;
232                 usec = t / cFreq.QuadPart;
233
234                 offset = usec - st.wMilliseconds * 1000;
235         }
236
237         tm->tm_usub = subs;
238
239         /* convert to microseconds */
240         count.QuadPart %= cFreq.QuadPart;
241         count.QuadPart *= 1000000;
242         count.QuadPart /= cFreq.QuadPart;
243         count.QuadPart -= offset;
244
245         tm->tm_usec = count.QuadPart % 1000000;
246         if ( tm->tm_usec < 0 )
247                 tm->tm_usec += 1000000;
248
249         /* any difference larger than microseconds is
250          * already reflected in st
251          */
252
253         tm->tm_sec = st.wSecond;
254         tm->tm_min = st.wMinute;
255         tm->tm_hour = st.wHour;
256         tm->tm_mday = st.wDay;
257         tm->tm_mon = st.wMonth - 1;
258         tm->tm_year = st.wYear - 1900;
259 }
260 #else
261 void
262 ldap_pvt_gettime( struct lutil_tm *ltm )
263 {
264         struct timeval tv;
265         static struct timeval prevTv;
266         static int subs;
267
268         struct tm tm;
269         time_t t;
270
271         gettimeofday( &tv, NULL );
272         t = tv.tv_sec;
273
274         if ( tv.tv_sec < prevTv.tv_sec
275                 || ( tv.tv_sec == prevTv.tv_sec && tv.tv_usec <= prevTv.tv_usec )) {
276                 subs++;
277         } else {
278                 subs = 0;
279                 prevTv = tv;
280         }
281
282         ltm->tm_usub = subs;
283
284         ldap_pvt_gmtime( &t, &tm );
285
286         ltm->tm_sec = tm.tm_sec;
287         ltm->tm_min = tm.tm_min;
288         ltm->tm_hour = tm.tm_hour;
289         ltm->tm_mday = tm.tm_mday;
290         ltm->tm_mon = tm.tm_mon;
291         ltm->tm_year = tm.tm_year;
292         ltm->tm_usec = tv.tv_usec;
293 }
294 #endif
295
296 size_t
297 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
298 {
299         struct lutil_tm tm;
300         int n;
301
302         ldap_pvt_gettime( &tm );
303
304         n = snprintf( buf, len,
305                 "%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
306                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
307                 tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_usub, replica, mod );
308
309         if( n < 0 ) return 0;
310         return ( (size_t) n < len ) ? n : 0;
311 }
312
313 #define BUFSTART (1024-32)
314 #define BUFMAX (32*1024-32)
315
316 #if defined(LDAP_R_COMPILE)
317 static char *safe_realloc( char **buf, int len );
318
319 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
320 static int copy_hostent( struct hostent *res,
321         char **buf, struct hostent * src );
322 #endif
323 #endif
324
325 int ldap_pvt_gethostbyname_a(
326         const char *name, 
327         struct hostent *resbuf,
328         char **buf,
329         struct hostent **result,
330         int *herrno_ptr )
331 {
332 #if defined( HAVE_GETHOSTBYNAME_R )
333
334 # define NEED_SAFE_REALLOC 1   
335         int r=-1;
336         int buflen=BUFSTART;
337         *buf = NULL;
338         for(;buflen<BUFMAX;) {
339                 if (safe_realloc( buf, buflen )==NULL)
340                         return r;
341
342 #if (GETHOSTBYNAME_R_NARGS < 6)
343                 *result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
344                 r = (*result == NULL) ?  -1 : 0;
345 #else
346                 r = gethostbyname_r( name, resbuf, *buf,
347                         buflen, result, herrno_ptr );
348 #endif
349
350                 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
351                        name, r, 0 );
352
353 #ifdef NETDB_INTERNAL
354                 if ((r<0) &&
355                         (*herrno_ptr==NETDB_INTERNAL) &&
356                         (errno==ERANGE))
357                 {
358                         buflen*=2;
359                         continue;
360                 }
361 #endif
362                 return r;
363         }
364         return -1;
365 #elif defined( LDAP_R_COMPILE )
366 # define NEED_COPY_HOSTENT   
367         struct hostent *he;
368         int     retval;
369         *buf = NULL;
370         
371         LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
372         
373         he = gethostbyname( name );
374         
375         if (he==NULL) {
376                 *herrno_ptr = h_errno;
377                 retval = -1;
378         } else if (copy_hostent( resbuf, buf, he )<0) {
379                 *herrno_ptr = -1;
380                 retval = -1;
381         } else {
382                 *result = resbuf;
383                 retval = 0;
384         }
385         
386         LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
387         
388         return retval;
389 #else   
390         *buf = NULL;
391         *result = gethostbyname( name );
392
393         if (*result!=NULL) {
394                 return 0;
395         }
396
397         *herrno_ptr = h_errno;
398         
399         return -1;
400 #endif  
401 }
402
403 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
404 static const char *
405 hp_strerror( int err )
406 {
407         switch (err) {
408         case HOST_NOT_FOUND:    return _("Host not found (authoritative)");
409         case TRY_AGAIN:                 return _("Host not found (server fail?)");
410         case NO_RECOVERY:               return _("Non-recoverable failure");
411         case NO_DATA:                   return _("No data of requested type");
412 #ifdef NETDB_INTERNAL
413         case NETDB_INTERNAL:    return STRERROR( errno );
414 #endif
415         }
416         return _("Unknown resolver error");
417 }
418 #endif
419
420 int ldap_pvt_get_hname(
421         const struct sockaddr *sa,
422         int len,
423         char *name,
424         int namelen,
425         char **err )
426 {
427         int rc;
428 #if defined( HAVE_GETNAMEINFO )
429
430         LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
431         rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
432         LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
433         if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
434         return rc;
435
436 #else /* !HAVE_GETNAMEINFO */
437         char *addr;
438         int alen;
439         struct hostent *hp = NULL;
440 #ifdef HAVE_GETHOSTBYADDR_R
441         struct hostent hb;
442         int buflen=BUFSTART, h_errno;
443         char *buf=NULL;
444 #endif
445
446 #ifdef LDAP_PF_INET6
447         if (sa->sa_family == AF_INET6) {
448                 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
449                 addr = (char *)&sin->sin6_addr;
450                 alen = sizeof(sin->sin6_addr);
451         } else
452 #endif
453         if (sa->sa_family == AF_INET) {
454                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
455                 addr = (char *)&sin->sin_addr;
456                 alen = sizeof(sin->sin_addr);
457         } else {
458                 rc = NO_RECOVERY;
459                 *err = (char *)HSTRERROR( rc );
460                 return rc;
461         }
462 #if defined( HAVE_GETHOSTBYADDR_R )
463         for(;buflen<BUFMAX;) {
464                 if (safe_realloc( &buf, buflen )==NULL) {
465                         *err = (char *)STRERROR( ENOMEM );
466                         return ENOMEM;
467                 }
468 #if (GETHOSTBYADDR_R_NARGS < 8)
469                 hp=gethostbyaddr_r( addr, alen, sa->sa_family,
470                         &hb, buf, buflen, &h_errno );
471                 rc = (hp == NULL) ? -1 : 0;
472 #else
473                 rc = gethostbyaddr_r( addr, alen, sa->sa_family,
474                         &hb, buf, buflen, 
475                         &hp, &h_errno );
476 #endif
477 #ifdef NETDB_INTERNAL
478                 if ((rc<0) &&
479                         (h_errno==NETDB_INTERNAL) &&
480                         (errno==ERANGE))
481                 {
482                         buflen*=2;
483                         continue;
484                 }
485 #endif
486                 break;
487         }
488         if (hp) {
489                 strncpy( name, hp->h_name, namelen );
490         } else {
491                 *err = (char *)HSTRERROR( h_errno );
492         }
493         LDAP_FREE(buf);
494 #else /* HAVE_GETHOSTBYADDR_R */
495
496         LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
497         hp = gethostbyaddr( addr, alen, sa->sa_family );
498         if (hp) {
499                 strncpy( name, hp->h_name, namelen );
500                 rc = 0;
501         } else {
502                 rc = h_errno;
503                 *err = (char *)HSTRERROR( h_errno );
504         }
505         LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
506
507 #endif  /* !HAVE_GETHOSTBYADDR_R */
508         return rc;
509 #endif  /* !HAVE_GETNAMEINFO */
510 }
511
512 int ldap_pvt_gethostbyaddr_a(
513         const char *addr,
514         int len,
515         int type,
516         struct hostent *resbuf,
517         char **buf,
518         struct hostent **result,
519         int *herrno_ptr )
520 {
521 #if defined( HAVE_GETHOSTBYADDR_R )
522
523 # undef NEED_SAFE_REALLOC
524 # define NEED_SAFE_REALLOC   
525         int r=-1;
526         int buflen=BUFSTART;
527         *buf = NULL;   
528         for(;buflen<BUFMAX;) {
529                 if (safe_realloc( buf, buflen )==NULL)
530                         return r;
531 #if (GETHOSTBYADDR_R_NARGS < 8)
532                 *result=gethostbyaddr_r( addr, len, type,
533                         resbuf, *buf, buflen, herrno_ptr );
534                 r = (*result == NULL) ? -1 : 0;
535 #else
536                 r = gethostbyaddr_r( addr, len, type,
537                         resbuf, *buf, buflen, 
538                         result, herrno_ptr );
539 #endif
540
541 #ifdef NETDB_INTERNAL
542                 if ((r<0) &&
543                         (*herrno_ptr==NETDB_INTERNAL) &&
544                         (errno==ERANGE))
545                 {
546                         buflen*=2;
547                         continue;
548                 }
549 #endif
550                 return r;
551         }
552         return -1;
553 #elif defined( LDAP_R_COMPILE )
554 # undef NEED_COPY_HOSTENT
555 # define NEED_COPY_HOSTENT   
556         struct hostent *he;
557         int     retval;
558         *buf = NULL;   
559         
560         LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
561         he = gethostbyaddr( addr, len, type );
562         
563         if (he==NULL) {
564                 *herrno_ptr = h_errno;
565                 retval = -1;
566         } else if (copy_hostent( resbuf, buf, he )<0) {
567                 *herrno_ptr = -1;
568                 retval = -1;
569         } else {
570                 *result = resbuf;
571                 retval = 0;
572         }
573         LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
574         
575         return retval;
576
577 #else /* gethostbyaddr() */
578         *buf = NULL;   
579         *result = gethostbyaddr( addr, len, type );
580
581         if (*result!=NULL) {
582                 return 0;
583         }
584         return -1;
585 #endif  
586 }
587 /* 
588  * ldap_int_utils_init() should be called before any other function.
589  */
590
591 void ldap_int_utils_init( void )
592 {
593         static int done=0;
594         if (done)
595           return;
596         done=1;
597
598 #ifdef LDAP_R_COMPILE
599 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
600         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
601 #endif
602 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
603         ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
604 #endif
605         ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
606
607         ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
608
609 #ifdef HAVE_CYRUS_SASL
610         ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
611 #endif
612 #ifdef HAVE_GSSAPI
613         ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
614 #endif
615 #endif
616
617         /* call other module init functions here... */
618 }
619
620 #if defined( NEED_COPY_HOSTENT )
621 # undef NEED_SAFE_REALLOC
622 #define NEED_SAFE_REALLOC
623
624 static char *cpy_aliases(
625         char ***tgtio,
626         char *buf,
627         char **src )
628 {
629         int len;
630         char **tgt=*tgtio;
631         for( ; (*src) ; src++ ) {
632                 len = strlen( *src ) + 1;
633                 AC_MEMCPY( buf, *src, len );
634                 *tgt++=buf;
635                 buf+=len;
636         }
637         *tgtio=tgt;   
638         return buf;
639 }
640
641 static char *cpy_addresses(
642         char ***tgtio,
643         char *buf,
644         char **src,
645         int len )
646 {
647         char **tgt=*tgtio;
648         for( ; (*src) ; src++ ) {
649                 AC_MEMCPY( buf, *src, len );
650                 *tgt++=buf;
651                 buf+=len;
652         }
653         *tgtio=tgt;      
654         return buf;
655 }
656
657 static int copy_hostent(
658         struct hostent *res,
659         char **buf,
660         struct hostent * src )
661 {
662         char    **p;
663         char    **tp;
664         char    *tbuf;
665         int     name_len;
666         int     n_alias=0;
667         int     total_alias_len=0;
668         int     n_addr=0;
669         int     total_addr_len=0;
670         int     total_len;
671           
672         /* calculate the size needed for the buffer */
673         name_len = strlen( src->h_name ) + 1;
674         
675         if( src->h_aliases != NULL ) {
676                 for( p = src->h_aliases; (*p) != NULL; p++ ) {
677                         total_alias_len += strlen( *p ) + 1;
678                         n_alias++; 
679                 }
680         }
681
682         if( src->h_addr_list != NULL ) {
683                 for( p = src->h_addr_list; (*p) != NULL; p++ ) {
684                         n_addr++;
685                 }
686                 total_addr_len = n_addr * src->h_length;
687         }
688         
689         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
690                 total_addr_len + total_alias_len + name_len;
691         
692         if (safe_realloc( buf, total_len )) {                    
693                 tp = (char **) *buf;
694                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
695                 AC_MEMCPY( res, src, sizeof( struct hostent ) );
696                 /* first the name... */
697                 AC_MEMCPY( tbuf, src->h_name, name_len );
698                 res->h_name = tbuf; tbuf+=name_len;
699                 /* now the aliases */
700                 res->h_aliases = tp;
701                 if ( src->h_aliases != NULL ) {
702                         tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
703                 }
704                 *tp++=NULL;
705                 /* finally the addresses */
706                 res->h_addr_list = tp;
707                 if ( src->h_addr_list != NULL ) {
708                         tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
709                 }
710                 *tp++=NULL;
711                 return 0;
712         }
713         return -1;
714 }
715 #endif
716
717 #if defined( NEED_SAFE_REALLOC )
718 static char *safe_realloc( char **buf, int len )
719 {
720         char *tmpbuf;
721         tmpbuf = LDAP_REALLOC( *buf, len );
722         if (tmpbuf) {
723                 *buf=tmpbuf;
724         } 
725         return tmpbuf;
726 }
727 #endif
728
729 char * ldap_pvt_get_fqdn( char *name )
730 {
731         char *fqdn, *ha_buf;
732         char hostbuf[MAXHOSTNAMELEN+1];
733         struct hostent *hp, he_buf;
734         int rc, local_h_errno;
735
736         if( name == NULL ) {
737                 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
738                         hostbuf[MAXHOSTNAMELEN] = '\0';
739                         name = hostbuf;
740                 } else {
741                         name = "localhost";
742                 }
743         }
744
745         rc = ldap_pvt_gethostbyname_a( name,
746                 &he_buf, &ha_buf, &hp, &local_h_errno );
747
748         if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
749                 fqdn = LDAP_STRDUP( name );
750         } else {
751                 fqdn = LDAP_STRDUP( hp->h_name );
752         }
753
754         LDAP_FREE( ha_buf );
755         return fqdn;
756 }
757
758 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
759         && !defined( HAVE_GAI_STRERROR )
760 char *ldap_pvt_gai_strerror (int code) {
761         static struct {
762                 int code;
763                 const char *msg;
764         } values[] = {
765 #ifdef EAI_ADDRFAMILY
766                 { EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
767 #endif
768                 { EAI_AGAIN, N_("Temporary failure in name resolution") },
769                 { EAI_BADFLAGS, N_("Bad value for ai_flags") },
770                 { EAI_FAIL, N_("Non-recoverable failure in name resolution") },
771                 { EAI_FAMILY, N_("ai_family not supported") },
772                 { EAI_MEMORY, N_("Memory allocation failure") },
773 #ifdef EAI_NODATA
774                 { EAI_NODATA, N_("No address associated with hostname") },
775 #endif    
776                 { EAI_NONAME, N_("Name or service not known") },
777                 { EAI_SERVICE, N_("Servname not supported for ai_socktype") },
778                 { EAI_SOCKTYPE, N_("ai_socktype not supported") },
779                 { EAI_SYSTEM, N_("System error") },
780                 { 0, NULL }
781         };
782
783         int i;
784
785         for ( i = 0; values[i].msg != NULL; i++ ) {
786                 if ( values[i].code == code ) {
787                         return (char *) _(values[i].msg);
788                 }
789         }
790         
791         return _("Unknown error");
792 }
793 #endif