]> git.sur5r.net Git - openldap/blob - libraries/libldap/cldap.c
silence excessive logging
[openldap] / libraries / libldap / cldap.c
1 /*
2  *  Copyright (c) 1990, 1994 Regents of the University of Michigan.
3  *  All rights reserved.
4  *
5  *  cldap.c - synchronous, retrying interface to the cldap protocol
6  */
7
8
9 #ifdef CLDAP
10
11 #ifndef lint 
12 static char copyright[] = "@(#) Copyright (c) 1990, 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
13 #endif
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #ifdef MACOS
19 #include <stdlib.h>
20 #include "macos.h"
21 #else /* MACOS */
22 #ifdef DOS
23 #include "msdos.h"
24 #else /* DOS */
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <netdb.h>
30 #endif /* DOS */
31 #endif /* MACOS */
32
33 #include "lber.h"
34 #include "ldap.h"
35 #include "ldap-int.h"
36
37 #define DEF_CLDAP_TIMEOUT       3
38 #define DEF_CLDAP_TRIES         4
39
40 #ifndef INADDR_LOOPBACK
41 #define INADDR_LOOPBACK ((unsigned long) 0x7f000001)
42 #endif
43
44
45 struct cldap_retinfo {
46         int             cri_maxtries;
47         int             cri_try;
48         int             cri_useaddr;
49         long            cri_timeout;
50 };
51
52 #ifdef NEEDPROTOS
53 static int add_addr( LDAP *ld, struct sockaddr *sap );
54 static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
55         struct cldap_retinfo *crip, char *base );
56 static int cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
57         LDAPMessage **res, char *base );
58 #else /* NEEDPROTOS */
59 static int add_addr();
60 static int cldap_result();
61 static int cldap_parsemsg();
62 #endif /* NEEDPROTOS */
63
64 /*
65  * cldap_open - initialize and connect to an ldap server.  A magic cookie to
66  * be used for future communication is returned on success, NULL on failure.
67  *
68  * Example:
69  *      LDAP    *ld;
70  *      ld = cldap_open( hostname, port );
71  */
72
73 LDAP *
74 cldap_open( char *host, int port )
75 {
76     int                 s;
77     unsigned long       address;
78     struct sockaddr_in  sock;
79     struct hostent      *hp;
80     LDAP                *ld;
81     char                *p;
82     int                 i;
83
84     Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
85
86     if ( port == 0 ) {
87             port = LDAP_PORT;
88     }
89
90     if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
91         return( NULL );
92     }
93
94     sock.sin_addr.s_addr = 0;
95     sock.sin_family = AF_INET;
96     sock.sin_port = 0;
97     if ( bind(s, (struct sockaddr *) &sock, sizeof(sock)) < 0)  {
98         close( s );
99         return( NULL );
100     }
101
102     if (( ld = ldap_init( host, port )) == NULL ) {
103         close( s );
104         return( NULL );
105     }
106     if ( (ld->ld_sb.sb_fromaddr = (void *) calloc( 1,
107             sizeof( struct sockaddr ))) == NULL ) {
108         free( ld );
109         close( s );
110         return( NULL );
111     }   
112     ld->ld_sb.sb_sd = s;
113     ld->ld_sb.sb_naddr = 0;
114     ld->ld_version = LDAP_VERSION;
115
116     sock.sin_family = AF_INET;
117     sock.sin_port = htons( port );
118
119     /*
120      * 'host' may be a space-separated list.
121      */
122     if ( host != NULL ) {
123         for ( ; host != NULL; host = p ) {
124             if (( p = strchr( host, ' ' )) != NULL ) {
125                 for (*p++ = '\0'; *p == ' '; p++) {
126                     ;
127                 }
128             }
129
130             if ( (address = inet_addr( host )) == -1 ) {
131                 if ( (hp = gethostbyname( host )) == NULL ) {
132                     errno = EHOSTUNREACH;
133                     continue;
134                 }
135
136                 for ( i = 0; hp->h_addr_list[ i ] != 0; ++i ) {
137                     SAFEMEMCPY( (char *)&sock.sin_addr.s_addr,
138                             (char *)hp->h_addr_list[ i ],
139                             sizeof(sock.sin_addr.s_addr));
140                     if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
141                         close( s );
142                         free( ld );
143                         return( NULL );
144                     }
145                 }
146
147             } else {
148                 sock.sin_addr.s_addr = address;
149                 if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
150                     close( s );
151                     free( ld );
152                     return( NULL );
153                 }
154             }
155
156             if ( ld->ld_host == NULL ) {
157                     ld->ld_host = strdup( host );
158             }
159         }
160
161     } else {
162         address = INADDR_LOOPBACK;
163         sock.sin_addr.s_addr = htonl( address );
164         if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
165             close( s );
166             free( ld );
167             return( NULL );
168         }
169     }
170
171     if ( ld->ld_sb.sb_addrs == NULL
172 #ifdef LDAP_REFERRALS
173             || ( ld->ld_defconn = new_connection( ld, NULL, 1,0,0 )) == NULL
174 #endif /* LDAP_REFERRALS */
175             ) {
176         free( ld );
177         return( NULL );
178     }
179
180     ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ 0 ];
181     cldap_setretryinfo( ld, 0, 0 );
182
183 #ifdef LDAP_DEBUG
184     putchar( '\n' );
185     for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) {
186         Debug( LDAP_DEBUG_TRACE, "end of cldap_open address %d is %s\n",
187                 i, inet_ntoa( ((struct sockaddr_in *)
188                 ld->ld_sb.sb_addrs[ i ])->sin_addr ), 0 );
189     }
190 #endif
191
192     return( ld );
193 }
194
195
196
197 void
198 cldap_close( LDAP *ld )
199 {
200         ldap_ld_free( ld, 0 );
201 }
202
203
204 void
205 cldap_setretryinfo( LDAP *ld, int tries, int timeout )
206 {
207     ld->ld_cldaptries = ( tries <= 0 ) ? DEF_CLDAP_TRIES : tries;
208     ld->ld_cldaptimeout = ( timeout <= 0 ) ? DEF_CLDAP_TIMEOUT : timeout;
209 }
210
211
212 int
213 cldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
214         int attrsonly, LDAPMessage **res, char *logdn )
215 {
216     int                         ret, msgid;
217     struct cldap_retinfo        cri;
218
219     *res = NULLMSG;
220
221     (void) memset( &cri, 0, sizeof( cri ));
222
223     if ( logdn != NULL ) {
224         ld->ld_cldapdn = logdn;
225     } else if ( ld->ld_cldapdn == NULL ) {
226         ld->ld_cldapdn = "";
227     }
228
229     do {
230         if ( cri.cri_try != 0 ) {
231                 --ld->ld_msgid; /* use same id as before */
232         }
233         ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ cri.cri_useaddr ];
234
235         Debug( LDAP_DEBUG_TRACE, "cldap_search_s try %d (to %s)\n",
236             cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
237             ld->ld_sb.sb_useaddr)->sin_addr ), 0 );
238
239             if ( (msgid = ldap_search( ld, base, scope, filter, attrs,
240                 attrsonly )) == -1 ) {
241                     return( ld->ld_errno );
242             }
243 #ifndef NO_CACHE
244             if ( ld->ld_cache != NULL && ld->ld_responses != NULL ) {
245                 Debug( LDAP_DEBUG_TRACE, "cldap_search_s res from cache\n",
246                         0, 0, 0 );
247                 *res = ld->ld_responses;
248                 ld->ld_responses = ld->ld_responses->lm_next;
249                 return( ldap_result2error( ld, *res, 0 ));
250             }
251 #endif /* NO_CACHE */
252             ret = cldap_result( ld, msgid, res, &cri, base );
253         } while (ret == -1);
254
255         return( ret );
256 }
257
258
259 static int
260 add_addr( LDAP *ld, struct sockaddr *sap )
261 {
262     struct sockaddr     *newsap, **addrs;
263
264     if (( newsap = (struct sockaddr *)malloc( sizeof( struct sockaddr )))
265             == NULL ) {
266         ld->ld_errno = LDAP_NO_MEMORY;
267         return( -1 );
268     }
269
270     if ( ld->ld_sb.sb_naddr == 0 ) {
271         addrs = (struct sockaddr **)malloc( sizeof(struct sockaddr *));
272     } else {
273         addrs = (struct sockaddr **)realloc( ld->ld_sb.sb_addrs,
274                 ( ld->ld_sb.sb_naddr + 1 ) * sizeof(struct sockaddr *));
275     }
276
277     if ( addrs == NULL ) {
278         free( newsap );
279         ld->ld_errno = LDAP_NO_MEMORY;
280         return( -1 );
281     }
282
283     SAFEMEMCPY( (char *)newsap, (char *)sap, sizeof( struct sockaddr ));
284     addrs[ ld->ld_sb.sb_naddr++ ] = newsap;
285     ld->ld_sb.sb_addrs = (void **)addrs;
286     return( 0 );
287 }
288
289
290 static int
291 cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
292         struct cldap_retinfo *crip, char *base )
293 {
294     Sockbuf             *sb = &ld->ld_sb;
295     BerElement          ber;
296     char                *logdn;
297     int                 ret, id, fromaddr, i;
298     struct timeval      tv;
299
300     fromaddr = -1;
301
302     if ( crip->cri_try == 0 ) {
303         crip->cri_maxtries = ld->ld_cldaptries * sb->sb_naddr;
304         crip->cri_timeout = ld->ld_cldaptimeout;
305         crip->cri_useaddr = 0;
306         Debug( LDAP_DEBUG_TRACE, "cldap_result tries %d timeout %d\n",
307                 ld->ld_cldaptries, ld->ld_cldaptimeout, 0 );
308     }
309
310     if ((tv.tv_sec = crip->cri_timeout / sb->sb_naddr) < 1 ) {
311         tv.tv_sec = 1;
312     }
313     tv.tv_usec = 0;
314
315     Debug( LDAP_DEBUG_TRACE,
316             "cldap_result waiting up to %d seconds for a response\n",
317             tv.tv_sec, 0, 0 );
318     ber_init( &ber, 0 );
319     set_ber_options( ld, &ber );
320
321     if ( cldap_getmsg( ld, &tv, &ber ) == -1 ) {
322         ret = ld->ld_errno;
323         Debug( LDAP_DEBUG_TRACE, "cldap_getmsg returned -1 (%d)\n",
324                 ret, 0, 0 );
325     } else if ( ld->ld_errno == LDAP_TIMEOUT ) {
326         Debug( LDAP_DEBUG_TRACE,
327             "cldap_result timed out\n", 0, 0, 0 );
328         /*
329          * It timed out; is it time to give up?
330          */
331         if ( ++crip->cri_try >= crip->cri_maxtries ) {
332             ret = LDAP_TIMEOUT;
333             --crip->cri_try;
334         } else {
335             if ( ++crip->cri_useaddr >= sb->sb_naddr ) {
336                 /*
337                  * new round: reset address to first one and
338                  * double the timeout
339                  */
340                 crip->cri_useaddr = 0;
341                 crip->cri_timeout <<= 1;
342             }
343             ret = -1;
344         }
345
346     } else {
347         /*
348          * Got a response.  It should look like:
349          * { msgid, logdn, { searchresponse...}}
350          */
351         logdn = NULL;
352
353         if ( ber_scanf( &ber, "ia", &id, &logdn ) == LBER_ERROR ) {
354             free( ber.ber_buf );        /* gack! */
355             ret = LDAP_DECODING_ERROR;
356             Debug( LDAP_DEBUG_TRACE,
357                     "cldap_result: ber_scanf returned LBER_ERROR (%d)\n",
358                     ret, 0, 0 );
359         } else if ( id != msgid ) {
360             free( ber.ber_buf );        /* gack! */
361             Debug( LDAP_DEBUG_TRACE,
362                     "cldap_result: looking for msgid %d; got %d\n",
363                     msgid, id, 0 );
364             ret = -1;   /* ignore and keep looking */
365         } else {
366             /*
367              * got a result: determine which server it came from
368              * decode into ldap message chain
369              */
370             for ( fromaddr = 0; fromaddr < sb->sb_naddr; ++fromaddr ) {
371                     if ( memcmp( &((struct sockaddr_in *)
372                             sb->sb_addrs[ fromaddr ])->sin_addr,
373                             &((struct sockaddr_in *)sb->sb_fromaddr)->sin_addr,
374                             sizeof( struct in_addr )) == 0 ) {
375                         break;
376                     }
377             }
378             ret = cldap_parsemsg( ld, msgid, &ber, res, base );
379             free( ber.ber_buf );        /* gack! */
380             Debug( LDAP_DEBUG_TRACE,
381                 "cldap_result got result (%d)\n", ret, 0, 0 );
382         }
383
384         if ( logdn != NULL ) {
385                 free( logdn );
386         }
387     }
388     
389
390     /*
391      * If we are giving up (successfully or otherwise) then 
392      * abandon any outstanding requests.
393      */
394     if ( ret != -1 ) {
395         i = crip->cri_try;
396         if ( i >= sb->sb_naddr ) {
397             i = sb->sb_naddr - 1;
398         }
399
400         for ( ; i >= 0; --i ) {
401             if ( i == fromaddr ) {
402                 continue;
403             }
404             sb->sb_useaddr = sb->sb_addrs[ i ];
405             Debug( LDAP_DEBUG_TRACE, "cldap_result abandoning id %d (to %s)\n",
406                 msgid, inet_ntoa( ((struct sockaddr_in *)
407                 sb->sb_useaddr)->sin_addr ), 0 );
408             (void) ldap_abandon( ld, msgid );
409         }
410     }
411
412     return( ld->ld_errno = ret );
413 }
414
415
416 static int
417 cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
418         LDAPMessage **res, char *base )
419 {
420     unsigned long       tag, len;
421     int                 baselen, slen, rc;
422     char                *dn, *p, *cookie;
423     LDAPMessage         *chain, *prev, *ldm;
424     struct berval       *bv;
425
426     rc = LDAP_DECODING_ERROR;   /* pessimistic */
427     ldm = chain = prev = NULLMSG;
428     baselen = ( base == NULL ) ? 0 : strlen( base );
429     bv = NULL;
430
431     for ( tag = ber_first_element( ber, &len, &cookie );
432             tag != LBER_DEFAULT && rc != LDAP_SUCCESS;
433             tag = ber_next_element( ber, &len, cookie )) {
434         if (( ldm = (LDAPMessage *)calloc( 1, sizeof(LDAPMessage)))
435                 == NULL || ( ldm->lm_ber = alloc_ber_with_options( ld ))
436                 == NULLBER ) {
437             rc = LDAP_NO_MEMORY;
438             break;      /* return w/error*/
439         }
440         ldm->lm_msgid = msgid;
441         ldm->lm_msgtype = tag;
442
443         if ( tag == LDAP_RES_SEARCH_RESULT ) {
444             Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg got search result\n",
445                     0, 0, 0 );
446
447             if ( ber_get_stringal( ber, &bv ) == LBER_DEFAULT ) {
448                 break;  /* return w/error */
449             }
450
451             if ( ber_printf( ldm->lm_ber, "to", tag, bv->bv_val,
452                     bv->bv_len ) == -1 ) {
453                 break;  /* return w/error */
454             }
455             ber_bvfree( bv );
456             bv = NULL;
457             rc = LDAP_SUCCESS;
458
459         } else if ( tag == LDAP_RES_SEARCH_ENTRY ) {
460             if ( ber_scanf( ber, "{aO", &dn, &bv ) == LBER_ERROR ) {
461                 break;  /* return w/error */
462             }
463             Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg entry %s\n", dn, 0, 0 );
464             if ( dn != NULL && *(dn + ( slen = strlen(dn)) - 1) == '*' &&
465                     baselen > 0 ) {
466                 /*
467                  * substitute original searchbase for trailing '*'
468                  */
469                 if (( p = (char *)malloc( slen + baselen )) == NULL ) {
470                     rc = LDAP_NO_MEMORY;
471                     free( dn );
472                     break;      /* return w/error */
473                 }
474                 strcpy( p, dn );
475                 strcpy( p + slen - 1, base );
476                 free( dn );
477                 dn = p;
478             }
479
480             if ( ber_printf( ldm->lm_ber, "t{so}", tag, dn, bv->bv_val,
481                     bv->bv_len ) == -1 ) {
482                 break;  /* return w/error */
483             }
484             free( dn );
485             ber_bvfree( bv );
486             bv = NULL;
487                 
488         } else {
489             Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg got unknown tag %d\n",
490                     tag, 0, 0 );
491             rc = LDAP_PROTOCOL_ERROR;
492             break;      /* return w/error */
493         }
494
495         /* Reset message ber so we can read from it later.  Gack! */
496         ldm->lm_ber->ber_end = ldm->lm_ber->ber_ptr;
497         ldm->lm_ber->ber_ptr = ldm->lm_ber->ber_buf;
498
499 #ifdef LDAP_DEBUG
500         if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
501             fprintf( stderr, "cldap_parsemsg add message id %d type %d:\n",
502                     ldm->lm_msgid, ldm->lm_msgtype  );
503             ber_dump( ldm->lm_ber, 1 );
504         }
505 #endif /* LDAP_DEBUG */
506
507 #ifndef NO_CACHE
508             if ( ld->ld_cache != NULL ) {
509                 add_result_to_cache( ld, ldm );
510             }
511 #endif /* NO_CACHE */
512
513         if ( chain == NULL ) {
514             chain = ldm;
515         } else {
516             prev->lm_chain = ldm;
517         }
518         prev = ldm;
519         ldm = NULL;
520     }
521
522     /* dispose of any leftovers */
523     if ( ldm != NULL ) {
524         if ( ldm->lm_ber != NULLBER ) {
525             ber_free( ldm->lm_ber, 1 );
526         }
527         free( ldm );
528     }
529     if ( bv != NULL ) {
530         ber_bvfree( bv );
531     }
532
533     /* return chain, calling result2error if we got anything at all */
534     *res = chain;
535     return(( *res == NULLMSG ) ? rc : ldap_result2error( ld, *res, 0 ));
536 }
537 #endif /* CLDAP */