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