]> git.sur5r.net Git - openldap/blob - clients/ud/find.c
From jon@symas.com - patches for consistent use of directory separators
[openldap] / clients / ud / find.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1991, 1992, 1993 
8  * Regents of the University of Michigan.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/stdlib.h>
23
24 #include <ac/ctype.h>
25 #include <ac/string.h>
26 #include <ac/time.h>
27
28 #include <ldap.h>
29
30 #include "ud.h"
31
32 static int num_picked = 0;      /* used when user picks entry at More prompt */
33
34
35 int
36 vrfy( char *dn )
37 {
38         LDAPMessage *results = NULL;
39         static char *attrs[2] = { "1.1", NULL };
40         int ld_errno = 0;
41
42 #ifdef DEBUG
43         if (debug & D_TRACE)
44                 printf("->vrfy(%s)\n", dn);
45 #endif
46         /* verify that this DN exists in the directory */
47         (void) ldap_search_s(ld, dn, LDAP_SCOPE_BASE, NULL, attrs, TRUE, &results);
48         (void) ldap_msgfree(results);
49
50         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
51
52         if ((ld_errno == LDAP_NO_SUCH_OBJECT) || (ld_errno == LDAP_INVALID_DN_SYNTAX))
53                 return(0);
54         else if (ld_errno == LDAP_SUCCESS)
55                 return(1);
56         else {
57                 ldap_perror(ld, "ldap_search");
58                 return(0);
59         }
60 }
61         
62
63 static LDAPMessage *
64 disambiguate( LDAPMessage *result, int matches, char **read_attrs, char *who )
65 {
66         int choice;                     /* entry that user chooses */
67         int i;
68         char *namelist[MAX_NUM_NAMES];  /* names found */
69         char response[SMALL_BUF_SIZE];  /* results from user */
70         char *name = NULL;              /* DN to lookup */
71         LDAPMessage *mp = NULL;
72         int ld_errno = 0;
73
74 #ifdef DEBUG
75         if (debug & D_TRACE)
76                 printf("->disambiguate(%x, %d, %x, %s)\n", result, matches, 
77                                                         read_attrs, who);
78 #endif
79
80         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
81
82         /*
83          *  If we are here, it means that we got back multiple answers.
84          */
85         if ((ld_errno == LDAP_TIMELIMIT_EXCEEDED)
86             || (ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
87                 if (verbose) {
88                         printf("  Your query was too general and a limit was exceeded.  The results listed\n");
89                         printf("  are not complete.  You may want to try again with a more refined query.\n\n");
90                 }
91                 else
92                         printf("  Time or size limit exceeded.  Partial results follow.\n\n");
93         }
94         printf("  %1d names matched \"%s\".\n", matches, who);
95         for (;;) {
96                 printf("  Do you wish to see a list of names? ");
97                 fflush(stdout);
98                 (void) memset(response, '\0', sizeof(response));
99                 fetch_buffer(response, sizeof(response), stdin);
100                 switch (response[0]) {
101                 case 'n' :
102                 case 'N' :
103                 case '\0' :
104                 case '\n' :
105                         return(NULL);
106                         /* NOTREACHED */
107                 case 'y' :
108                 case 'Y' :
109                         print_list(result, namelist, &matches);
110                         if (num_picked == 0)
111                                 choice = pick_one(matches);
112                         else
113                                 choice = num_picked;
114                         num_picked = 0;
115                         if (choice >= 0)
116                                 name = strdup(namelist[choice]);
117                         /*
118                          *  Now free up all of the pointers allocated in
119                          *  namelist.  The print_list() routine that filled
120                          *  in this collection of strings starts at 1, not 0.
121                          */
122                         for (i = 1; namelist[i] != NULL; i++)
123                                 Free(namelist[i]);
124                         if (choice < 0) {
125                                 if (name != NULL)
126                                         Free(name);
127                                 return(NULL);
128                         }
129 #ifdef DEBUG
130                         if (debug & D_FIND) {
131                                 printf("  Calling ldap_search_s()\n");
132                                 printf("     ld = 0x%x\n", ld);
133                                 printf("     search base = %s\n", name);
134                                 printf("     scope = LDAP_SCOPE_BASE\n");
135                                 printf("     filter = (objectClass=*)\n");
136                                 for (i = 0; read_attrs[i] != NULL; i++)
137                                         printf("     read_attrs[%d] = %s\n", i, read_attrs[i]);
138                                 printf("     read_attrs[%d] = NULL\n", i);
139                                 printf("     attrsonly = FALSE\n");
140                                 printf("     &mp = 0x%x\n", &mp);
141                         }
142 #endif
143                         if (ldap_search_s(ld, name, LDAP_SCOPE_BASE, NULL, read_attrs, FALSE, &mp) != LDAP_SUCCESS) {
144                                 ldap_perror(ld, "ldap_search_s");
145                                 Free(name);
146                                 ldap_msgfree(mp);
147                                 return(NULL);
148                         }
149                         Free(name);
150                         return(mp);
151                         /* NOTREACHED */
152                 default :
153                         printf("  Please enter 'y', 'n', or RETURN.\n");
154                         break;
155                 }
156         }
157 }
158
159 LDAPMessage *
160 find( char *who, int quiet )
161 {
162         register int i, j, k;           /* general ints */
163         int matches;                    /* from ldap_count_entries() */
164         int admonished = FALSE;
165         static int attrs_set = 0;
166         static char *read_attrs[MAX_ATTRS];     /* attrs to use in a read op */
167         static char *search_attrs[MAX_ATTRS];   /* attrs to use in a srch op */
168         static int rc;                  /* return from ldap_search */
169         LDAPMessage *ldtmp, *res;       /* results returned from search */
170         char name[MED_BUF_SIZE];
171         char response[SMALL_BUF_SIZE];
172         char *cp, *dn, **rdns;
173         LDAPFiltInfo *fi;
174
175 #ifdef DEBUG
176         if (debug & D_TRACE)
177                 fprintf(stderr, "->find(%s)\n", who);
178 #endif
179         /* did not specify a 'who' */
180         if (who == NULL) {
181                 printf("  Locate whose entry? ");
182                 fflush(stdout);
183                 fetch_buffer(name, sizeof(name), stdin);
184                 if (name[0] != '\0')
185                         who = name;
186                 else
187                         return(NULL);
188         }
189         if (attrs_set == 0) {
190                 j = k = 0;
191                 attrs_set = 1;
192                 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
193                         if (attrlist[i].flags & ATTR_FLAG_READ)
194                                 read_attrs[j++] = attrlist[i].quipu_name;
195                         if (attrlist[i].flags & ATTR_FLAG_SEARCH)
196                                 search_attrs[k++] = attrlist[i].quipu_name;
197                 }
198                 read_attrs[j] = NULL;
199                 search_attrs[k] = NULL;
200         }
201
202         /*
203          *  Old users of the MTS *USERDIRECTORY will likely wrap the name
204          *  in quotes.  Not only is this unnecessary, but it also won't work.
205          */
206         for (cp = strchr(who, '"'); cp != NULL; cp = strchr(cp, '"')) {
207                 if (!admonished) {
208                         printf("  You do not need to enclose names in quotes.\n");
209                         admonished = TRUE;
210                 }
211                 *cp++ = ' ';
212                 if (*cp == '\0')
213                         break;
214         }
215
216         for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL;
217              fi = ldap_getnextfilter(lfdp)) {
218 #ifdef DEBUG
219                 if (debug & D_FIND)
220                         printf("Searching, filter = %s\n", fi->lfi_filter);
221 #endif
222
223                 if ((rc = ldap_search_s(ld, search_base, fi->lfi_scope, 
224                 fi->lfi_filter, search_attrs, FALSE, &res)) != LDAP_SUCCESS &&
225                 rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
226                         ldap_perror(ld, "ldap_search_s");
227                         ldap_msgfree(res);
228                         return(NULL);
229                 }
230                 if ((matches = ldap_count_entries(ld, res)) < 0) {
231                         ldap_perror(ld, "ldap_count_entries");
232                         ldap_msgfree(res);
233                         return(NULL);
234                 }
235                 else if (matches == 1) {
236                         dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
237                         ldap_msgfree(res);
238                         if (!quiet)
239                                 printf("  Found one %s match for \"%s\"\n", 
240                                                         fi->lfi_desc, who);
241                         if (!fi->lfi_isexact) {
242                                 rdns = ldap_explode_dn(dn, TRUE);
243                                 printf("  Do you mean %s? ", *rdns);
244                                 (void) ldap_value_free(rdns);
245                                 fflush(stdout);
246                                 fetch_buffer(response, sizeof(response), stdin);
247                                 if ((response[0] == 'n') || (response[0] == 'N'))
248                                 {
249                                         ldap_memfree(dn);
250                                         return(NULL);
251                                 }
252                         }
253 #ifdef DEBUG
254                         if (debug & D_FIND) {
255                                 printf("  Calling ldap_search_s()\n");
256                                 printf("     ld = 0x%x\n", ld);
257                                 printf("     dn = %s\n", dn);
258                                 printf("     scope = LDAP_SCOPE_BASE\n");
259                                 printf("     filter = %s\n", "(objectClass=*)");
260                                 for (i = 0; read_attrs[i] != NULL; i++)
261                                         printf("     read_attrs[%d] = %s\n", i, read_attrs[i]);
262                                 printf("     read_attrs[%d] = NULL\n", i);
263                                 printf("     attrsonly = FALSE\n");
264                                 printf("     &results = 0x%x\n", &res);
265                         }
266 #endif
267                         if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, NULL, read_attrs, FALSE, &res) != LDAP_SUCCESS) {
268                                 ldap_perror(ld, "ldap_search_s");
269                                 ldap_msgfree(res);
270                                 res = NULL;
271                         }
272                         ldap_memfree(dn);
273                         return(res);
274                 }
275                 else if (matches > 0) {
276                         ldtmp = disambiguate(res, matches, read_attrs, who);
277                         ldap_msgfree(res);
278                         return(ldtmp);
279                 }
280                 /* if we're here, there were zero matches */
281                 ldap_msgfree(res);
282         }
283         return(NULL);
284 }
285
286 int
287 pick_one( int i )
288 {
289         int n;
290         char user_pick[SMALL_BUF_SIZE];
291
292 #ifdef DEBUG
293         if (debug & D_TRACE)
294                 printf("->pick_one(%d)\n", i);
295 #endif
296         
297         /* make the user pick an entry */
298         for (;;) {
299                 printf("  Enter the number of the name you want or Q to quit: ");
300                 fflush(stdout);
301                 fetch_buffer(user_pick, sizeof(user_pick), stdin);
302                 if (user_pick[0] == 'q' || user_pick[0] == 'Q')
303                         return(-1);
304                 n = atoi(user_pick);
305                 if ((n > 0) && (n <= i))
306                         return(n);
307                 printf("  Invalid response\n");
308         }
309         /* NOTREACHED */
310 }
311
312 void
313 print_list( LDAPMessage *list, char **names, int *matches )
314 {
315         char **rdns, **cpp;
316         char resp[SMALL_BUF_SIZE];
317         register LDAPMessage *ep;
318         register int i = 1;
319         register int rest = 4;          /* 4, not 1 */
320
321 #ifdef DEBUG
322         if (debug & D_TRACE)
323                 printf("->print_list(%x, %x, %x)\n", list, names, matches);
324 #endif
325         /* print a list of names from which the user will select */
326         for (ep = ldap_first_entry(ld, list); ep != NULL; ep = ldap_next_entry(ld, ep)) {
327                 
328                 names[i] = ldap_get_dn(ld, ep);
329                 rdns = ldap_explode_dn(names[i], TRUE);
330                 cpp = ldap_get_values(ld, ep, "title");
331                 if (cpp == NULL)
332                         printf(" %3d. %s\n", i, *rdns);
333                 else
334                         printf(" %3d. %s, %s\n", i, *rdns, *cpp);
335                 ldap_value_free(rdns);
336                 ldap_value_free(cpp);
337                 i++;
338                 if ((rest++ > (lpp - 1)) && (i < *matches)) {
339 again:
340                         printf("  More? ");
341                         fflush(stdout);
342                         fetch_buffer(resp, sizeof(resp), stdin);
343                         if ((resp[0] == 'n') || (resp[0] == 'N'))
344                                 break;
345                         else if ((num_picked = atoi(resp)) != 0) {
346                                 if (num_picked < i)
347                                         break;
348                                 else
349                                         goto again;
350                         }
351                         rest = 1;
352                 }
353         }
354         *matches = i - 1;
355         names[i] = NULL;
356         return;
357 }
358
359 int
360 find_all_subscribers( char **sub, char *group )
361 {
362         int count;
363         LDAPMessage *result;
364         static char *attributes[] = { "cn", NULL };
365         char filter[MED_BUF_SIZE];
366         register LDAPMessage *ep;
367         register int i = 0;
368
369 #ifdef DEBUG
370         if (debug & D_TRACE)
371                 printf("->find_all_subscribers(%x, %s)\n", sub, group);
372 #endif
373
374         sprintf(filter, "%s=%s", "memberOfGroup", group);
375         if (ldap_search_s(ld, search_base, LDAP_SCOPE_SUBTREE, filter, attributes, FALSE, &result) != LDAP_SUCCESS) {
376                 int ld_errno = 0;
377                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
378                 if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
379                         return(0);
380                 ldap_perror(ld, "ldap_search_s");
381                 return(0);
382         }
383         count = ldap_count_entries(ld, result);
384         if (count < 1) {
385                 ldap_msgfree(result);
386                 return(0);
387         }
388         if ( count > MAX_VALUES ) {
389                 printf( "  Only retrieving the first %d subscribers....\n",
390                         MAX_VALUES );
391         }
392
393         for (ep = ldap_first_entry(ld, result); i < MAX_VALUES && ep != NULL; ep = ldap_next_entry(ld, ep)) {
394                 sub[i++] = ldap_get_dn(ld, ep);
395 #ifdef DEBUG
396                 if (debug & D_PARSE)
397                         printf("sub[%d] = %s\n", i - 1, sub[i - 1]);
398 #endif
399         }
400         sub[i] = NULL;
401         ldap_msgfree(result);
402         return(count);
403 }
404
405 char *
406 fetch_boolean_value( char *who, struct attribute attr )
407 {
408         LDAPMessage *result;            /* from the search below */
409         register LDAPMessage *ep;       /* entry pointer */
410         register char **vp;             /* for parsing the result */
411         static char *attributes[] = { NULL, NULL };
412
413 #ifdef DEBUG
414         if (debug & D_TRACE)
415                 printf("->fetch_boolean_value(%s, %s)\n", who, attr.quipu_name);
416 #endif
417         attributes[0] = attr.quipu_name;
418         if (ldap_search_s(ld, who, LDAP_SCOPE_BASE, NULL, attributes, FALSE, &result) != LDAP_SUCCESS) {
419                 int ld_errno = 0;
420                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
421                 if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
422                         return("FALSE");
423                 ldap_perror(ld, "ldap_search_s");
424                 ldap_msgfree(result);
425                 return(NULL);
426         }
427
428         /*
429          *  We did a read on one name and only asked for one attribute.
430          *  There's no reason to loop through any of these structures.
431          *
432          *  If ldap_first_attribute() returns NULL, then this entry did
433          *  not have this particular attribute.
434          */
435         ep = ldap_first_entry(ld, result);
436         if ((vp = (char **) ldap_get_values(ld, ep, attr.quipu_name)) == NULL) {
437                 ldap_msgfree(result);
438                 return("FALSE");
439         }
440         else {
441                 ldap_msgfree(result);
442                 if (!strcasecmp(*vp, "TRUE")) {
443                         ldap_value_free(vp);
444                         return("TRUE");
445                 }
446                 else if (!strcasecmp(*vp, "FALSE")) {
447                         ldap_value_free(vp);
448                         return("FALSE");
449                 }
450                 else {
451                         fprintf(stderr, "  Got garbage -> [%s]\n", *vp);
452                         ldap_value_free(vp);
453                         return(NULL);
454                 }
455         }
456 }