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