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