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