]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
6d5886d3654428fb43797175e33f7438d09f514a
[openldap] / libraries / libldap / util-int.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 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 #ifndef GETNAMEINFO
183 static const char *
184 hp_strerror( int err )
185 {
186         switch (err) {
187         case HOST_NOT_FOUND:    return "Host not found (authoritative)";
188         case TRY_AGAIN:         return "Host not found (server fail?)";
189         case NO_RECOVERY:       return "Non-recoverable failure";
190         case NO_DATA:           return "No data of requested type";
191 #ifdef NETDB_INTERNAL
192         case NETDB_INTERNAL:    return STRERROR( errno );
193 #endif
194         default:        break;  
195         }
196         return "Unknown resolver error";
197 }
198 #endif
199
200 int ldap_pvt_get_hname(
201         const struct sockaddr *sa,
202         int len,
203         char *name,
204         int namelen,
205         char **err )
206 {
207         int rc;
208 #if defined( HAVE_GETNAMEINFO )
209
210 #if defined( LDAP_R_COMPILE )
211         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
212 #endif
213         rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
214 #if defined( LDAP_R_COMPILE )
215         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
216 #endif
217         if ( rc ) *err = AC_GAI_STRERROR( rc );
218         return rc;
219
220 #else /* !HAVE_GETNAMEINFO */
221         char *addr;
222         int alen;
223         struct hostent *hp = NULL;
224 #ifdef HAVE_GETHOSTBYADDR_R
225         struct hostent hb;
226         int buflen=BUFSTART, h_errno;
227         char *buf=NULL;
228 #endif
229
230 #ifdef LDAP_PF_INET6
231         if (sa->sa_family == AF_INET6) {
232                 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
233                 addr = (char *)&sin->sin6_addr;
234                 alen = sizeof(sin->sin6_addr);
235         } else
236 #endif
237         if (sa->sa_family == AF_INET) {
238                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
239                 addr = (char *)&sin->sin_addr;
240                 alen = sizeof(sin->sin_addr);
241         } else {
242                 rc = NO_RECOVERY;
243                 *err = hp_strerror( rc );
244                 return rc;
245         }
246 #if defined( HAVE_GETHOSTBYADDR_R )
247         for(;buflen<BUFMAX;) {
248                 if (safe_realloc( &buf, buflen )==NULL) {
249                         *err = STRERROR( ENOMEM );
250                         return ENOMEM;
251                 }
252 #if (GETHOSTBYADDR_R_NARGS < 8)
253                 hp=gethostbyaddr_r( addr, alen, sa->sa_family,
254                         &hb, buf, buflen, &h_errno );
255                 rc = (hp == NULL) ? -1 : 0;
256 #else
257                 rc = gethostbyaddr_r( addr, alen, sa->sa_family,
258                         &hb, buf, buflen, 
259                         &hp, &h_errno );
260 #endif
261 #ifdef NETDB_INTERNAL
262                 if ((rc<0) &&
263                         (h_errno==NETDB_INTERNAL) &&
264                         (errno==ERANGE))
265                 {
266                         buflen*=2;
267                         continue;
268                 }
269 #endif
270                 break;
271         }
272         if (hp) {
273                 strncpy( name, hp->h_name, namelen );
274         } else {
275                 *err = hp_strerror( h_errno );
276         }
277         LDAP_FREE(buf);
278 #else /* HAVE_GETHOSTBYADDR_R */
279
280 #if defined( LDAP_R_COMPILE )
281         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
282 #endif
283         hp = gethostbyaddr( addr, alen, sa->sa_family );
284         if (hp) {
285                 strncpy( name, hp->h_name, namelen );
286                 rc = 0;
287         } else {
288                 rc = h_errno;
289                 *err = hp_strerror( h_errno );
290         }
291 #if defined( LDAP_R_COMPILE )
292         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
293 #endif
294
295 #endif  /* !HAVE_GETHOSTBYADDR_R */
296         return rc;
297 #endif  /* !HAVE_GETNAMEINFO */
298 }
299
300 int ldap_pvt_gethostbyaddr_a(
301         const char *addr,
302         int len,
303         int type,
304         struct hostent *resbuf,
305         char **buf,
306         struct hostent **result,
307         int *herrno_ptr )
308 {
309 #if defined( HAVE_GETHOSTBYADDR_R )
310
311 # undef NEED_SAFE_REALLOC
312 # define NEED_SAFE_REALLOC   
313         int r=-1;
314         int buflen=BUFSTART;
315         *buf = NULL;   
316         for(;buflen<BUFMAX;) {
317                 if (safe_realloc( buf, buflen )==NULL)
318                         return r;
319 #if (GETHOSTBYADDR_R_NARGS < 8)
320                 *result=gethostbyaddr_r( addr, len, type,
321                         resbuf, *buf, buflen, herrno_ptr );
322                 r = (*result == NULL) ? -1 : 0;
323 #else
324                 r = gethostbyaddr_r( addr, len, type,
325                         resbuf, *buf, buflen, 
326                         result, herrno_ptr );
327 #endif
328
329 #ifdef NETDB_INTERNAL
330                 if ((r<0) &&
331                         (*herrno_ptr==NETDB_INTERNAL) &&
332                         (errno==ERANGE))
333                 {
334                         buflen*=2;
335                         continue;
336                 }
337 #endif
338                 return r;
339         }
340         return -1;
341 #elif defined( LDAP_R_COMPILE )
342 # undef NEED_COPY_HOSTENT
343 # define NEED_COPY_HOSTENT   
344         struct hostent *he;
345         int     retval;
346         *buf = NULL;   
347         
348         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
349         
350         he = gethostbyaddr( addr, len, type );
351         
352         if (he==NULL) {
353                 *herrno_ptr = h_errno;
354                 retval = -1;
355         } else if (copy_hostent( resbuf, buf, he )<0) {
356                 *herrno_ptr = -1;
357                 retval = -1;
358         } else {
359                 *result = resbuf;
360                 retval = 0;
361         }
362         
363         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
364         
365         return retval;
366
367 #else /* gethostbyaddr() */
368         *buf = NULL;   
369         *result = gethostbyaddr( addr, len, type );
370
371         if (*result!=NULL) {
372                 return 0;
373         }
374         return -1;
375 #endif  
376 }
377 /* 
378  * ldap_int_utils_init() should be called before any other function.
379  */
380
381 void ldap_int_utils_init( void )
382 {
383         static int done=0;
384         if (done)
385           return;
386         done=1;
387
388 #ifdef LDAP_R_COMPILE
389 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
390         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
391 #endif
392         ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
393 #endif
394
395         /* call other module init functions here... */
396 }
397
398 #if defined( NEED_COPY_HOSTENT )
399 # undef NEED_SAFE_REALLOC
400 #define NEED_SAFE_REALLOC
401
402 static char *cpy_aliases(
403         char ***tgtio,
404         char *buf,
405         char **src )
406 {
407         int len;
408         char **tgt=*tgtio;
409         for( ; (*src) ; src++ ) {
410                 len = strlen( *src ) + 1;
411                 AC_MEMCPY( buf, *src, len );
412                 *tgt++=buf;
413                 buf+=len;
414         }
415         *tgtio=tgt;   
416         return buf;
417 }
418
419 static char *cpy_addresses(
420         char ***tgtio,
421         char *buf,
422         char **src,
423         int len )
424 {
425         char **tgt=*tgtio;
426         for( ; (*src) ; src++ ) {
427                 AC_MEMCPY( buf, *src, len );
428                 *tgt++=buf;
429                 buf+=len;
430         }
431         *tgtio=tgt;      
432         return buf;
433 }
434
435 static int copy_hostent(
436         struct hostent *res,
437         char **buf,
438         struct hostent * src )
439 {
440         char    **p;
441         char    **tp;
442         char    *tbuf;
443         int     name_len;
444         int     n_alias=0;
445         int     total_alias_len=0;
446         int     n_addr=0;
447         int     total_addr_len;
448         int     total_len;
449           
450         /* calculate the size needed for the buffer */
451         name_len = strlen( src->h_name ) + 1;
452         
453         if( src->h_aliases != NULL ) {
454                 for( p = src->h_aliases; (*p) != NULL; p++ ) {
455                         total_alias_len += strlen( *p ) + 1;
456                         n_alias++; 
457                 }
458         }
459
460         if( src->h_addr_list != NULL ) {
461                 for( p = src->h_addr_list; (*p) != NULL; p++ ) {
462                         n_addr++;
463                 }
464                 total_addr_len = n_addr * src->h_length;
465         }
466         
467         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
468                 total_addr_len + total_alias_len + name_len;
469         
470         if (safe_realloc( buf, total_len )) {                    
471                 tp = (char **) *buf;
472                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
473                 AC_MEMCPY( res, src, sizeof( struct hostent ) );
474                 /* first the name... */
475                 AC_MEMCPY( tbuf, src->h_name, name_len );
476                 res->h_name = tbuf; tbuf+=name_len;
477                 /* now the aliases */
478                 res->h_aliases = tp;
479                 if ( src->h_aliases != NULL ) {
480                         tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
481                 }
482                 *tp++=NULL;
483                 /* finally the addresses */
484                 res->h_addr_list = tp;
485                 if ( src->h_addr_list != NULL ) {
486                         tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
487                 }
488                 *tp++=NULL;
489                 return 0;
490         }
491         return -1;
492 }
493 #endif
494
495 #if defined( NEED_SAFE_REALLOC )
496 static char *safe_realloc( char **buf, int len )
497 {
498         char *tmpbuf;
499         tmpbuf = LDAP_REALLOC( *buf, len );
500         if (tmpbuf) {
501                 *buf=tmpbuf;
502         } 
503         return tmpbuf;
504 }
505 #endif
506
507 char * ldap_pvt_get_fqdn( char *name )
508 {
509         char *fqdn, *ha_buf;
510         char hostbuf[MAXHOSTNAMELEN+1];
511         struct hostent *hp, he_buf;
512         int rc, local_h_errno;
513
514         if( name == NULL ) {
515                 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
516                         hostbuf[MAXHOSTNAMELEN] = '\0';
517                         name = hostbuf;
518                 } else {
519                         name = "localhost";
520                 }
521         }
522
523         rc = ldap_pvt_gethostbyname_a( name,
524                 &he_buf, &ha_buf, &hp, &local_h_errno );
525
526         if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
527                 fqdn = LDAP_STRDUP( name );
528         } else {
529                 fqdn = LDAP_STRDUP( hp->h_name );
530         }
531
532         LDAP_FREE( ha_buf );
533         return fqdn;
534 }
535
536 #if defined( HAVE_GETADDRINFO ) && !defined( HAVE_GAI_STRERROR )
537 char *ldap_pvt_gai_strerror (int code) {
538         static struct {
539                 int code;
540                 const char *msg;
541         } values[] = {
542 #ifdef EAI_ADDRFAMILY
543                 { EAI_ADDRFAMILY, "Address family for hostname not supported" },
544 #endif
545                 { EAI_AGAIN, "Temporary failure in name resolution" },
546                 { EAI_BADFLAGS, "Bad value for ai_flags" },
547                 { EAI_FAIL, "Non-recoverable failure in name resolution" },
548                 { EAI_FAMILY, "ai_family not supported" },
549                 { EAI_MEMORY, "Memory allocation failure" },
550 #ifdef EAI_NODATA
551                 { EAI_NODATA, "No address associated with hostname" },
552 #endif    
553                 { EAI_NONAME, "Name or service not known" },
554                 { EAI_SERVICE, "Servname not supported for ai_socktype" },
555                 { EAI_SOCKTYPE, "ai_socktype not supported" },
556                 { EAI_SYSTEM, "System error" },
557                 { 0, NULL }
558         };
559
560         int i;
561
562         for ( i = 0; values[i].msg != NULL; i++ ) {
563                 if ( values[i].code == code ) {
564                         return (char *) values[i].msg;
565                 }
566         }
567         
568         return "Unknown error";
569 }
570 #endif