]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
4254c5f7337dede5006fe255ff21a45146756cab
[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 h_errno
37 /* newer systems declare this in <netdb.h> for you, older ones don't.
38  * harmless to declare it again (unless defined by a macro).
39  */
40 extern int h_errno;
41 #endif
42
43 #ifndef LDAP_R_COMPILE
44 # undef HAVE_REENTRANT_FUNCTIONS
45 # undef HAVE_CTIME_R
46 # undef HAVE_GETHOSTBYNAME_R
47 # undef HAVE_GETHOSTBYADDR_R
48
49 #else
50 # include <ldap_pvt_thread.h>
51   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
52
53 #if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
54         && defined( CTIME_R_NARGS )
55 # define USE_CTIME_R
56 # else
57         static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
58 # endif
59
60 # if defined(HAVE_GETHOSTBYNAME_R) && \
61         (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
62         /* Don't know how to handle this version, pretend it's not there */
63 #       undef HAVE_GETHOSTBYNAME_R
64 # endif
65 # if defined(HAVE_GETHOSTBYADDR_R) && \
66         (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
67         /* Don't know how to handle this version, pretend it's not there */
68 #       undef HAVE_GETHOSTBYADDR_R
69 # endif
70 #endif /* LDAP_R_COMPILE */
71
72 char *ldap_pvt_ctime( const time_t *tp, char *buf )
73 {
74 #ifdef USE_CTIME_R
75 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
76 #       error "CTIME_R_NARGS should be 2 or 3"
77 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
78         return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
79 # elif CTIME_R_NARGS > 2
80         return ctime_r(tp,buf,26);
81 # else
82         return ctime_r(tp,buf);
83 # endif   
84
85 #else
86
87 # ifdef LDAP_R_COMPILE
88         ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
89 # endif
90
91         AC_MEMCPY( buf, ctime(tp), 26 );
92
93 # ifdef LDAP_R_COMPILE
94         ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
95 # endif
96
97         return buf;
98 #endif  
99 }
100
101 #define BUFSTART (1024-32)
102 #define BUFMAX (32*1024-32)
103
104 static char *safe_realloc( char **buf, int len );
105
106 #if !defined(HAVE_GETHOSTBYNAME_R) && defined(LDAP_R_COMPILE)
107 static int copy_hostent( struct hostent *res,
108         char **buf, struct hostent * src );
109 #endif
110
111 int ldap_pvt_gethostbyname_a(
112         const char *name, 
113         struct hostent *resbuf,
114         char **buf,
115         struct hostent **result,
116         int *herrno_ptr )
117 {
118 #if defined( HAVE_GETHOSTBYNAME_R )
119
120 # define NEED_SAFE_REALLOC 1   
121         int r=-1;
122         int buflen=BUFSTART;
123         *buf = NULL;
124         for(;buflen<BUFMAX;) {
125                 if (safe_realloc( buf, buflen )==NULL)
126                         return r;
127
128 #if (GETHOSTBYNAME_R_NARGS < 6)
129                 *result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
130                 r = (*result == NULL) ?  -1 : 0;
131 #else
132                 r = gethostbyname_r( name, resbuf, *buf,
133                         buflen, result, herrno_ptr );
134 #endif
135
136                 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
137                        name, r, 0 );
138
139 #ifdef NETDB_INTERNAL
140                 if ((r<0) &&
141                         (*herrno_ptr==NETDB_INTERNAL) &&
142                         (errno==ERANGE))
143                 {
144                         buflen*=2;
145                         continue;
146                 }
147 #endif
148                 return r;
149         }
150         return -1;
151 #elif defined( LDAP_R_COMPILE )
152 # define NEED_COPY_HOSTENT   
153         struct hostent *he;
154         int     retval;
155         *buf = NULL;
156         
157         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
158         
159         he = gethostbyname( name );
160         
161         if (he==NULL) {
162                 *herrno_ptr = h_errno;
163                 retval = -1;
164         } else if (copy_hostent( resbuf, buf, he )<0) {
165                 *herrno_ptr = -1;
166                 retval = -1;
167         } else {
168                 *result = resbuf;
169                 retval = 0;
170         }
171         
172         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
173         
174         return retval;
175 #else   
176         *buf = NULL;
177         *result = gethostbyname( name );
178
179         if (*result!=NULL) {
180                 return 0;
181         }
182
183         *herrno_ptr = h_errno;
184         
185         return -1;
186 #endif  
187 }
188
189 #ifndef GETNAMEINFO
190 static const char *
191 hp_strerror( int err )
192 {
193         switch (err) {
194         case HOST_NOT_FOUND:    return _("Host not found (authoritative)");
195         case TRY_AGAIN:                 return _("Host not found (server fail?)");
196         case NO_RECOVERY:               return _("Non-recoverable failure");
197         case NO_DATA:                   return _("No data of requested type");
198 #ifdef NETDB_INTERNAL
199         case NETDB_INTERNAL:    return STRERROR( errno );
200 #endif
201         }
202         return _("Unknown resolver error");
203 }
204 #endif
205
206 int ldap_pvt_get_hname(
207         const struct sockaddr *sa,
208         int len,
209         char *name,
210         int namelen,
211         char **err )
212 {
213         int rc;
214 #if defined( HAVE_GETNAMEINFO )
215
216 #if defined( LDAP_R_COMPILE )
217         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
218 #endif
219         rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
220 #if defined( LDAP_R_COMPILE )
221         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
222 #endif
223         if ( rc ) *err = AC_GAI_STRERROR( rc );
224         return rc;
225
226 #else /* !HAVE_GETNAMEINFO */
227         char *addr;
228         int alen;
229         struct hostent *hp = NULL;
230 #ifdef HAVE_GETHOSTBYADDR_R
231         struct hostent hb;
232         int buflen=BUFSTART, h_errno;
233         char *buf=NULL;
234 #endif
235
236 #ifdef LDAP_PF_INET6
237         if (sa->sa_family == AF_INET6) {
238                 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
239                 addr = (char *)&sin->sin6_addr;
240                 alen = sizeof(sin->sin6_addr);
241         } else
242 #endif
243         if (sa->sa_family == AF_INET) {
244                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
245                 addr = (char *)&sin->sin_addr;
246                 alen = sizeof(sin->sin_addr);
247         } else {
248                 rc = NO_RECOVERY;
249                 *err = (char *)hp_strerror( rc );
250                 return rc;
251         }
252 #if defined( HAVE_GETHOSTBYADDR_R )
253         for(;buflen<BUFMAX;) {
254                 if (safe_realloc( &buf, buflen )==NULL) {
255                         *err = (char *)STRERROR( ENOMEM );
256                         return ENOMEM;
257                 }
258 #if (GETHOSTBYADDR_R_NARGS < 8)
259                 hp=gethostbyaddr_r( addr, alen, sa->sa_family,
260                         &hb, buf, buflen, &h_errno );
261                 rc = (hp == NULL) ? -1 : 0;
262 #else
263                 rc = gethostbyaddr_r( addr, alen, sa->sa_family,
264                         &hb, buf, buflen, 
265                         &hp, &h_errno );
266 #endif
267 #ifdef NETDB_INTERNAL
268                 if ((rc<0) &&
269                         (h_errno==NETDB_INTERNAL) &&
270                         (errno==ERANGE))
271                 {
272                         buflen*=2;
273                         continue;
274                 }
275 #endif
276                 break;
277         }
278         if (hp) {
279                 strncpy( name, hp->h_name, namelen );
280         } else {
281                 *err = (char *)hp_strerror( h_errno );
282         }
283         LDAP_FREE(buf);
284 #else /* HAVE_GETHOSTBYADDR_R */
285
286 #if defined( LDAP_R_COMPILE )
287         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
288 #endif
289         hp = gethostbyaddr( addr, alen, sa->sa_family );
290         if (hp) {
291                 strncpy( name, hp->h_name, namelen );
292                 rc = 0;
293         } else {
294                 rc = h_errno;
295                 *err = (char *)hp_strerror( h_errno );
296         }
297 #if defined( LDAP_R_COMPILE )
298         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
299 #endif
300
301 #endif  /* !HAVE_GETHOSTBYADDR_R */
302         return rc;
303 #endif  /* !HAVE_GETNAMEINFO */
304 }
305
306 int ldap_pvt_gethostbyaddr_a(
307         const char *addr,
308         int len,
309         int type,
310         struct hostent *resbuf,
311         char **buf,
312         struct hostent **result,
313         int *herrno_ptr )
314 {
315 #if defined( HAVE_GETHOSTBYADDR_R )
316
317 # undef NEED_SAFE_REALLOC
318 # define NEED_SAFE_REALLOC   
319         int r=-1;
320         int buflen=BUFSTART;
321         *buf = NULL;   
322         for(;buflen<BUFMAX;) {
323                 if (safe_realloc( buf, buflen )==NULL)
324                         return r;
325 #if (GETHOSTBYADDR_R_NARGS < 8)
326                 *result=gethostbyaddr_r( addr, len, type,
327                         resbuf, *buf, buflen, herrno_ptr );
328                 r = (*result == NULL) ? -1 : 0;
329 #else
330                 r = gethostbyaddr_r( addr, len, type,
331                         resbuf, *buf, buflen, 
332                         result, herrno_ptr );
333 #endif
334
335 #ifdef NETDB_INTERNAL
336                 if ((r<0) &&
337                         (*herrno_ptr==NETDB_INTERNAL) &&
338                         (errno==ERANGE))
339                 {
340                         buflen*=2;
341                         continue;
342                 }
343 #endif
344                 return r;
345         }
346         return -1;
347 #elif defined( LDAP_R_COMPILE )
348 # undef NEED_COPY_HOSTENT
349 # define NEED_COPY_HOSTENT   
350         struct hostent *he;
351         int     retval;
352         *buf = NULL;   
353         
354         ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
355         
356         he = gethostbyaddr( addr, len, type );
357         
358         if (he==NULL) {
359                 *herrno_ptr = h_errno;
360                 retval = -1;
361         } else if (copy_hostent( resbuf, buf, he )<0) {
362                 *herrno_ptr = -1;
363                 retval = -1;
364         } else {
365                 *result = resbuf;
366                 retval = 0;
367         }
368         
369         ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
370         
371         return retval;
372
373 #else /* gethostbyaddr() */
374         *buf = NULL;   
375         *result = gethostbyaddr( addr, len, type );
376
377         if (*result!=NULL) {
378                 return 0;
379         }
380         return -1;
381 #endif  
382 }
383 /* 
384  * ldap_int_utils_init() should be called before any other function.
385  */
386
387 void ldap_int_utils_init( void )
388 {
389         static int done=0;
390         if (done)
391           return;
392         done=1;
393
394 #ifdef LDAP_R_COMPILE
395 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
396         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
397 #endif
398         ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
399 #endif
400
401         /* call other module init functions here... */
402 }
403
404 #if defined( NEED_COPY_HOSTENT )
405 # undef NEED_SAFE_REALLOC
406 #define NEED_SAFE_REALLOC
407
408 static char *cpy_aliases(
409         char ***tgtio,
410         char *buf,
411         char **src )
412 {
413         int len;
414         char **tgt=*tgtio;
415         for( ; (*src) ; src++ ) {
416                 len = strlen( *src ) + 1;
417                 AC_MEMCPY( buf, *src, len );
418                 *tgt++=buf;
419                 buf+=len;
420         }
421         *tgtio=tgt;   
422         return buf;
423 }
424
425 static char *cpy_addresses(
426         char ***tgtio,
427         char *buf,
428         char **src,
429         int len )
430 {
431         char **tgt=*tgtio;
432         for( ; (*src) ; src++ ) {
433                 AC_MEMCPY( buf, *src, len );
434                 *tgt++=buf;
435                 buf+=len;
436         }
437         *tgtio=tgt;      
438         return buf;
439 }
440
441 static int copy_hostent(
442         struct hostent *res,
443         char **buf,
444         struct hostent * src )
445 {
446         char    **p;
447         char    **tp;
448         char    *tbuf;
449         int     name_len;
450         int     n_alias=0;
451         int     total_alias_len=0;
452         int     n_addr=0;
453         int     total_addr_len;
454         int     total_len;
455           
456         /* calculate the size needed for the buffer */
457         name_len = strlen( src->h_name ) + 1;
458         
459         if( src->h_aliases != NULL ) {
460                 for( p = src->h_aliases; (*p) != NULL; p++ ) {
461                         total_alias_len += strlen( *p ) + 1;
462                         n_alias++; 
463                 }
464         }
465
466         if( src->h_addr_list != NULL ) {
467                 for( p = src->h_addr_list; (*p) != NULL; p++ ) {
468                         n_addr++;
469                 }
470                 total_addr_len = n_addr * src->h_length;
471         }
472         
473         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
474                 total_addr_len + total_alias_len + name_len;
475         
476         if (safe_realloc( buf, total_len )) {                    
477                 tp = (char **) *buf;
478                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
479                 AC_MEMCPY( res, src, sizeof( struct hostent ) );
480                 /* first the name... */
481                 AC_MEMCPY( tbuf, src->h_name, name_len );
482                 res->h_name = tbuf; tbuf+=name_len;
483                 /* now the aliases */
484                 res->h_aliases = tp;
485                 if ( src->h_aliases != NULL ) {
486                         tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
487                 }
488                 *tp++=NULL;
489                 /* finally the addresses */
490                 res->h_addr_list = tp;
491                 if ( src->h_addr_list != NULL ) {
492                         tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
493                 }
494                 *tp++=NULL;
495                 return 0;
496         }
497         return -1;
498 }
499 #endif
500
501 #if defined( NEED_SAFE_REALLOC )
502 static char *safe_realloc( char **buf, int len )
503 {
504         char *tmpbuf;
505         tmpbuf = LDAP_REALLOC( *buf, len );
506         if (tmpbuf) {
507                 *buf=tmpbuf;
508         } 
509         return tmpbuf;
510 }
511 #endif
512
513 char * ldap_pvt_get_fqdn( char *name )
514 {
515         char *fqdn, *ha_buf;
516         char hostbuf[MAXHOSTNAMELEN+1];
517         struct hostent *hp, he_buf;
518         int rc, local_h_errno;
519
520         if( name == NULL ) {
521                 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
522                         hostbuf[MAXHOSTNAMELEN] = '\0';
523                         name = hostbuf;
524                 } else {
525                         name = "localhost";
526                 }
527         }
528
529         rc = ldap_pvt_gethostbyname_a( name,
530                 &he_buf, &ha_buf, &hp, &local_h_errno );
531
532         if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
533                 fqdn = LDAP_STRDUP( name );
534         } else {
535                 fqdn = LDAP_STRDUP( hp->h_name );
536         }
537
538         LDAP_FREE( ha_buf );
539         return fqdn;
540 }
541
542 #if defined( HAVE_GETADDRINFO ) && !defined( HAVE_GAI_STRERROR )
543 char *ldap_pvt_gai_strerror (int code) {
544         static struct {
545                 int code;
546                 const char *msg;
547         } values[] = {
548 #ifdef EAI_ADDRFAMILY
549                 { EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
550 #endif
551                 { EAI_AGAIN, N_("Temporary failure in name resolution") },
552                 { EAI_BADFLAGS, N_("Bad value for ai_flags") },
553                 { EAI_FAIL, N_("Non-recoverable failure in name resolution") },
554                 { EAI_FAMILY, N_("ai_family not supported") },
555                 { EAI_MEMORY, N_("Memory allocation failure") },
556 #ifdef EAI_NODATA
557                 { EAI_NODATA, N_("No address associated with hostname") },
558 #endif    
559                 { EAI_NONAME, N_("Name or service not known") },
560                 { EAI_SERVICE, N_("Servname not supported for ai_socktype") },
561                 { EAI_SOCKTYPE, N_("ai_socktype not supported") },
562                 { EAI_SYSTEM, N_("System error") },
563                 { 0, NULL }
564         };
565
566         int i;
567
568         for ( i = 0; values[i].msg != NULL; i++ ) {
569                 if ( values[i].code == code ) {
570                         return (char *) _(values[i].msg);
571                 }
572         }
573         
574         return _("Unknown error");
575 }
576 #endif