]> git.sur5r.net Git - openldap/blob - contrib/saucer/main.c
Use ldap_<set/get>_option instead of poking into the LDAP structure
[openldap] / contrib / saucer / main.c
1 /*
2  * Copyright (c) 1994, Strata Software Limited, Ottawa, Ontario, Canada.
3  * 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 Eric Rosenquist and Strata Software Limited. The SSL name
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  * 'saucer' LDAP command-line client source code.
14  *
15  * Author: Eric Rosenquist, 1994.
16  */
17
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include <lber.h>
24 #include <ldap.h>
25
26 #define DN_MAXLEN       4096
27
28 typedef struct {
29         char    *cmd;
30         int             (*func)();
31         char    *help_msg;
32 } CMDTABLE;
33
34 typedef enum {
35         CMD_HELP,
36         CMD_LIST,
37         CMD_MOVETO,
38         CMD_QUIT,
39         CMD_SEARCH,
40         CMD_SET,
41         CMD_SHOW
42 } COMMAND;
43
44 char            *attrs_null[] = { "0.10", NULL };
45 char            *credentials;
46 char            default_dn[DN_MAXLEN];
47 char            *hostname = "127.0.0.1";
48 LDAP            *ld;
49 extern char     *optarg;
50 extern int      opterr;
51 extern int      optind;
52 int                     option;
53 int                     portnum = LDAP_PORT;
54 char            *progname;
55 char            true_filter[] = "objectClass=*";        /* Always succeeds */
56 char            *username;
57
58 int                     cmd_help(char **cmdargv, int cmdargc);
59 int                     cmd_list(char **cmdargv, int cmdargc);
60 int                     cmd_moveto(char **cmdargv, int cmdargc);
61 int                     cmd_quit(char **cmdargv, int cmdargc);
62 int                     cmd_search(char **cmdargv, int cmdargc);
63 int                     cmd_set(char **cmdargv, int cmdargc);
64 int                     cmd_show(char **cmdargv, int cmdargc);
65 char            *make_dn(char *dn, int relative);
66 char            *skip_to_char(register char *s, register int c);
67 char            *skip_to_whitespace(register char *s);
68 char            *skip_whitespace(register char *s);
69 FILE            *user_tailor(void);
70
71 static char     *binary_attrs[] = { "audio", "jpegPhoto", "personalSignature", "photo" };
72
73 CMDTABLE        cmdtable[] = {
74         "help"  , cmd_help  , "[command]",
75         "list"  , cmd_list  , "[RDN-or-DN] [-absolute]",
76         "moveto", cmd_moveto, "[RDN-or-DN] [-absolute]",
77         "quit"  , cmd_quit  , "",
78         "search", cmd_search, "<filter> [-object RDN-or-DN] [-absolute]\n\t\t[-scope base|onelevel|subtree]",
79         "set"   , cmd_set   , "[-aliasderef never|search|find|always] [-sizelimit N] [-timelimit seconds]",
80         "show"  , cmd_show  , "[RDN-or-DN] [-absolute]"
81 };
82
83
84 int bind_user(void)
85 {
86         if (ldap_simple_bind_s(ld, username, credentials) != LDAP_SUCCESS) {
87                 ldap_perror(ld, progname);
88                 return 0;
89         }
90         if (username)
91                 printf("Bound to ldap server as `%s' (%s authentication)\n", username,
92                            credentials ? "simple" : "no");
93         else
94                 puts("Bound anonymously to ldap server");
95
96         return 1;
97 }
98
99 int cmd_help(char **cmdargv, int cmdargc)
100 {
101         int             i;
102
103         if (cmdargc == 2) {
104                 for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
105                         if (strncasecmp(cmdargv[1], cmdtable[i].cmd, strlen(cmdargv[1])) == 0) {
106                                 show_syntax(i);
107                                 return 0;
108                         }
109                 cmdargc = 1;    /* Command not found - make it display the list of commands */
110         }
111
112         if (cmdargc == 1) {
113                 puts("\nType 'help <command>' for help on a particular command.\n\n"
114                          "Supported commands are:");
115                 for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
116                         printf("  %s\n", cmdtable[i].cmd);
117                 puts("\nArguments to commands are separated by whitespace.  Single (')\n"
118                          "or double (\") quotes must be used around arguments that contain\n"
119                          "embedded whitespace characters.\n");
120         } else
121                 show_syntax(CMD_HELP);
122
123         return 0;
124 }
125
126 int cmd_list(char **cmdargv, int cmdargc)
127 {
128         char            *dn      = NULL;
129         int                     errflag  = 0;
130         int                     i;
131         static char     *opts[]  = { "absolute" };
132         int                     relative = 1;
133         LDAPMessage     *result;
134
135         for (i = 1; i < cmdargc; i++) {
136                 if (cmdargv[i][0] == '-') {
137                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
138                         case 0:
139                                 relative = 0;
140                                 break;
141                         default:
142                                 errflag = 1;
143                         }
144                 } else {
145                         if (dn)
146                                 errflag = 1;
147                         else
148                                 dn = cmdargv[i];
149                 }
150         }
151
152         if (errflag) {
153                 show_syntax(CMD_LIST);
154                 return 0;
155         }
156
157         if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_ONELEVEL,
158                                         true_filter, attrs_null, 1) == -1) {
159                 ldap_perror(ld, progname);
160                 return 0;
161         }
162
163         if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
164                 ldap_perror(ld, progname);
165                 return 0;
166         }
167
168         display_search_results(result);
169                 
170         return 0;
171 }
172
173 int cmd_moveto(char **cmdargv, int cmdargc)
174 {
175         char            *dn      = NULL;
176         int                     errflag  = 0;
177         char            **exploded_dn;
178         int                     i;
179         static char     *opts[]  = { "absolute" };
180         int                     relative = 1;
181
182         for (i = 1; i < cmdargc; i++) {
183                 if (cmdargv[i][0] == '-') {
184                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
185                         case 0:
186                                 relative = 0;
187                                 break;
188                         default:
189                                 errflag = 1;
190                         }
191                 } else {
192                         if (dn)
193                                 errflag = 1;
194                         else
195                                 dn = cmdargv[i];
196                 }
197         }
198
199         if (errflag) {
200                 show_syntax(CMD_MOVETO);
201                 return 0;
202         }
203
204         if (dn) {
205                 if (is_whitespace(dn))
206                         default_dn[0] = 0;
207                 else {
208                         if (strcmp(dn, "..") == 0) {
209                                 /* Move up one level */
210                                 if (exploded_dn = ldap_explode_dn(default_dn, 0)) {
211                                         if (exploded_dn[0]) {
212                                                 char    **rdn;
213
214                                                 default_dn[0] = 0;
215                                                 for (rdn = exploded_dn + 1; *rdn; rdn++) {
216                                                         if (default_dn[0])
217                                                                 strcat(default_dn, ", ");
218                                                         strcat(default_dn, *rdn);
219                                                 }
220                                         }
221                                         ldap_value_free(exploded_dn);
222                                 }
223                         } else {
224                                 /* Use ldap_explode_dn() to parse the string & test its syntax */
225                                 if (exploded_dn = ldap_explode_dn(dn, 1)) {
226                                         if (relative  &&  !is_whitespace(default_dn)) {
227                                                 char    buf[DN_MAXLEN];
228
229                                                 strcpy(default_dn, strcat(strcat(strcpy(buf, dn), ", "), default_dn));
230                                         } else
231                                                 strcpy(default_dn, dn);
232                                         ldap_value_free(exploded_dn);
233                                 } else
234                                         puts("Invalid distinguished name.");
235                         }
236                 }
237         }
238
239         printf("Distinguished name suffix is `%s'\n", default_dn);
240
241         return 0;
242 }
243
244 int cmd_quit(char **cmdargv, int cmdargc)
245 {
246         return 1;
247 }
248
249 int cmd_search(char **cmdargv, int cmdargc)
250 {
251         char            *dn           = NULL;
252         int                     errflag       = 0;
253         char            *filter       = NULL;
254         int                     i, j;
255         static char     *opts[]       = { "absolute", "object", "scope" };
256         int                     relative      = 1;
257         LDAPMessage     *result;
258         static char     *scope_opts[] = { "base", "onelevel", "subtree" };
259         static int      scope_vals[]  = { LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE };
260         static int      search_scope  = LDAP_SCOPE_ONELEVEL;
261
262         for (i = 1; i < cmdargc; i++) {
263                 if (cmdargv[i][0] == '-') {
264                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
265                         case 0:
266                                 relative = 0;
267                                 break;
268                         case 1:
269                                 if (++i < cmdargc)
270                                         dn = cmdargv[i];
271                                 else
272                                         errflag = 1;
273                                 break;
274                         case 2:
275                                 if ((++i < cmdargc)  &&
276                                         (j = table_lookup(cmdargv[i], scope_opts, sizeof(scope_opts) / sizeof(scope_opts[0]))) >= 0)
277                                         search_scope = scope_vals[j];
278                                 else
279                                         errflag = 1;
280                                 break;
281                         default:
282                                 errflag = 1;
283                         }
284                 } else {
285                         if (filter)
286                                 errflag = 1;
287                         else
288                                 filter = cmdargv[i];
289                 }
290         }
291
292         if (errflag  ||  !filter) {
293                 show_syntax(CMD_SEARCH);
294                 return 0;
295         }
296
297         if (ldap_search(ld, make_dn(dn, relative), search_scope, filter, attrs_null, 0) == -1) {
298                 ldap_perror(ld, progname);
299                 return 0;
300         }
301
302         if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
303                 ldap_perror(ld, progname);
304                 return 0;
305         }
306
307         display_search_results(result);
308                 
309         return 0;
310 }
311
312 int cmd_set(char **cmdargv, int cmdargc)
313 {
314         static char     *alias_opts[] = { "never", "search", "find", "always" };
315         int                     errflag       = 0;
316         int                     i, j;
317         static char     *opts[]       = { "aliasderef", "sizelimit", "timelimit" };
318
319         for (i = 1; i < cmdargc; i++) {
320                 if (cmdargv[i][0] == '-') {
321                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
322                         case 0:
323                                 if ((++i < cmdargc)  &&
324                                         (j = table_lookup(cmdargv[i], alias_opts, sizeof(alias_opts) / sizeof(alias_opts[0]))) >= 0)
325                                         ldap_set_option(ld, LDAP_OPT_DEREF, &j);
326                                 else
327                                         errflag = 1;
328                                 break;
329                         case 1:
330                                 if (++i < cmdargc) {
331                                         j = atoi(cmdargv[i]);
332                                         ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &j);
333                                 } else
334                                         errflag = 1;
335                                 break;
336                         case 2:
337                                 if (++i < cmdargc) {
338                                         j = atoi(cmdargv[i]);
339                                         ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &j);
340                                 } else
341                                         errflag = 1;
342                                 break;
343                         default:
344                                 errflag = 1;
345                         }
346                 } else
347                         errflag = 1;
348         }
349
350         if (errflag)
351                 show_syntax(CMD_SET);
352         else {
353                 int opt_a, opt_s, opt_t;
354                 ldap_get_option(ld, LDAP_OPT_DEREF, &opt_a);
355                 ldap_get_option(ld, LDAP_OPT_SIZELIMIT, &opt_s);
356                 ldap_get_option(ld, LDAP_OPT_TIMELIMIT, &opt_t);
357                 printf("Alias dereferencing is %s, Sizelimit is %d entr%s, Timelimit is %d second%s.\n",
358                        alias_opts[opt_a],
359                        opt_s, opt_s == 1 ? "y" : "ies",
360                        opt_t, opt_t == 1 ? ""  : "s");
361         }
362
363         return 0;
364 }
365
366 int cmd_show(char **cmdargv, int cmdargc)
367 {
368         char            *dn      = NULL;
369         LDAPMessage     *entry;
370         int                     errflag  = 0;
371         int                     i;
372         static char     *opts[]  = { "absolute" };
373         int                     relative = 1;
374         LDAPMessage     *result;
375
376         for (i = 1; i < cmdargc; i++) {
377                 if (cmdargv[i][0] == '-') {
378                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
379                         case 0:
380                                 relative = 0;
381                                 break;
382                         default:
383                                 errflag = 1;
384                         }
385                 } else {
386                         if (dn)
387                                 errflag = 1;
388                         else
389                                 dn = cmdargv[i];
390                 }
391         }
392
393         if (errflag) {
394                 show_syntax(CMD_SHOW);
395                 return 0;
396         }
397
398         if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_BASE, true_filter, NULL, 0) == -1) {
399                 ldap_perror(ld, progname);
400                 return 0;
401         }
402
403         if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
404                 ldap_perror(ld, progname);
405                 return 0;
406         }
407
408         display_search_results(result);
409                 
410         return 0;
411 }
412
413 display_search_results(LDAPMessage *result)
414 {
415         BerElement      *cookie;
416         int                     i;
417         LDAPMessage     *entry;
418         int                     maxname;
419         char            *s;
420
421         for (entry = ldap_first_entry(ld, result); entry; entry = ldap_next_entry(ld, entry)) {
422                 if (s = ldap_get_dn(ld, entry)) {
423                         printf("  %s\n", s);
424                         free(s);
425                 }
426
427                 /* Make one pass to calculate the length of the longest attribute name */
428                 maxname = 0;
429                 for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie))
430                         if ((i = strlen(s)) > maxname)
431                                 maxname = i;
432
433                 /* Now print the attributes and values */
434                 for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie)) {
435                         char    **values;
436
437                         if (table_lookup(s, binary_attrs, sizeof(binary_attrs) / sizeof(binary_attrs[0])) >= 0)
438                                 continue;       /* Skip this attribute - it's binary */
439
440                         printf("    %-*s - ", maxname, s);
441
442                         /* Now print each of the values for the given attribute */
443                         if (values = ldap_get_values(ld, entry, s)) {
444                                 char    **val;
445
446                                 for (val = values; *val; ) {
447                                         char    *nl;
448                                         char    *v = *val;
449
450                                         /* Watch out for values that have embedded \n characters */
451                                         while (nl = strchr(v, '\n')) {
452                                                 *nl = 0;
453                                                 puts(v);
454                                                 v = nl + 1;
455                                                 if (*v)
456                                                         printf("    %*s", maxname + 3, "");
457                                         }
458                                         if (*v)
459                                                 puts(v);
460                                         if (*++val)
461                                                 printf("    %*s", maxname + 3, "");
462                                 }
463                                 ldap_value_free(values);
464                         } else
465                                 putchar('\n');
466                 }
467         }
468
469         if (ldap_result2error(ld, result, 0))
470                 ldap_perror(ld, progname);
471 }
472
473 int do_command(char *cmd)
474 {
475         char    *cmdargv[128];
476         int             cmdargc = 0;
477         int             i;
478
479         /* Tokenize the input command, allowing for quoting */
480         for (;;) {
481                 cmd = skip_whitespace(cmd);
482                 if (!cmd  ||  !*cmd)
483                         break;  /* end of input */
484
485                 cmdargv[cmdargc++] = cmd;
486                 if (*cmd == '\''  ||  *cmd == '"') {
487                         cmdargv[cmdargc - 1]++;         /* Skip over the opening quote */
488                         cmd = skip_to_char(cmd + 1, *cmd);
489                         if (!cmd  ||  !*cmd) {
490                                 puts("Command is missing a trailing quote");
491                                 return 0;
492                         }
493                         *cmd++ = 0;
494                 } else {
495                         cmd = skip_to_whitespace(cmd);
496                         if (cmd  &&  *cmd)
497                                 *cmd++ = 0;
498                 }
499         }
500
501 #ifdef DEBUG
502         printf("cmdargc = %d\n", cmdargc);
503         for (i = 0; i < cmdargc; i++)
504                 puts(cmdargv[i]);
505 #endif
506         
507         if (cmdargv[0][0] == '?')
508                 return cmd_help(cmdargv, cmdargc);
509
510         for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
511                 if (strncasecmp(cmdargv[0], cmdtable[i].cmd, strlen(cmdargv[0])) == 0)
512                         return (*cmdtable[i].func)(cmdargv, cmdargc);
513
514         if (!is_whitespace(cmdargv[0])) {
515                 printf("Unrecognized command - %s\n", cmdargv[0]);
516                 cmd_help(cmdargv, 1);
517         }
518
519         return 0;
520 }
521
522 void do_commands(FILE *file)
523 {
524         char    cmd_buf[BUFSIZ];
525         int             tty = isatty(fileno(file));
526
527         for (;;) {
528                 if (tty)
529                         printf("Cmd? ");
530                 if (!fgets(cmd_buf, sizeof(cmd_buf), file))
531                         break;
532                 if (do_command(cmd_buf))
533                         break;
534         }
535 }
536
537 int is_whitespace(register char *s)
538 {
539         if (!s)
540                 return 1;
541
542         while (*s  &&  isspace((unsigned char) *s))
543                 ++s;
544
545         return !*s;
546 }
547
548 int main(int argc, char **argv)
549 {
550         int             error_flag = 0;
551         FILE    *rc;
552
553         progname = argv[0];
554         while ((option = getopt(argc, argv, "h:p:u:c:d:")) != EOF)
555                 switch (option) {
556                 case 'c':
557                         credentials = optarg;
558                         break;
559                 case 'd':
560 #ifdef LDAP_DEBUG
561                         lber_debug = atoi(optarg);
562                         ldap_debug = atoi(optarg);
563 #endif
564                         break;
565                 case 'h':
566                         hostname = optarg;
567                         break;
568                 case 'p':
569                         portnum = atoi(optarg);
570                         break;
571                 case 'u':
572                         username = optarg;
573                         break;
574                 case '?':
575                         error_flag = 1;
576                 }
577
578         if (error_flag) {
579                 fprintf(stderr, "usage: %s [-h host] [-p portnumber] [-u X500UserName]\n\t[-c credentials] [-d debug-level]\n",
580                                 progname);
581                 exit(2);
582         }
583
584         rc = user_tailor();
585
586         if (!(ld = ldap_open(hostname, portnum))) {
587                 fprintf(stderr, "%s: unable to connect to server at host `%s' on port %d\n",
588                                 progname, hostname, portnum);
589                 exit(2);
590         }
591
592         if (!bind_user())
593                 return 1;
594
595         if (rc) {
596                 do_commands(rc);
597                 fclose(rc);
598         }
599         do_commands(stdin);
600
601         ldap_unbind(ld);
602
603         return 0;
604 }
605
606 char *make_dn(char *dn, int relative)
607 {
608         static char     dn_buf[DN_MAXLEN];
609         char            *s;
610
611         if (!dn)
612                 dn = "";
613
614         if (!default_dn[0]  ||  !relative)
615                 return dn;
616
617         if (!dn[0])
618                 return default_dn;
619
620         return strcat(strcat(strcpy(dn_buf, dn), ", "), default_dn);
621 }
622
623 show_syntax(int cmdnum)
624 {
625         printf("Syntax: %s %s\n", cmdtable[cmdnum].cmd, cmdtable[cmdnum].help_msg);
626 }
627
628 char *skip_to_char(register char *s, register int c)
629 {
630         if (!s)
631                 return s;
632
633         while (*s  &&  *s != c)
634                 ++s;
635
636         return s;
637 }
638
639 char *skip_to_whitespace(register char *s)
640 {
641         if (!s)
642                 return s;
643
644         while (*s  &&  !isspace((unsigned char) *s))
645                 ++s;
646
647         return s;
648 }
649
650 char *skip_whitespace(register char *s)
651 {
652         if (!s)
653                 return s;
654
655         while (*s  &&  isspace((unsigned char) *s))
656                 ++s;
657
658         return s;
659 }
660
661 int table_lookup(char *word, char **table, int table_count)
662 {
663         register int    i;
664         int                             wordlen;
665
666         if (!word  ||  !*word)
667                 return -1;
668
669         wordlen = strlen(word);
670
671         for (i = 0; i < table_count; i++)
672                 if (strncasecmp(word, table[i], wordlen) == 0)
673                         return i;
674         return -1;
675 }
676
677 FILE *user_tailor(void)
678 {
679         char    rcfile[BUFSIZ];
680
681         rcfile[0] = 0;
682
683 #ifdef unix
684         {
685 #include <pwd.h>
686                 struct passwd   *pwent;
687
688                 if (pwent = getpwuid(getuid()))
689                         strcat(strcpy(rcfile, pwent->pw_dir), "/");
690                 strcat(rcfile, ".saucerrc");
691         }
692 #else
693         strcpy(rcfile, "saucer.rc");
694 #endif
695
696         return fopen(rcfile, "r");
697 }