]> git.sur5r.net Git - openldap/blob - libraries/libldap/util-int.c
e2b36c5f12d9d8e469bd051bb8d3a529fcd46ef1
[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 work, but won't be
8  *                                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 #include "portable.h"
23
24 #include <stdlib.h>
25
26 #include <ac/errno.h>
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30
31 #include "ldap-int.h"
32
33 #if defined( LDAP_R_COMPILE )
34 # include <ldap_pvt_thread.h>
35 # if !defined( HAVE_REENTRANT_FUNCTIONS )
36 #  if !defined( HAVE_CTIME_R )
37 #   define LDAP_INT_CTIME_MUTEX 1
38 #  endif
39 #  if !defined( HAVE_GETHOSTBYNAME_R )
40 #   define LDAP_INT_GETHOSTBYNAME_MUTEX 1
41 #  endif
42 #  if !defined( HAVE_GETHOSTBYADDR_R )
43 #   define LDAP_INT_GETHOSTBYADDR_MUTEX 1
44 #  endif
45 # endif /* defined( HAVE_REENTRANT_FUNCTIONS ) */
46
47 #if defined( LDAP_INT_CTIME_MUTEX )
48 static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
49 #endif
50 #if defined( LDAP_INT_GETHOSTBYNAME_MUTEX )
51 static ldap_pvt_thread_mutex_t ldap_int_gethostbyname_mutex;
52 #endif
53 #if defined( LDAP_INT_GETHOSTBYADDR_MUTEX )
54 static ldap_pvt_thread_mutex_t ldap_int_gethostbyaddr_mutex;
55 #endif
56 #else /* LDAP_R_COMPILE */
57 #undef HAVE_REENTRANT_FUNCTIONS
58 #endif
59
60 #if defined ( HAVE_STRSPN )
61 #define int_strspn strspn
62 #else
63 static int int_strspn( const char *str, const char *delim )
64 {
65         int pos;
66         const char *p=delim;
67         for( pos=0; (*str) ; pos++,str++) {
68                 if (*str!=*p)
69                         for( p=delim; (*p) ; p++ ) {
70                                 if (*str==*p)
71                                         break;
72                         }
73                 if (*p=='\0')
74                         return pos;
75         }
76         return pos;
77 }
78 #endif
79
80 #if defined( HAVE_STRPBRK )
81 #define int_strpbrk strpbrk
82 #else
83 static char *int_strpbrk( const char *str, const char *accept )
84 {
85         const char *p;
86         for( ; (*str) ; str++ ) {
87                 for( p=accept; (*p) ; p++) {
88                         if (*str==*p)
89                                 return str;
90                 }
91         }
92         return NULL;
93 }
94 #endif
95
96 char *ldap_pvt_strtok( char *str, const char *delim, char **pos )
97 {
98 #if defined( HAVE_STRTOK_R ) || defined( HAVE_REENTRANT_FUNCTIONS )
99         return strtok_r(str, delim, pos);
100 #else
101         char *p;
102
103         if (pos==NULL)
104                 return NULL;
105         if (str==NULL) {
106                 if (*pos==NULL)
107                         return NULL;
108                 str=*pos;
109         }
110         /* skip any initial delimiters */
111         str += int_strspn( str, delim );
112         if (*str == '\0')
113                 return NULL;
114         p = int_strpbrk( str, delim );
115         if (p==NULL) {
116                 *pos = NULL;
117         } else {
118                 *p ='\0';
119                 *pos = p+1;
120         }
121         return str;
122 #endif
123 }
124
125 char *ldap_pvt_ctime( const time_t *tp, char *buf )
126 {
127 #if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
128         && defined( CTIME_R_NARGS )
129 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
130         choke me!  nargs should have 2 or 3
131 # elif CTIME_R_NARGS > 2
132         return ctime_r(tp,buf,26);
133 # else
134         return ctime_r(tp,buf);
135 # endif   
136 #else
137 # if defined( LDAP_INT_CTIME_MUTEX )
138         ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
139 # endif 
140         memcpy( buf, ctime(tp), 26 );
141 # if defined( LDAP_INT_CTIME_MUTEX )
142         ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
143 # endif 
144         return buf;
145 #endif  
146 }
147
148 #define BUFSTART 1024
149 #define BUFMAX (32*1024)
150
151 static char *safe_realloc( char **buf, int len );
152 static int copy_hostent( struct hostent *res, char **buf, struct hostent * src );
153
154 int ldap_pvt_gethostbyname_a(
155         const char *name, 
156         struct hostent *resbuf,
157         char **buf,
158         struct hostent **result,
159         int *herrno_ptr )
160 {
161 #if defined( HAVE_GETHOSTBYNAME_R ) || defined( HAVE_REENTRANT_FUNCTIONS )
162 # define NEED_SAFE_REALLOC 1   
163         int r=-1;
164         int buflen=BUFSTART;
165         *buf = NULL;
166         for(;buflen<BUFMAX;) {
167                 if (safe_realloc( buf, buflen )==NULL)
168                         return r;
169                 r = gethostbyname_r( name, resbuf, *buf,
170                         buflen, result, herrno_ptr );
171 #ifdef NETDB_INTERNAL
172                 if ((r<0) &&
173                         (*herrno_ptr==NETDB_INTERNAL) &&
174                         (errno==ERANGE))
175                 {
176                         buflen*=2;
177                         continue;
178                 }
179 #endif
180                 return r;
181         }
182         return -1;
183 #elif defined( LDAP_INT_GETHOSTBYNAME_MUTEX )
184 # define NEED_COPY_HOSTENT   
185         struct hostent *he;
186         int     retval;
187         
188         ldap_pvt_thread_mutex_lock( &ldap_int_gethostbyname_mutex );
189         
190         he = gethostbyname( name );
191         
192         if (he==NULL) {
193                 *herrno_ptr = h_errno;
194                 retval = -1;
195         } else if (copy_hostent( resbuf, buf, he )<0) {
196                 *herrno_ptr = -1;
197                 retval = -1;
198         } else {
199                 *result = resbuf;
200                 retval = 0;
201         }
202         
203         ldap_pvt_thread_mutex_unlock( &ldap_int_gethostbyname_mutex );
204         
205         return retval;
206 #else   
207         *result = gethostbyname( name );
208
209         if (*result!=NULL) {
210                 return 0;
211         }
212
213         *herrno_ptr = h_errno;
214         
215         return -1;
216 #endif  
217 }
218          
219 int ldap_pvt_gethostbyaddr_a(
220         const char *addr,
221         int len,
222         int type,
223         struct hostent *resbuf,
224         char **buf,
225         struct hostent **result,
226         int *herrno_ptr )
227 {
228 #if defined( HAVE_GETHOSTBYADDR_R ) || defined( HAVE_REENTRANT_FUNCTIONS )
229 # undef NEED_SAFE_REALLOC
230 # define NEED_SAFE_REALLOC   
231         int r=-1;
232         int buflen=BUFSTART;
233         *buf = NULL;   
234         for(;buflen<BUFMAX;) {
235                 if (safe_realloc( buf, buflen )==NULL)
236                         return r;
237                 r = gethostbyaddr_r( addr, len, type,
238                         resbuf, *buf, buflen, 
239                         result, herrno_ptr );
240 #ifdef NETDB_INTERNAL
241                 if ((r<0) &&
242                         (*herrno_ptr==NETDB_INTERNAL) &&
243                         (errno==ERANGE))
244                 {
245                         buflen*=2;
246                         continue;
247                 }
248 #endif
249                 return r;
250         }
251         return -1;
252 #elif defined( LDAP_INT_GETHOSTBYADDR_MUTEX )
253 # undef NEED_COPY_HOSTENT
254 # define NEED_COPY_HOSTENT   
255         struct hostent *he;
256         int     retval;
257         
258         ldap_pvt_thread_mutex_lock( &ldap_int_gethostbyaddr_mutex );
259         
260         he = gethostbyaddr( addr, len, type );
261         
262         if (he==NULL) {
263                 *herrno_ptr = h_errno;
264                 retval = -1;
265         } else if (copy_hostent( resbuf, buf, he )<0) {
266                 *herrno_ptr = -1;
267                 retval = -1;
268         } else {
269                 *result = resbuf;
270                 retval = 0;
271         }
272         
273         ldap_pvt_thread_mutex_unlock( &ldap_int_gethostbyaddr_mutex );
274         
275         return retval;   
276 #else /* gethostbyaddr() */
277         *result = gethostbyaddr( addr, len, type );
278
279         if (*result!=NULL) {
280                 return 0;
281         }
282         return -1;
283 #endif  
284 }
285 /* 
286  * ldap_pvt_init_utils() should be called before any other function.
287  */
288
289 void ldap_pvt_init_utils( void )
290 {
291         static int done=0;
292         if (done)
293           return;
294         done=1;
295 #if defined( LDAP_INT_CTIME_MUTEX )
296         ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex, NULL );
297 #endif  
298 #if defined( LDAP_INT_GETHOSTBYNAME_MUTEX )
299         ldap_pvt_thread_mutex_init( &ldap_int_gethostbyname_mutex, NULL );
300 #endif
301 #if defined( LDAP_INT_GETHOSTBYADDR_MUTEX )
302         ldap_pvt_thread_mutex_init( &ldap_int_gethostbyaddr_mutex, NULL );
303 #endif
304 #if defined( LDAP_R_COMPILE )
305         /* call other module init functions here... */
306 #endif  
307 }
308
309 #if defined( NEED_COPY_HOSTENT )
310 # undef NEED_SAFE_REALLOC
311 #define NEED_SAFE_REALLOC
312
313 static char *cpy_aliases( char ***tgtio, char *buf, char **src )
314 {
315         int len;
316         char **tgt=*tgtio;
317         for( ; (*src) ; src++ ) {
318                 len = strlen( *src ) + 1;
319                 memcpy( buf, *src, len );
320                 *tgt++=buf;
321                 buf+=len;
322         }
323         *tgtio=tgt;   
324         return buf;
325 }
326
327 static char *cpy_addresses( char ***tgtio, char *buf, char **src, int len )
328 {
329         char **tgt=*tgtio;
330         for( ; (*src) ; src++ ) {
331                 memcpy( buf, *src, len );
332                 *tgt++=buf;
333                 buf+=len;
334         }
335         *tgtio=tgt;      
336         return buf;
337 }
338
339 static int copy_hostent( struct hostent *res, char **buf, struct hostent * src )
340 {
341         char    **p;
342         char    **tp;
343         char    *tbuf;
344         int     name_len;
345         int     n_alias;
346         int     total_alias_len;
347         int     n_addr;
348         int     total_addr_len;
349         int     total_len;
350           
351         /* calculate the size needed for the buffer */
352         name_len = strlen( src->h_name ) + 1;
353         
354         for( n_alias=total_alias_len=0, p=src->h_aliases; (*p) ; p++ ) {
355                 total_alias_len += strlen( *p ) + 1;
356                 n_alias++;
357         }
358
359         for( n_addr=0, p=src->h_addr_list; (*p) ; p++ ) {
360                 n_addr++;
361         }
362         total_addr_len = n_addr * src->h_length;
363         
364         total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
365                 total_addr_len + total_alias_len + name_len;
366         
367         if (safe_realloc( buf, total_len )) {                    
368                 tp = (char **) *buf;
369                 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
370                 memcpy( res, src, sizeof( struct hostent ) );
371                 /* first the name... */
372                 memcpy( tbuf, src->h_name, name_len );
373                 res->h_name = tbuf; tbuf+=name_len;
374                 /* now the aliases */
375                 res->h_aliases = tp;
376                 tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
377                 *tp++=NULL;
378                 /* finally the addresses */
379                 res->h_addr_list = tp;
380                 tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
381                 *tp++=NULL;
382                 return 0;
383         }
384         return -1;
385 }
386 #endif
387
388 #if defined( NEED_SAFE_REALLOC )
389 static char *safe_realloc( char **buf, int len )
390 {
391         char *tmpbuf;
392         tmpbuf = realloc( *buf, len );
393         if (tmpbuf) {
394                 *buf=tmpbuf;
395         } 
396         return tmpbuf;
397 }
398 #endif
399
400