]> git.sur5r.net Git - openldap/blob - contrib/saucer/main.c
Cast `char' arguments to ctype.h functions to `unsigned char'.
[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                                         ld->ld_deref = j;
326                                 else
327                                         errflag = 1;
328                                 break;
329                         case 1:
330                                 if (++i < cmdargc)
331                                         ld->ld_sizelimit = atoi(cmdargv[i]);
332                                 else
333                                         errflag = 1;
334                                 break;
335                         case 2:
336                                 if (++i < cmdargc)
337                                         ld->ld_timelimit = atoi(cmdargv[i]);
338                                 else
339                                         errflag = 1;
340                                 break;
341                         default:
342                                 errflag = 1;
343                         }
344                 } else
345                         errflag = 1;
346         }
347
348         if (errflag)
349                 show_syntax(CMD_SET);
350         else
351                 printf("Alias dereferencing is %s, Sizelimit is %d entr%s, Timelimit is %d second%s.\n",
352                            alias_opts[ld->ld_deref],
353                            ld->ld_sizelimit, ld->ld_sizelimit == 1 ? "y" : "ies",
354                            ld->ld_timelimit, ld->ld_timelimit == 1 ? ""  : "s");
355
356         return 0;
357 }
358
359 int cmd_show(char **cmdargv, int cmdargc)
360 {
361         char            *dn      = NULL;
362         LDAPMessage     *entry;
363         int                     errflag  = 0;
364         int                     i;
365         static char     *opts[]  = { "absolute" };
366         int                     relative = 1;
367         LDAPMessage     *result;
368
369         for (i = 1; i < cmdargc; i++) {
370                 if (cmdargv[i][0] == '-') {
371                         switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
372                         case 0:
373                                 relative = 0;
374                                 break;
375                         default:
376                                 errflag = 1;
377                         }
378                 } else {
379                         if (dn)
380                                 errflag = 1;
381                         else
382                                 dn = cmdargv[i];
383                 }
384         }
385
386         if (errflag) {
387                 show_syntax(CMD_SHOW);
388                 return 0;
389         }
390
391         if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_BASE, true_filter, NULL, 0) == -1) {
392                 ldap_perror(ld, progname);
393                 return 0;
394         }
395
396         if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
397                 ldap_perror(ld, progname);
398                 return 0;
399         }
400
401         display_search_results(result);
402                 
403         return 0;
404 }
405
406 display_search_results(LDAPMessage *result)
407 {
408         BerElement      *cookie;
409         int                     i;
410         LDAPMessage     *entry;
411         int                     maxname;
412         char            *s;
413
414         for (entry = ldap_first_entry(ld, result); entry; entry = ldap_next_entry(ld, entry)) {
415                 if (s = ldap_get_dn(ld, entry)) {
416                         printf("  %s\n", s);
417                         free(s);
418                 }
419
420                 /* Make one pass to calculate the length of the longest attribute name */
421                 maxname = 0;
422                 for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie))
423                         if ((i = strlen(s)) > maxname)
424                                 maxname = i;
425
426                 /* Now print the attributes and values */
427                 for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie)) {
428                         char    **values;
429
430                         if (table_lookup(s, binary_attrs, sizeof(binary_attrs) / sizeof(binary_attrs[0])) >= 0)
431                                 continue;       /* Skip this attribute - it's binary */
432
433                         printf("    %-*s - ", maxname, s);
434
435                         /* Now print each of the values for the given attribute */
436                         if (values = ldap_get_values(ld, entry, s)) {
437                                 char    **val;
438
439                                 for (val = values; *val; ) {
440                                         char    *nl;
441                                         char    *v = *val;
442
443                                         /* Watch out for values that have embedded \n characters */
444                                         while (nl = strchr(v, '\n')) {
445                                                 *nl = 0;
446                                                 puts(v);
447                                                 v = nl + 1;
448                                                 if (*v)
449                                                         printf("    %*s", maxname + 3, "");
450                                         }
451                                         if (*v)
452                                                 puts(v);
453                                         if (*++val)
454                                                 printf("    %*s", maxname + 3, "");
455                                 }
456                                 ldap_value_free(values);
457                         } else
458                                 putchar('\n');
459                 }
460         }
461
462         if (ldap_result2error(ld, result, 0))
463                 ldap_perror(ld, progname);
464 }
465
466 int do_command(char *cmd)
467 {
468         char    *cmdargv[128];
469         int             cmdargc = 0;
470         int             i;
471
472         /* Tokenize the input command, allowing for quoting */
473         for (;;) {
474                 cmd = skip_whitespace(cmd);
475                 if (!cmd  ||  !*cmd)
476                         break;  /* end of input */
477
478                 cmdargv[cmdargc++] = cmd;
479                 if (*cmd == '\''  ||  *cmd == '"') {
480                         cmdargv[cmdargc - 1]++;         /* Skip over the opening quote */
481                         cmd = skip_to_char(cmd + 1, *cmd);
482                         if (!cmd  ||  !*cmd) {
483                                 puts("Command is missing a trailing quote");
484                                 return 0;
485                         }
486                         *cmd++ = 0;
487                 } else {
488                         cmd = skip_to_whitespace(cmd);
489                         if (cmd  &&  *cmd)
490                                 *cmd++ = 0;
491                 }
492         }
493
494 #ifdef DEBUG
495         printf("cmdargc = %d\n", cmdargc);
496         for (i = 0; i < cmdargc; i++)
497                 puts(cmdargv[i]);
498 #endif
499         
500         if (cmdargv[0][0] == '?')
501                 return cmd_help(cmdargv, cmdargc);
502
503         for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
504                 if (strncasecmp(cmdargv[0], cmdtable[i].cmd, strlen(cmdargv[0])) == 0)
505                         return (*cmdtable[i].func)(cmdargv, cmdargc);
506
507         if (!is_whitespace(cmdargv[0])) {
508                 printf("Unrecognized command - %s\n", cmdargv[0]);
509                 cmd_help(cmdargv, 1);
510         }
511
512         return 0;
513 }
514
515 void do_commands(FILE *file)
516 {
517         char    cmd_buf[BUFSIZ];
518         int             tty = isatty(fileno(file));
519
520         for (;;) {
521                 if (tty)
522                         printf("Cmd? ");
523                 if (!fgets(cmd_buf, sizeof(cmd_buf), file))
524                         break;
525                 if (do_command(cmd_buf))
526                         break;
527         }
528 }
529
530 int is_whitespace(register char *s)
531 {
532         if (!s)
533                 return 1;
534
535         while (*s  &&  isspace((unsigned char) *s))
536                 ++s;
537
538         return !*s;
539 }
540
541 int main(int argc, char **argv)
542 {
543         int             error_flag = 0;
544         FILE    *rc;
545
546         progname = argv[0];
547         while ((option = getopt(argc, argv, "h:p:u:c:d:")) != EOF)
548                 switch (option) {
549                 case 'c':
550                         credentials = optarg;
551                         break;
552                 case 'd':
553 #ifdef LDAP_DEBUG
554                         lber_debug = atoi(optarg);
555                         ldap_debug = atoi(optarg);
556 #endif
557                         break;
558                 case 'h':
559                         hostname = optarg;
560                         break;
561                 case 'p':
562                         portnum = atoi(optarg);
563                         break;
564                 case 'u':
565                         username = optarg;
566                         break;
567                 case '?':
568                         error_flag = 1;
569                 }
570
571         if (error_flag) {
572                 fprintf(stderr, "usage: %s [-h host] [-p portnumber] [-u X500UserName]\n\t[-c credentials] [-d debug-level]\n",
573                                 progname);
574                 exit(2);
575         }
576
577         rc = user_tailor();
578
579         if (!(ld = ldap_open(hostname, portnum))) {
580                 fprintf(stderr, "%s: unable to connect to server at host `%s' on port %d\n",
581                                 progname, hostname, portnum);
582                 exit(2);
583         }
584
585         if (!bind_user())
586                 return 1;
587
588         if (rc) {
589                 do_commands(rc);
590                 fclose(rc);
591         }
592         do_commands(stdin);
593
594         ldap_unbind(ld);
595
596         return 0;
597 }
598
599 char *make_dn(char *dn, int relative)
600 {
601         static char     dn_buf[DN_MAXLEN];
602         char            *s;
603
604         if (!dn)
605                 dn = "";
606
607         if (!default_dn[0]  ||  !relative)
608                 return dn;
609
610         if (!dn[0])
611                 return default_dn;
612
613         return strcat(strcat(strcpy(dn_buf, dn), ", "), default_dn);
614 }
615
616 show_syntax(int cmdnum)
617 {
618         printf("Syntax: %s %s\n", cmdtable[cmdnum].cmd, cmdtable[cmdnum].help_msg);
619 }
620
621 char *skip_to_char(register char *s, register int c)
622 {
623         if (!s)
624                 return s;
625
626         while (*s  &&  *s != c)
627                 ++s;
628
629         return s;
630 }
631
632 char *skip_to_whitespace(register char *s)
633 {
634         if (!s)
635                 return s;
636
637         while (*s  &&  !isspace((unsigned char) *s))
638                 ++s;
639
640         return s;
641 }
642
643 char *skip_whitespace(register char *s)
644 {
645         if (!s)
646                 return s;
647
648         while (*s  &&  isspace((unsigned char) *s))
649                 ++s;
650
651         return s;
652 }
653
654 int table_lookup(char *word, char **table, int table_count)
655 {
656         register int    i;
657         int                             wordlen;
658
659         if (!word  ||  !*word)
660                 return -1;
661
662         wordlen = strlen(word);
663
664         for (i = 0; i < table_count; i++)
665                 if (strncasecmp(word, table[i], wordlen) == 0)
666                         return i;
667         return -1;
668 }
669
670 FILE *user_tailor(void)
671 {
672         char    rcfile[BUFSIZ];
673
674         rcfile[0] = 0;
675
676 #ifdef unix
677         {
678 #include <pwd.h>
679                 struct passwd   *pwent;
680
681                 if (pwent = getpwuid(getuid()))
682                         strcat(strcpy(rcfile, pwent->pw_dir), "/");
683                 strcat(rcfile, ".saucerrc");
684         }
685 #else
686         strcpy(rcfile, "saucer.rc");
687 #endif
688
689         return fopen(rcfile, "r");
690 }