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