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