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