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