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