]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
e9e2e55e6b52c2c09cf9f366e02d2823e0a863d8
[openldap] / libraries / libldap / util-int.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * util-int.c   Various functions to replace missing threadsafe ones.
8  *                                Without the real *_r funcs, things will
9  *                                work, but might not be threadsafe. 
10  * 
11  * Written by Bart Hartgers.
12  *
13  * Copyright 1998, A. Hartgers, All rights reserved.
14  * This software is not subject to any license of Eindhoven University of
15  * Technology, since it was written in my spare time.
16  *                      
17  * Redistribution and use in source and binary forms are permitted only
18  * as authorized by the OpenLDAP Public License.  A copy of this
19  * license is available at http://www.OpenLDAP.org/license.html or
20  * in file LICENSE in the top-level directory of the distribution.
21  */ 
22
23
24 #include "portable.h"
25
26 #include <ac/stdlib.h>
27
28 #include <ac/errno.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/time.h>
32 #include <ac/unistd.h>
33
34 #include "ldap-int.h"
35
36 #ifndef LDAP_R_COMPILE
37 # undef HAVE_REENTRANT_FUNCTIONS
38 # undef HAVE_CTIME_R
39 # undef HAVE_GETHOSTBYNAME_R
40 # undef HAVE_GETHOSTBYADDR_R
41
42 #else
43 # include <ldap_pvt_thread.h>
44   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
45
46 #if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
47         && defined( CTIME_R_NARGS )
48 # define USE_CTIME_R
49 # else
50         static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
51 # endif
52
53 # if defined(HAVE_GETHOSTBYNAME_R) && \
54         (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
55         /* Don't know how to handle this version, pretend it's not there */
56 #       undef HAVE_GETHOSTBYNAME_R
57 # endif
58 # if defined(HAVE_GETHOSTBYADDR_R) && \
59         (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
60         /* Don't know how to handle this version, pretend it's not there */
61 #       undef HAVE_GETHOSTBYADDR_R
62 # endif
63 #endif /* LDAP_R_COMPILE */
64
65 char *ldap_pvt_ctime( const time_t *tp, char *buf )
66 {
67 #ifdef USE_CTIME_R
68 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
69 #       error "CTIME_R_NARGS should be 2 or 3"
70 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
71         return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
72 # elif CTIME_R_NARGS > 2
73         return ctime_r(tp,buf,26);
74 # else
75         return ctime_r(tp,buf);
76 # endif   
77
78 #else
79
80 # ifdef LDAP_R_COMPILE
81         ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
82 # endif
83
84         AC_MEMCPY( buf, ctime(tp), 26 );
85
86 # ifdef LDAP_R_COMPILE
87         ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
88 # endif
89
90         return buf;
91 #endif  
92 }
93
94 #define BUFSTART (1024-32)
95 #define BUFMAX (32*1024-32)
96
97 static char *safe_realloc( char **buf, int len );
98
99 #if !defined(HAVE_GETHOSTBYNAME_R) && defined(LDAP_R_COMPILE)
100 static int copy_hostent( struct hostent *res,
101         char **buf, struct hostent * src );
102 #endif
103
104 int ldap_pvt_gethostbyname_a(
105         const char *name, 
106         struct hostent *resbuf,
107         char **buf,
108         struct hostent **result,
109         int *herrno_ptr )
110 {
111 #if defined( HAVE_GETHOSTBYNAME_R )
112
113 # define NEED_SAFE_REALLOC 1   
114         int r=-1;
115         int buflen=BUFSTART;
116         *buf = NULL;
117         for(;buflen<BUFMAX;) {
118                 if (safe_realloc( buf, buflen )==NULL)
119                         return r;
120
121 #if (GETHOSTBYNAME_R_NARGS < 6)
122                 *result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
123                 r = (*result == NULL) ?  -1 : 0;
124 #else
125                 r = gethostbyname_r( name, resbuf, *buf,
126                         buflen, result, herrno_ptr );
127 #endif
128
129                 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
130                        name, r, 0 );
131
132 #ifdef NETDB_INTERNAL
133                 if ((r<0) &&
134                         (*herrno_ptr==NETDB_INTERNAL) &&
135                         (errno==ERANGE))
136                 {
137                         buflen*=2;
138                         continue;
139                 }
140 #endif
141                 return r;
142         }
143         return -1;
144 #elif defined( LDAP_R_COMPILE )
145 # define NEED_COPY_HOSTENT   
146         struct hostent *he;
147         int     retval;
148         *buf = NULL;
149         
150         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
151         
152         he = gethostbyname( name );
153         
154         if (he==NULL) {
155                 *herrno_ptr = h_errno;
156                 retval = -1;
157         } else if (copy_hostent( resbuf, buf, he )<0) {
158                 *herrno_ptr = -1;
159                 retval = -1;
160         } else {
161                 *result = resbuf;
162                 retval = 0;
163         }
164         
165         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
166         
167         return retval;
168 #else   
169         *buf = NULL;
170         *result = gethostbyname( name );
171
172         if (*result!=NULL) {
173                 return 0;
174         }
175
176         *herrno_ptr = h_errno;
177         
178         return -1;
179 #endif  
180 }
181          
182 int ldap_pvt_gethostbyaddr_a(
183         const char *addr,
184         int len,
185         int type,
186         struct hostent *resbuf,
187         char **buf,
188         struct hostent **result,
189         int *herrno_ptr )
190 {
191 #if defined( HAVE_GETHOSTBYADDR_R )
192
193 # undef NEED_SAFE_REALLOC
194 # define NEED_SAFE_REALLOC   
195         int r=-1;
196         int buflen=BUFSTART;
197         *buf = NULL;   
198         for(;buflen<BUFMAX;) {
199                 if (safe_realloc( buf, buflen )==NULL)
200                         return r;
201 #if (GETHOSTBYADDR_R_NARGS < 8)
202                 *result=gethostbyaddr_r( addr, len, type,
203                         resbuf, *buf, buflen, herrno_ptr );
204                 r = (*result == NULL) ? -1 : 0;
205 #else
206                 r = gethostbyaddr_r( addr, len, type,
207                         resbuf, *buf, buflen, 
208                         result, herrno_ptr );
209 #endif
210
211 #ifdef NETDB_INTERNAL
212                 if ((r<0) &&
213                         (*herrno_ptr==NETDB_INTERNAL) &&
214                         (errno==ERANGE))
215                 {
216                         buflen*=2;
217                         continue;
218                 }
219 #endif
220                 return r;
221         }
222         return -1;
223 #elif defined( LDAP_R_COMPILE )
224 # undef NEED_COPY_HOSTENT
225 # define NEED_COPY_HOSTENT   
226         struct hostent *he;
227         int     retval;
228         *buf = NULL;   
229         
230         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
231         
232         he = gethostbyaddr( addr, len, type );
233         
234         if (he==NULL) {
235                 *herrno_ptr = h_errno;
236                 retval = -1;
237         } else if (copy_hostent( resbuf, buf, he )<0) {
238                 *herrno_ptr = -1;
239                 retval = -1;
240         } else {
241                 *result = resbuf;
242                 retval = 0;
243         }
244         
245         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
246         
247         return retval;
248
249 #else /* gethostbyaddr() */
250         *buf = NULL;   
251         *result = gethostbyaddr( addr, len, type );
252
253         if (*result!=NULL) {
254                 return 0;
255         }
256         return -1;
257 #endif  
258 }
259 /* 
260  * ldap_int_utils_init() should be called before any other function.
261  */
262
263 void ldap_int_utils_init( void )
264 {
265         static int done=0;
266         if (done)
267           return;
268         done=1;
269
270 #ifdef LDAP_R_COMPILE
271 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
272         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
273 #endif
274         ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
275 #endif
276
277         /* call other module init functions here... */
278 }
279
280 #if defined( NEED_COPY_HOSTENT )
281 # undef NEED_SAFE_REALLOC
282 #define NEED_SAFE_REALLOC
283
284 static char *cpy_aliases(
285         char ***tgtio,
286         char *buf,
287         char **src )
288 {
289         int len;
290         char **tgt=*tgtio;
291         for( ; (*src) ; src++ ) {
292                 len = strlen( *src ) + 1;
293                 AC_MEMCPY( buf, *src, len );
294                 *tgt++=buf;
295                 buf+=len;
296         }
297         *tgtio=tgt;   
298         return buf;
299 }
300
301 static char *cpy_addresses(
302         char ***tgtio,
303         char *buf,
304         char **src,
305         int len )
306 {
307         char **tgt=*tgtio;
308         for( ; (*src) ; src++ ) {
309                 AC_MEMCPY( buf, *src, len );
310                 *tgt++=buf;
311                 buf+=len;
312         }
313         *tgtio=tgt;      
314         return buf;
315 }
316
317 static int copy_hostent(
318         struct hostent *res,
319         char **buf,
320         struct hostent * src )
321 {
322         char    **p;
323         char    **tp;
324         char    *tbuf;
325         int     name_len;
326         int     n_alias=0;
327         int     total_alias_len=0;
328         int     n_addr=0;
329         int     total_addr_len;
330         int     total_len;
331           
332         /* calculate the size needed for the buffer */
333         name_len = strlen( src->h_name ) + 1;
334         
335         if( src->h_aliases != NULL ) {
336                 for( p = src->h_aliases; (*p) != NULL; p++ ) {
337                         total_alias_len += strlen( *p ) + 1;
338                         n_alias++; 
339                 }
340         }
341
342         if( src->h_addr_list != NULL ) {
343                 for( p = src->h_addr_list; (*p) != NULL; p++ ) {
344                         n_addr++;
345                 }
346                 total_addr_len = n_addr * src->h_length;
347         }
348         
349         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
350                 total_addr_len + total_alias_len + name_len;
351         
352         if (safe_realloc( buf, total_len )) {                    
353                 tp = (char **) *buf;
354                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
355                 AC_MEMCPY( res, src, sizeof( struct hostent ) );
356                 /* first the name... */
357                 AC_MEMCPY( tbuf, src->h_name, name_len );
358                 res->h_name = tbuf; tbuf+=name_len;
359                 /* now the aliases */
360                 res->h_aliases = tp;
361                 if ( src->h_aliases != NULL ) {
362                         tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
363                 }
364                 *tp++=NULL;
365                 /* finally the addresses */
366                 res->h_addr_list = tp;
367                 if ( src->h_addr_list != NULL ) {
368                         tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
369                 }
370                 *tp++=NULL;
371                 return 0;
372         }
373         return -1;
374 }
375 #endif
376
377 #if defined( NEED_SAFE_REALLOC )
378 static char *safe_realloc( char **buf, int len )
379 {
380         char *tmpbuf;
381         tmpbuf = LDAP_REALLOC( *buf, len );
382         if (tmpbuf) {
383                 *buf=tmpbuf;
384         } 
385         return tmpbuf;
386 }
387 #endif
388
389 char * ldap_pvt_get_fqdn( char *name )
390 {
391         char *fqdn, *ha_buf;
392         char hostbuf[MAXHOSTNAMELEN+1];
393         struct hostent *hp, he_buf;
394         int rc, local_h_errno;
395
396         if( name == NULL ) {
397                 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
398                         hostbuf[MAXHOSTNAMELEN] = '\0';
399                         name = hostbuf;
400                 } else {
401                         name = "localhost";
402                 }
403         }
404
405         rc = ldap_pvt_gethostbyname_a( name,
406                 &he_buf, &ha_buf, &hp, &local_h_errno );
407
408         if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
409                 fqdn = LDAP_STRDUP( name );
410         } else {
411                 fqdn = LDAP_STRDUP( hp->h_name );
412         }
413
414         LDAP_FREE( ha_buf );
415         return fqdn;
416 }
417
418 #if defined( HAVE_GETADDRINFO ) && !defined( HAVE_GAI_STRERROR )
419 char *ldap_pvt_gai_strerror (int code) {
420         static struct {
421                 int code;
422                 const char *msg;
423         } values[] = {
424 #ifdef EAI_ADDRFAMILY
425                 { EAI_ADDRFAMILY, "Address family for hostname not supported" },
426 #endif
427                 { EAI_AGAIN, "Temporary failure in name resolution" },
428                 { EAI_BADFLAGS, "Bad value for ai_flags" },
429                 { EAI_FAIL, "Non-recoverable failure in name resolution" },
430                 { EAI_FAMILY, "ai_family not supported" },
431                 { EAI_MEMORY, "Memory allocation failure" },
432 #ifdef EAI_NODATA
433                 { EAI_NODATA, "No address associated with hostname" },
434 #endif    
435                 { EAI_NONAME, "Name or service not known" },
436                 { EAI_SERVICE, "Servname not supported for ai_socktype" },
437                 { EAI_SOCKTYPE, "ai_socktype not supported" },
438                 { EAI_SYSTEM, "System error" },
439                 { 0, NULL }
440         };
441
442         int i;
443
444         for ( i = 0; values[i].msg != NULL; i++ ) {
445                 if ( values[i].code == code ) {
446                         return (char *) values[i].msg;
447                 }
448         }
449         
450         return "Unknown error";
451 }
452 #endif