]> git.sur5r.net Git - openldap/blob - clients/rcpt500/query.c
dac5f15fc92f2435b0be5aed35915443b89774e2
[openldap] / clients / rcpt500 / query.c
1 /*
2  * query.c: for rcpt500 (X.500 email query responder)
3  *
4  * 18 June 1992 by Mark C Smith
5  * Copyright (c) 1992 The Regents of The University of Michigan
6  * All Rights Reserved
7  */
8
9 #include "portable.h"
10
11 #include <ac/stdlib.h>
12
13 #include <ac/ctype.h>
14 #include <ac/string.h>
15 #include <ac/syslog.h>
16 #include <ac/time.h>
17
18 #include <stdio.h>
19
20 #include <ldap.h>
21 #include <disptmpl.h>
22
23 #include "rcpt500.h"
24 #include "ldap_defaults.h"
25
26 static char buf[ MAXSIZE ];
27 static char *errpreface = "Your query failed: ";
28
29 static void close_ldap(LDAP *ld);
30 static void append_entry_list(char *rep, char *qu, LDAP *ld, LDAPMessage *msg);
31 static int  append_text(void *reply, char *text, ber_len_t len);
32 static int  do_read (LDAP *ld, char *dn, char *rep, struct ldap_disptmpl *tmp);
33 static void report_ldap_err (LDAP *ldp, char *reply);
34 static void remove_trailing_space (char *s);
35
36
37 int
38 query_cmd( struct msginfo *msgp, char *reply )
39 {
40     LDAP                        *ldp;
41     LDAPMessage                 *ldmsgp, *entry;
42     char                        *dn;
43     int                         matches, rc, ld_errno, ufn;
44     LDAPFiltDesc                *lfdp;
45     LDAPFiltInfo                *lfi;
46     struct ldap_disptmpl        *tmpllist = NULL;
47     static char *attrs[] = { "cn", "title",
48 #ifdef RCPT500_SORT_ATTR
49                         RCPT500_SORT_ATTR,
50 #endif
51                         NULL };
52
53     ufn = 0;
54
55     if ( msgp->msg_arg == NULL ) {
56         return( help_cmd( msgp, reply ));
57     }
58
59     remove_trailing_space( msgp->msg_arg );
60     if ( *msgp->msg_arg == '\0' ) {
61         return( help_cmd( msgp, reply ));
62     }
63
64     if (( lfdp = ldap_init_getfilter( filterfile )) == NULL ) {
65         strcat( reply, errpreface );
66         strcat( reply, "filter file configuration error.  Try again later." );
67         return( 0 );
68     }
69
70     /*
71      * open connection to LDAP server and bind as dapuser
72      */
73 #ifdef LDAP_CONNECTIONLESS
74     if ( do_cldap )
75         ldp = cldap_open( ldaphost, ldapport );
76     else
77 #endif /* LDAP_CONNECTIONLESS */
78         ldp = ldap_init( ldaphost, ldapport );
79
80     if ( ldp == NULL ) {
81         strcat( reply, errpreface );
82         strcat( reply, "X.500 service unavailable.  Try again later." );
83         ldap_getfilter_free( lfdp );
84         return( 0 );
85     }
86
87 #ifdef LDAP_CONNECTIONLESS
88     if ( !do_cldap )
89 #endif /* LDAP_CONNECTIONLESS */
90         if ( ldap_simple_bind_s( ldp, dapuser, NULL ) != LDAP_SUCCESS ) {
91             report_ldap_err( ldp, reply );
92             close_ldap( ldp );
93             ldap_getfilter_free( lfdp );
94             return( 0 );
95         }
96
97     /*
98      * set options for search and build filter
99      */
100         ldap_set_option(ldp, LDAP_OPT_DEREF, &derefaliases);
101         ldap_set_option(ldp, LDAP_OPT_SIZELIMIT, &sizelimit);
102
103     matches = 0;
104
105 #ifdef RCPT500_UFN
106 #ifdef LDAP_CONNECTIONLESS
107     if ( !do_cldap && strchr( msgp->msg_arg, ',' ) != NULL ) {
108 #else /* LDAP_CONNECTIONLESS */
109     if ( strchr( msgp->msg_arg, ',' ) != NULL ) {
110 #endif /* LDAP_CONNECTIONLESS */
111         struct timeval  tv;
112
113         ldap_ufn_setprefix( ldp, searchbase );
114         if (( rc = ldap_ufn_search_s( ldp, msgp->msg_arg, attrs, 0, &ldmsgp ))
115                 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
116                 && rc != LDAP_TIMELIMIT_EXCEEDED ) {
117             report_ldap_err( ldp, reply );
118             close_ldap( ldp );
119             ldap_getfilter_free( lfdp );
120             return( 0 );
121         }
122         matches = ldap_count_entries( ldp, ldmsgp );
123         ufn = 1;
124     } else {
125 #endif /* RCPT500_UFN */
126     
127         for ( lfi = ldap_getfirstfilter( lfdp, "rcpt500", msgp->msg_arg );
128                 lfi != NULL; lfi = ldap_getnextfilter( lfdp )) {
129 #ifdef LDAP_CONNECTIONLESS
130             if ( do_cldap )
131                 rc = cldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
132                         lfi->lfi_filter, attrs, 0, &ldmsgp, dapuser );
133             else 
134 #endif /* LDAP_CONNECTIONLESS */
135                 rc = ldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
136                         lfi->lfi_filter, attrs, 0, &ldmsgp );
137
138             if ( rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
139                     && rc != LDAP_TIMELIMIT_EXCEEDED ) {
140                 report_ldap_err( ldp, reply );
141                 close_ldap( ldp );
142                 ldap_getfilter_free( lfdp );
143                 return( 0 );
144             }
145
146             if (( matches = ldap_count_entries( ldp, ldmsgp )) != 0 ) {
147                 break;
148             }
149
150             if ( ldmsgp != NULL ) {
151                 ldap_msgfree( ldmsgp );
152             }
153         }
154 #ifdef RCPT500_UFN
155     }
156 #endif /* RCPT500_UFN */
157
158     if ( matches == 0 ) {
159         sprintf( buf, "No matches were found for '%s'\n", msgp->msg_arg );
160         strcat( reply, buf );
161         close_ldap( ldp );
162         ldap_getfilter_free( lfdp );
163         return( 0 );
164     }
165
166         ld_errno = 0;
167         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
168
169     if ( ld_errno == LDAP_TIMELIMIT_EXCEEDED
170             || ld_errno == LDAP_SIZELIMIT_EXCEEDED ) {
171         strcat( reply, "(Partial results only - a limit was exceeded)\n" );
172     }
173
174     if ( matches <= RCPT500_LISTLIMIT ) {
175         sprintf( buf, "%d %s match%s found for '%s':\n\n", matches,
176                 ufn ? "UFN" : lfi->lfi_desc,
177                 ( matches > 1 ) ? "es" : "", msgp->msg_arg );
178         strcat( reply, buf );
179
180         if (( rc = ldap_init_templates( templatefile, &tmpllist )) != 0 ) {
181             sprintf( buf, "%s ldap_init_templates( %s ) failed (error %d)\n",
182                 errpreface, templatefile, rc );
183             strcat( reply, buf );
184         }
185
186         for ( entry = ldap_first_entry( ldp, ldmsgp ); entry != NULL; ) {
187             dn = ldap_get_dn( ldp, entry );
188             if ( do_read( ldp, dn, reply, tmpllist ) != LDAP_SUCCESS ) {
189                 report_ldap_err( ldp, reply );
190             }
191             free( dn );
192             if (( entry = ldap_next_entry( ldp, entry )) != NULL ) {
193                 strcat( reply, "\n-------\n\n" );
194             }
195         }
196
197         if ( tmpllist != NULL ) {
198             ldap_free_templates( tmpllist );
199         }
200         ldap_msgfree( ldmsgp );
201
202     } else {
203         sprintf( buf, "%d %s matches were found for '%s':\n",
204                 matches, ufn ? "UFN" : lfi->lfi_desc, msgp->msg_arg );
205         strcat( reply, buf );
206         append_entry_list( reply, msgp->msg_arg, ldp, ldmsgp );
207         ldap_msgfree( ldmsgp );
208     }
209
210     close_ldap( ldp );
211     ldap_getfilter_free( lfdp );
212     return( 0 );
213 }
214
215
216 static void
217 close_ldap( LDAP *ld )
218 {
219 #ifdef LDAP_CONNECTIONLESS
220     if ( do_cldap )
221         cldap_close( ld );
222     else
223 #endif /* LDAP_CONNECTIONLESS */
224         ldap_unbind( ld );
225 }
226
227
228 static void
229 append_entry_list( char *reply, char *query, LDAP *ldp, LDAPMessage *ldmsgp )
230 {
231     LDAPMessage *e;
232     char        *dn, *rdn, *s, **title;
233     int         free_rdn = 0;
234
235 #ifdef RCPT500_SORT_ATTR
236     ldap_sort_entries( ldp, &ldmsgp, RCPT500_SORT_ATTR, strcasecmp );
237 #endif
238
239     for ( e = ldap_first_entry( ldp, ldmsgp ); e != NULL;
240                 e = ldap_next_entry( ldp, e )) {
241         dn = ldap_get_dn( ldp, e );
242         if (( s = strchr( dn, ',' )) != NULL ) {
243             *s = '\0';
244         }
245         if (( s = strchr( dn, '=' )) == NULL ) {
246             rdn = dn;
247         } else {
248             rdn = s + 1;
249         }
250
251 #ifdef UOFM
252         /*
253          * if this entry's rdn is an exact match for the thing looked up, we
254          * return the CN that has a digit after it, so that the user is
255          * returned something guaranteed to yield exactly one match if they
256          * pick it from the list and query it
257          */
258
259         if ( strcasecmp( rdn, query ) == 0 ) {
260             char        **cn;
261             int         i;
262
263             if (( cn = ldap_get_values( ldp, e, "cn" )) != NULL ) {
264                 for ( i = 0; cn[i] != NULL; i++ ) {
265                     if ( isdigit((unsigned char) cn[i][strlen( cn[i] ) - 1])) {
266                         rdn = strdup( cn[i] );
267                         free_rdn = 1;
268                         break;
269                     }
270                 }
271                 ldap_value_free( cn );
272             }
273         }
274 #endif /* UOFM */
275
276         title = ldap_get_values( ldp, e, "title" );
277         sprintf( buf, "  %-20s    %s\n", rdn, title ? title[0] : "" );
278         strcat( reply, buf );
279         if ( title != NULL ) {
280             ldap_value_free( title );
281         }
282         free( dn );
283         if ( free_rdn ) {
284             free( rdn );
285         }
286     }
287 }
288
289
290 static int
291 append_text( void *reply, char *text, ber_len_t len )
292 {
293     strcat( (char *) reply, text );
294     return( len );
295 }
296     
297
298 static int
299 do_read( LDAP *ldp, char *dn, char *reply, struct ldap_disptmpl *tmpll )
300 {
301     int                         rc;
302     static char *maildefvals[] = { "None registered in this service", NULL };
303     static char *defattrs[] = { "mail", NULL };
304     static char **defvals[] = { maildefvals, NULL };
305
306
307     rc = ldap_entry2text_search( ldp, dn, searchbase, NULL, tmpll,
308             defattrs, defvals, append_text, (void *)reply, "\n",
309             rdncount, LDAP_DISP_OPT_DOSEARCHACTIONS );
310
311     return( rc );
312 }
313
314
315 static void
316 report_ldap_err( LDAP *ldp, char *reply )
317 {
318         int ld_errno = 0;
319         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
320
321     strcat( reply, errpreface );
322     strcat( reply, ldap_err2string( ld_errno ));
323     strcat( reply, "\n" );
324 }
325
326
327 static void
328 remove_trailing_space( char *s )
329 {
330     char        *p = s + strlen( s ) - 1;
331
332     while ( isspace( (unsigned char) *p ) && p > s ) {
333         --p;
334     }
335     *(++p) = '\0';
336 }