]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
eb0517d9bf508c9d550e56bc86c3e030c2411d70
[openldap] / libraries / libldap / util-int.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /*
6  * util-int.c   Various functions to replace missing threadsafe ones.
7  *                                Without the real *_r funcs, things will
8  *                                work, but might not be threadsafe. 
9  * 
10  * Written by Bart Hartgers.
11  *
12  * Copyright 1998, A. Hartgers, All rights reserved.
13  * This software is not subject to any license of Eindhoven University of
14  * Technology, since it was written in my spare time.
15  *                      
16  * Redistribution and use in source and binary forms are permitted only
17  * as authorized by the OpenLDAP Public License.  A copy of this
18  * license is available at http://www.OpenLDAP.org/license.html or
19  * in file LICENSE in the top-level directory of the distribution.
20  */ 
21
22
23 #include "portable.h"
24
25 #include <stdlib.h>
26
27 #include <ac/errno.h>
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31
32 #include "ldap-int.h"
33
34 #if defined( LDAP_R_COMPILE )
35 # include <ldap_pvt_thread.h>
36 #else
37 # undef HAVE_REENTRANT_FUNCTIONS
38 #endif
39
40 #if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
41         && defined( CTIME_R_NARGS )
42 #       define USE_CTIME_R
43 #endif
44
45 #if defined(HAVE_GETHOSTBYNAME_R) && \
46     (GETHOSTBYNAME_R_NARGS > 6 || GETHOSTBYNAME_R_NARGS < 5)
47         /* Don't know how to handle this version, pretend it's not there */
48 #       undef HAVE_GETHOSTBYNAME_R
49 #endif
50 #if defined(HAVE_GETHOSTBYADDR_R) && \
51     (GETHOSTBYADDR_R_NARGS > 8 || GETHOSTBYADDR_R_NARGS < 7)
52         /* Don't know how to handle this version, pretend it's not there */
53 #       undef HAVE_GETHOSTBYADDR_R
54 #endif
55
56 #ifdef LDAP_R_COMPILE
57 # ifndef USE_CTIME_R
58         static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
59 # endif
60 # ifndef HAVE_GETHOSTBYNAME_R
61         static ldap_pvt_thread_mutex_t ldap_int_gethostbyname_mutex;
62 # endif
63 # ifndef HAVE_GETHOSTBYADDR_R
64         static ldap_pvt_thread_mutex_t ldap_int_gethostbyaddr_mutex;
65 # endif
66 #endif /* LDAP_R_COMPILE */
67
68 char *ldap_pvt_ctime( const time_t *tp, char *buf )
69 {
70 #ifdef USE_CTIME_R
71 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
72         choke me!  nargs should have 2 or 3
73 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
74         return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
75 # elif CTIME_R_NARGS > 2
76         return ctime_r(tp,buf,26);
77 # else
78         return ctime_r(tp,buf);
79 # endif   
80
81 #else
82 # ifdef LDAP_R_COMPILE
83         ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
84 # endif
85         memcpy( buf, ctime(tp), 26 );
86 # ifdef LDAP_R_COMPILE
87         ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
88 # endif
89         return buf;
90 #endif  
91 }
92
93 #define BUFSTART 1024
94 #define BUFMAX (32*1024)
95
96 static char *safe_realloc( char **buf, int len );
97 static int copy_hostent( struct hostent *res, char **buf, struct hostent * src );
98
99 int ldap_pvt_gethostbyname_a(
100         const char *name, 
101         struct hostent *resbuf,
102         char **buf,
103         struct hostent **result,
104         int *herrno_ptr )
105 {
106 #if defined( HAVE_GETHOSTBYNAME_R )
107
108 # define NEED_SAFE_REALLOC 1   
109         int r=-1;
110         int buflen=BUFSTART;
111         *buf = NULL;
112         for(;buflen<BUFMAX;) {
113                 if (safe_realloc( buf, buflen )==NULL)
114                         return r;
115
116 #if (GETHOSTBYNAME_R_NARGS < 6)
117                 r = ((*result=gethostbyname_r( name, resbuf, *buf,\
118                                                buflen, herrno_ptr ))== NULL) ?\
119                     -1 : 0;
120 #else
121                 r = gethostbyname_r( name, resbuf, *buf,
122                         buflen, result, herrno_ptr );
123 #endif
124
125                 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",\
126                        name, r, 0 );
127
128 #ifdef NETDB_INTERNAL
129                 if ((r<0) &&
130                         (*herrno_ptr==NETDB_INTERNAL) &&
131                         (errno==ERANGE))
132                 {
133                         buflen*=2;
134                         continue;
135                 }
136 #endif
137                 return r;
138         }
139         return -1;
140 #elif defined( LDAP_R_COMPILE )
141 # define NEED_COPY_HOSTENT   
142         struct hostent *he;
143         int     retval;
144         
145         ldap_pvt_thread_mutex_lock( &ldap_int_gethostbyname_mutex );
146         
147         he = gethostbyname( name );
148         
149         if (he==NULL) {
150                 *herrno_ptr = h_errno;
151                 retval = -1;
152         } else if (copy_hostent( resbuf, buf, he )<0) {
153                 *herrno_ptr = -1;
154                 retval = -1;
155         } else {
156                 *result = resbuf;
157                 retval = 0;
158         }
159         
160         ldap_pvt_thread_mutex_unlock( &ldap_int_gethostbyname_mutex );
161         
162         return retval;
163 #else   
164         *result = gethostbyname( name );
165
166         if (*result!=NULL) {
167                 return 0;
168         }
169
170         *herrno_ptr = h_errno;
171         
172         return -1;
173 #endif  
174 }
175          
176 int ldap_pvt_gethostbyaddr_a(
177         const char *addr,
178         int len,
179         int type,
180         struct hostent *resbuf,
181         char **buf,
182         struct hostent **result,
183         int *herrno_ptr )
184 {
185 #if defined( HAVE_GETHOSTBYADDR_R )
186
187 # undef NEED_SAFE_REALLOC
188 # define NEED_SAFE_REALLOC   
189         int r=-1;
190         int buflen=BUFSTART;
191         *buf = NULL;   
192         for(;buflen<BUFMAX;) {
193                 if (safe_realloc( buf, buflen )==NULL)
194                         return r;
195 #if (GETHOSTBYADDR_R_NARGS < 8)
196                 r = ((*result=gethostbyaddr_r( addr, len, type,
197                                                resbuf, *buf, buflen, 
198                                                herrno_ptr )) == NULL) ?\
199                     -1 : 0;
200 #else
201                 r = gethostbyaddr_r( addr, len, type,
202                         resbuf, *buf, buflen, 
203                         result, herrno_ptr );
204 #endif
205
206 #ifdef NETDB_INTERNAL
207                 if ((r<0) &&
208                         (*herrno_ptr==NETDB_INTERNAL) &&
209                         (errno==ERANGE))
210                 {
211                         buflen*=2;
212                         continue;
213                 }
214 #endif
215                 return r;
216         }
217         return -1;
218 #elif defined( LDAP_R_COMPILE )
219 # undef NEED_COPY_HOSTENT
220 # define NEED_COPY_HOSTENT   
221         struct hostent *he;
222         int     retval;
223         
224         ldap_pvt_thread_mutex_lock( &ldap_int_gethostbyaddr_mutex );
225         
226         he = gethostbyaddr( addr, len, type );
227         
228         if (he==NULL) {
229                 *herrno_ptr = h_errno;
230                 retval = -1;
231         } else if (copy_hostent( resbuf, buf, he )<0) {
232                 *herrno_ptr = -1;
233                 retval = -1;
234         } else {
235                 *result = resbuf;
236                 retval = 0;
237         }
238         
239         ldap_pvt_thread_mutex_unlock( &ldap_int_gethostbyaddr_mutex );
240         
241         return retval;   
242 #else /* gethostbyaddr() */
243         *result = gethostbyaddr( addr, len, type );
244
245         if (*result!=NULL) {
246                 return 0;
247         }
248         return -1;
249 #endif  
250 }
251 /* 
252  * ldap_pvt_init_utils() should be called before any other function.
253  */
254
255 void ldap_pvt_init_utils( void )
256 {
257         static int done=0;
258         if (done)
259           return;
260         done=1;
261
262 #ifdef LDAP_R_COMPILE
263
264 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
265         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
266 #endif
267
268 #if !defined( HAVE_GETHOSTBYNAME_R )
269         ldap_pvt_thread_mutex_init( &ldap_int_gethostbyname_mutex );
270 #endif
271
272 #if !defined( HAVE_GETHOSTBYADDR_R )
273         ldap_pvt_thread_mutex_init( &ldap_int_gethostbyaddr_mutex );
274 #endif
275
276         /* call other module init functions here... */
277 #endif
278 }
279
280 #if defined( NEED_COPY_HOSTENT )
281 # undef NEED_SAFE_REALLOC
282 #define NEED_SAFE_REALLOC
283
284 static char *cpy_aliases( char ***tgtio, char *buf, char **src )
285 {
286         int len;
287         char **tgt=*tgtio;
288         for( ; (*src) ; src++ ) {
289                 len = strlen( *src ) + 1;
290                 memcpy( buf, *src, len );
291                 *tgt++=buf;
292                 buf+=len;
293         }
294         *tgtio=tgt;   
295         return buf;
296 }
297
298 static char *cpy_addresses( char ***tgtio, char *buf, char **src, int len )
299 {
300         char **tgt=*tgtio;
301         for( ; (*src) ; src++ ) {
302                 memcpy( buf, *src, len );
303                 *tgt++=buf;
304                 buf+=len;
305         }
306         *tgtio=tgt;      
307         return buf;
308 }
309
310 static int copy_hostent( struct hostent *res, char **buf, struct hostent * src )
311 {
312         char    **p;
313         char    **tp;
314         char    *tbuf;
315         int     name_len;
316         int     n_alias;
317         int     total_alias_len;
318         int     n_addr;
319         int     total_addr_len;
320         int     total_len;
321           
322         /* calculate the size needed for the buffer */
323         name_len = strlen( src->h_name ) + 1;
324         
325         for( n_alias=total_alias_len=0, p=src->h_aliases; (*p) ; p++ ) {
326                 total_alias_len += strlen( *p ) + 1;
327                 n_alias++; 
328         }
329
330         for( n_addr=0, p=src->h_addr_list; (*p) ; p++ ) {
331                 n_addr++;
332         }
333         total_addr_len = n_addr * src->h_length;
334         
335         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
336                 total_addr_len + total_alias_len + name_len;
337         
338         if (safe_realloc( buf, total_len )) {                    
339                 tp = (char **) *buf;
340                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
341                 memcpy( res, src, sizeof( struct hostent ) );
342                 /* first the name... */
343                 memcpy( tbuf, src->h_name, name_len );
344                 res->h_name = tbuf; tbuf+=name_len;
345                 /* now the aliases */
346                 res->h_aliases = tp;
347                 tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
348                 *tp++=NULL;
349                 /* finally the addresses */
350                 res->h_addr_list = tp;
351                 tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
352                 *tp++=NULL;
353                 return 0;
354         }
355         return -1;
356 }
357 #endif
358
359 #if defined( NEED_SAFE_REALLOC )
360 static char *safe_realloc( char **buf, int len )
361 {
362         char *tmpbuf;
363         tmpbuf = realloc( *buf, len );
364         if (tmpbuf) {
365                 *buf=tmpbuf;
366         } 
367         return tmpbuf;
368 }
369 #endif
370
371