]> git.sur5r.net Git - openldap/blob - clients/rcpt500/query.c
Made dnNormalize() do Unicode normalization and case folding.
[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, ufn;
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     ufn = 0;
55
56     if ( msgp->msg_arg == NULL ) {
57         return( help_cmd( msgp, reply ));
58     }
59
60     remove_trailing_space( msgp->msg_arg );
61     if ( *msgp->msg_arg == '\0' ) {
62         return( help_cmd( msgp, reply ));
63     }
64
65     if (( lfdp = ldap_init_getfilter( filterfile )) == NULL ) {
66         strcat( reply, errpreface );
67         strcat( reply, "filter file configuration error.  Try again later." );
68         return( 0 );
69     }
70
71     /*
72      * open connection to LDAP server and bind as dapuser
73      */
74         ldp = ldap_init( ldaphost, ldapport );
75
76     if ( ldp == NULL ) {
77         strcat( reply, errpreface );
78         strcat( reply, "X.500 service unavailable.  Try again later." );
79         ldap_getfilter_free( lfdp );
80         return( 0 );
81     }
82
83         if ( ldap_simple_bind_s( ldp, dapuser, NULL ) != LDAP_SUCCESS ) {
84             report_ldap_err( ldp, reply );
85             close_ldap( ldp );
86             ldap_getfilter_free( lfdp );
87             return( 0 );
88         }
89
90     /*
91      * set options for search and build filter
92      */
93         ldap_set_option(ldp, LDAP_OPT_DEREF, &derefaliases);
94         ldap_set_option(ldp, LDAP_OPT_SIZELIMIT, &sizelimit);
95
96     matches = 0;
97
98 #ifdef RCPT500_UFN
99     if ( strchr( msgp->msg_arg, ',' ) != NULL ) {
100         struct timeval  tv;
101
102         ldap_ufn_setprefix( ldp, searchbase );
103         if (( rc = ldap_ufn_search_s( ldp, msgp->msg_arg, attrs, 0, &ldmsgp ))
104                 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
105                 && rc != LDAP_TIMELIMIT_EXCEEDED ) {
106             report_ldap_err( ldp, reply );
107             close_ldap( ldp );
108             ldap_getfilter_free( lfdp );
109             return( 0 );
110         }
111         matches = ldap_count_entries( ldp, ldmsgp );
112         ufn = 1;
113     } else {
114 #endif /* RCPT500_UFN */
115     
116         for ( lfi = ldap_getfirstfilter( lfdp, "rcpt500", msgp->msg_arg );
117                 lfi != NULL; lfi = ldap_getnextfilter( lfdp )) {
118                 rc = ldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
119                         lfi->lfi_filter, attrs, 0, &ldmsgp );
120
121             if ( rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
122                     && rc != LDAP_TIMELIMIT_EXCEEDED ) {
123                 report_ldap_err( ldp, reply );
124                 close_ldap( ldp );
125                 ldap_getfilter_free( lfdp );
126                 return( 0 );
127             }
128
129             if (( matches = ldap_count_entries( ldp, ldmsgp )) != 0 ) {
130                 break;
131             }
132
133             if ( ldmsgp != NULL ) {
134                 ldap_msgfree( ldmsgp );
135             }
136         }
137 #ifdef RCPT500_UFN
138     }
139 #endif /* RCPT500_UFN */
140
141     if ( matches == 0 ) {
142         sprintf( buf, "No matches were found for '%s'\n", msgp->msg_arg );
143         strcat( reply, buf );
144         close_ldap( ldp );
145         ldap_getfilter_free( lfdp );
146         return( 0 );
147     }
148
149         ld_errno = 0;
150         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
151
152     if ( ld_errno == LDAP_TIMELIMIT_EXCEEDED
153             || ld_errno == LDAP_SIZELIMIT_EXCEEDED ) {
154         strcat( reply, "(Partial results only - a limit was exceeded)\n" );
155     }
156
157     if ( matches <= RCPT500_LISTLIMIT ) {
158         sprintf( buf, "%d %s match%s found for '%s':\n\n", matches,
159                 ufn ? "UFN" : lfi->lfi_desc,
160                 ( matches > 1 ) ? "es" : "", msgp->msg_arg );
161         strcat( reply, buf );
162
163         if (( rc = ldap_init_templates( templatefile, &tmpllist )) != 0 ) {
164             sprintf( buf, "%s ldap_init_templates( %s ) failed (error %d)\n",
165                 errpreface, templatefile, rc );
166             strcat( reply, buf );
167         }
168
169         for ( entry = ldap_first_entry( ldp, ldmsgp ); entry != NULL; ) {
170             dn = ldap_get_dn( ldp, entry );
171             if ( do_read( ldp, dn, reply, tmpllist ) != LDAP_SUCCESS ) {
172                 report_ldap_err( ldp, reply );
173             }
174             free( dn );
175             if (( entry = ldap_next_entry( ldp, entry )) != NULL ) {
176                 strcat( reply, "\n-------\n\n" );
177             }
178         }
179
180         if ( tmpllist != NULL ) {
181             ldap_free_templates( tmpllist );
182         }
183         ldap_msgfree( ldmsgp );
184
185     } else {
186         sprintf( buf, "%d %s matches were found for '%s':\n",
187                 matches, ufn ? "UFN" : lfi->lfi_desc, msgp->msg_arg );
188         strcat( reply, buf );
189         append_entry_list( reply, msgp->msg_arg, ldp, ldmsgp );
190         ldap_msgfree( ldmsgp );
191     }
192
193     close_ldap( ldp );
194     ldap_getfilter_free( lfdp );
195     return( 0 );
196 }
197
198
199 static void
200 close_ldap( LDAP *ld )
201 {
202         ldap_unbind( ld );
203 }
204
205
206 static void
207 append_entry_list( char *reply, char *query, LDAP *ldp, LDAPMessage *ldmsgp )
208 {
209     LDAPMessage *e;
210     char        *dn, *rdn, *s, **title;
211     int         free_rdn = 0;
212
213 #ifdef RCPT500_SORT_ATTR
214     ldap_sort_entries( ldp, &ldmsgp, RCPT500_SORT_ATTR, strcasecmp );
215 #endif
216
217     for ( e = ldap_first_entry( ldp, ldmsgp ); e != NULL;
218                 e = ldap_next_entry( ldp, e )) {
219         dn = ldap_get_dn( ldp, e );
220         if (( s = strchr( dn, ',' )) != NULL ) {
221             *s = '\0';
222         }
223         if (( s = strchr( dn, '=' )) == NULL ) {
224             rdn = dn;
225         } else {
226             rdn = s + 1;
227         }
228
229 #ifdef UOFM
230         /*
231          * if this entry's rdn is an exact match for the thing looked up, we
232          * return the CN that has a digit after it, so that the user is
233          * returned something guaranteed to yield exactly one match if they
234          * pick it from the list and query it
235          */
236
237         if ( strcasecmp( rdn, query ) == 0 ) {
238             char        **cn;
239             int         i;
240
241             if (( cn = ldap_get_values( ldp, e, "cn" )) != NULL ) {
242                 for ( i = 0; cn[i] != NULL; i++ ) {
243                     if ( isdigit((unsigned char) cn[i][strlen( cn[i] ) - 1])) {
244                         rdn = strdup( cn[i] );
245                         free_rdn = 1;
246                         break;
247                     }
248                 }
249                 ldap_value_free( cn );
250             }
251         }
252 #endif /* UOFM */
253
254         title = ldap_get_values( ldp, e, "title" );
255         sprintf( buf, "  %-20s    %s\n", rdn, title ? title[0] : "" );
256         strcat( reply, buf );
257         if ( title != NULL ) {
258             ldap_value_free( title );
259         }
260         free( dn );
261         if ( free_rdn ) {
262             free( rdn );
263         }
264     }
265 }
266
267
268 static int
269 append_text( void *reply, char *text, ber_len_t len )
270 {
271     strcat( (char *) reply, text );
272     return( len );
273 }
274     
275
276 static int
277 do_read( LDAP *ldp, char *dn, char *reply, struct ldap_disptmpl *tmpll )
278 {
279     int                         rc;
280     static char *maildefvals[] = { "None registered in this service", NULL };
281     static char *defattrs[] = { "mail", NULL };
282     static char **defvals[] = { maildefvals, NULL };
283
284
285     rc = ldap_entry2text_search( ldp, dn, searchbase, NULL, tmpll,
286             defattrs, defvals, append_text, (void *)reply, "\n",
287             rdncount, LDAP_DISP_OPT_DOSEARCHACTIONS );
288
289     return( rc );
290 }
291
292
293 static void
294 report_ldap_err( LDAP *ldp, char *reply )
295 {
296         int ld_errno = 0;
297         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
298
299     strcat( reply, errpreface );
300     strcat( reply, ldap_err2string( ld_errno ));
301     strcat( reply, "\n" );
302 }
303
304
305 static void
306 remove_trailing_space( char *s )
307 {
308     char        *p = s + strlen( s ) - 1;
309
310     while ( isspace( (unsigned char) *p ) && p > s ) {
311         --p;
312     }
313     *(++p) = '\0';
314 }