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