openldap/contrib/saucer/main.c

753 lines
16 KiB
C
Raw Normal View History

1998-08-09 08:43:13 +08:00
/*
* Copyright (c) 1994, Strata Software Limited, Ottawa, Ontario, Canada.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to Eric Rosenquist and Strata Software Limited. The SSL name
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided "as is" without express or implied warranty.
*
*
* 'saucer' LDAP command-line client source code.
*
* Author: Eric Rosenquist, 1994.
*
* 07-Mar-1999 readline support added: O. Steffensen (oddbjorn@tricknology.org)
1998-08-09 08:43:13 +08:00
*/
#include "portable.h"
1998-08-09 08:43:13 +08:00
#include <stdio.h>
1999-06-03 08:37:44 +08:00
#include <ac/stdlib.h>
#ifdef HAVE_READLINE
# include <readline/readline.h>
# ifdef HAVE_READLINE_HISTORY_H
# include <readline/history.h>
# endif
#endif
#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/unistd.h>
1998-08-09 08:43:13 +08:00
#include <lber.h>
#include <ldap.h>
#include <ldap_log.h>
1998-08-09 08:43:13 +08:00
#define DN_MAXLEN 4096
typedef struct {
const char *cmd;
int (*func) (char **, int);
const char *help_msg;
1998-08-09 08:43:13 +08:00
} CMDTABLE;
typedef enum {
CMD_HELP,
CMD_LIST,
CMD_MOVETO,
CMD_QUIT,
CMD_SEARCH,
CMD_SET,
CMD_SHOW
} COMMAND;
char *attrs_null[] = { "0.10", NULL };
char *credentials;
char default_dn[DN_MAXLEN];
char *hostname = "127.0.0.1";
LDAP *ld;
extern char *optarg;
extern int opterr;
extern int optind;
int option;
int portnum = LDAP_PORT;
char *progname;
2000-04-12 16:38:01 +08:00
char true_filter[] = "(objectClass=*)"; /* Always succeeds */
1998-08-09 08:43:13 +08:00
char *username;
int cmd_help(char **cmdargv, int cmdargc);
int cmd_list(char **cmdargv, int cmdargc);
int cmd_moveto(char **cmdargv, int cmdargc);
int cmd_quit(char **cmdargv, int cmdargc);
int cmd_search(char **cmdargv, int cmdargc);
int cmd_set(char **cmdargv, int cmdargc);
int cmd_show(char **cmdargv, int cmdargc);
int bind_user(void);
void display_search_results(LDAPMessage *result);
int do_command(char *cmd);
void do_commands(FILE *file);
int is_whitespace(register char *s);
1998-08-09 08:43:13 +08:00
char *make_dn(char *dn, int relative);
void show_syntax(unsigned int cmdnum);
1998-08-09 08:43:13 +08:00
char *skip_to_char(register char *s, register int c);
char *skip_to_whitespace(register char *s);
char *skip_whitespace(register char *s);
int table_lookup(const char *, const char *const *, int);
1998-08-09 08:43:13 +08:00
FILE *user_tailor(void);
static const char *const binary_attrs[] = {
"audio", "jpegPhoto", "personalSignature", "photo"
};
1998-08-09 08:43:13 +08:00
const CMDTABLE cmdtable[] = {
1998-08-09 08:43:13 +08:00
"help" , cmd_help , "[command]",
"list" , cmd_list , "[RDN-or-DN] [-absolute]",
"moveto", cmd_moveto, "[RDN-or-DN] [-absolute]",
"quit" , cmd_quit , "",
"search", cmd_search, "<filter> [-object RDN-or-DN] [-absolute]\n\t\t[-scope base|onelevel|subtree]",
"set" , cmd_set , "[-aliasderef never|search|find|always] [-sizelimit N] [-timelimit seconds]",
"show" , cmd_show , "[RDN-or-DN] [-absolute]"
};
int bind_user(void)
{
if (ldap_simple_bind_s(ld, username, credentials) != LDAP_SUCCESS) {
ldap_perror(ld, progname);
return 0;
}
if (username)
printf("Bound to ldap server as `%s' (%s authentication)\n", username,
credentials ? "simple" : "no");
else
puts("Bound anonymously to ldap server");
return 1;
}
int cmd_help(char **cmdargv, int cmdargc)
{
unsigned int i;
1998-08-09 08:43:13 +08:00
if (cmdargc == 2) {
for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
if (strncasecmp(cmdargv[1], cmdtable[i].cmd, strlen(cmdargv[1])) == 0) {
show_syntax(i);
return 0;
}
cmdargc = 1; /* Command not found - make it display the list of commands */
}
if (cmdargc == 1) {
puts("\nType 'help <command>' for help on a particular command.\n\n"
"Supported commands are:");
for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
printf(" %s\n", cmdtable[i].cmd);
puts("\nArguments to commands are separated by whitespace. Single (')\n"
"or double (\") quotes must be used around arguments that contain\n"
"embedded whitespace characters.\n");
} else
show_syntax(CMD_HELP);
return 0;
}
int cmd_list(char **cmdargv, int cmdargc)
{
char *dn = NULL;
int errflag = 0;
int i;
static const char *const opts[] = { "absolute" };
1998-08-09 08:43:13 +08:00
int relative = 1;
LDAPMessage *result;
for (i = 1; i < cmdargc; i++) {
if (cmdargv[i][0] == '-') {
switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
case 0:
relative = 0;
break;
default:
errflag = 1;
}
} else {
if (dn)
errflag = 1;
else
dn = cmdargv[i];
}
}
if (errflag) {
show_syntax(CMD_LIST);
return 0;
}
if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_ONELEVEL,
true_filter, attrs_null, 1) == -1) {
ldap_perror(ld, progname);
return 0;
}
if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
ldap_perror(ld, progname);
return 0;
}
display_search_results(result);
return 0;
}
int cmd_moveto(char **cmdargv, int cmdargc)
{
char *dn = NULL;
int errflag = 0;
char **exploded_dn;
int i;
static const char *const opts[] = { "absolute" };
1998-08-09 08:43:13 +08:00
int relative = 1;
for (i = 1; i < cmdargc; i++) {
if (cmdargv[i][0] == '-') {
switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
case 0:
relative = 0;
break;
default:
errflag = 1;
}
} else {
if (dn)
errflag = 1;
else
dn = cmdargv[i];
}
}
if (errflag) {
show_syntax(CMD_MOVETO);
return 0;
}
if (dn) {
if (is_whitespace(dn))
default_dn[0] = 0;
else {
if (strcmp(dn, "..") == 0) {
/* Move up one level */
if (exploded_dn = ldap_explode_dn(default_dn, 0)) {
if (exploded_dn[0]) {
char **rdn;
default_dn[0] = 0;
for (rdn = exploded_dn + 1; *rdn; rdn++) {
if (default_dn[0])
strcat(default_dn, ", ");
strcat(default_dn, *rdn);
}
}
ldap_value_free(exploded_dn);
}
} else {
/* Use ldap_explode_dn() to parse the string & test its syntax */
if (exploded_dn = ldap_explode_dn(dn, 1)) {
if (relative && !is_whitespace(default_dn)) {
char buf[DN_MAXLEN];
strcpy(default_dn, strcat(strcat(strcpy(buf, dn), ", "), default_dn));
} else
strcpy(default_dn, dn);
ldap_value_free(exploded_dn);
} else
puts("Invalid distinguished name.");
}
}
}
printf("Distinguished name suffix is `%s'\n", default_dn);
return 0;
}
int cmd_quit(char **cmdargv, int cmdargc)
{
return 1;
}
int cmd_search(char **cmdargv, int cmdargc)
{
char *dn = NULL;
int errflag = 0;
char *filter = NULL;
int i, j;
static const char *const opts[] = { "absolute", "object", "scope" };
1998-08-09 08:43:13 +08:00
int relative = 1;
LDAPMessage *result;
static const char *const scope_opts[]= { "base","onelevel","subtree" };
static const int scope_vals[] = { LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE };
1998-08-09 08:43:13 +08:00
static int search_scope = LDAP_SCOPE_ONELEVEL;
for (i = 1; i < cmdargc; i++) {
if (cmdargv[i][0] == '-') {
switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
case 0:
relative = 0;
break;
case 1:
if (++i < cmdargc)
dn = cmdargv[i];
else
errflag = 1;
break;
case 2:
if ((++i < cmdargc) &&
(j = table_lookup(cmdargv[i], scope_opts, sizeof(scope_opts) / sizeof(scope_opts[0]))) >= 0)
search_scope = scope_vals[j];
else
errflag = 1;
break;
default:
errflag = 1;
}
} else {
if (filter)
errflag = 1;
else
filter = cmdargv[i];
}
}
if (errflag || !filter) {
show_syntax(CMD_SEARCH);
return 0;
}
if (ldap_search(ld, make_dn(dn, relative), search_scope, filter, attrs_null, 0) == -1) {
ldap_perror(ld, progname);
return 0;
}
if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
ldap_perror(ld, progname);
return 0;
}
display_search_results(result);
return 0;
}
int cmd_set(char **cmdargv, int cmdargc)
{
static const char *const alias_opts[] = {
"never", "search", "find", "always"
};
1998-08-09 08:43:13 +08:00
int errflag = 0;
int i, j;
static const char *const opts[] = {
"aliasderef", "sizelimit", "timelimit"
};
1998-08-09 08:43:13 +08:00
for (i = 1; i < cmdargc; i++) {
if (cmdargv[i][0] == '-') {
switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
case 0:
if ((++i < cmdargc) &&
(j = table_lookup(cmdargv[i], alias_opts, sizeof(alias_opts) / sizeof(alias_opts[0]))) >= 0)
ldap_set_option(ld, LDAP_OPT_DEREF, &j);
1998-08-09 08:43:13 +08:00
else
errflag = 1;
break;
case 1:
if (++i < cmdargc) {
j = atoi(cmdargv[i]);
ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &j);
} else
1998-08-09 08:43:13 +08:00
errflag = 1;
break;
case 2:
if (++i < cmdargc) {
j = atoi(cmdargv[i]);
ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &j);
} else
1998-08-09 08:43:13 +08:00
errflag = 1;
break;
default:
errflag = 1;
}
} else
errflag = 1;
}
if (errflag)
show_syntax(CMD_SET);
else {
int opt_a, opt_s, opt_t;
ldap_get_option(ld, LDAP_OPT_DEREF, &opt_a);
ldap_get_option(ld, LDAP_OPT_SIZELIMIT, &opt_s);
ldap_get_option(ld, LDAP_OPT_TIMELIMIT, &opt_t);
1998-08-09 08:43:13 +08:00
printf("Alias dereferencing is %s, Sizelimit is %d entr%s, Timelimit is %d second%s.\n",
alias_opts[opt_a],
opt_s, opt_s == 1 ? "y" : "ies",
opt_t, opt_t == 1 ? "" : "s");
}
1998-08-09 08:43:13 +08:00
return 0;
}
int cmd_show(char **cmdargv, int cmdargc)
{
char *dn = NULL;
int errflag = 0;
int i;
static const char *const opts[] = { "absolute" };
1998-08-09 08:43:13 +08:00
int relative = 1;
LDAPMessage *result;
for (i = 1; i < cmdargc; i++) {
if (cmdargv[i][0] == '-') {
switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
case 0:
relative = 0;
break;
default:
errflag = 1;
}
} else {
if (dn)
errflag = 1;
else
dn = cmdargv[i];
}
}
if (errflag) {
show_syntax(CMD_SHOW);
return 0;
}
if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_BASE, true_filter, NULL, 0) == -1) {
ldap_perror(ld, progname);
return 0;
}
if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
ldap_perror(ld, progname);
return 0;
}
display_search_results(result);
return 0;
}
void display_search_results(LDAPMessage *result)
1998-08-09 08:43:13 +08:00
{
BerElement *cookie;
int i;
LDAPMessage *entry;
int maxname;
char *s;
for (entry = ldap_first_entry(ld, result); entry; entry = ldap_next_entry(ld, entry)) {
if (s = ldap_get_dn(ld, entry)) {
printf(" %s\n", s);
1999-03-28 00:51:05 +08:00
ldap_memfree(s);
1998-08-09 08:43:13 +08:00
}
/* Make one pass to calculate the length of the longest attribute name */
maxname = 0;
for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie))
if ((i = strlen(s)) > maxname)
maxname = i;
/* Now print the attributes and values */
for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie)) {
char **values;
if (table_lookup(s, binary_attrs, sizeof(binary_attrs) / sizeof(binary_attrs[0])) >= 0)
continue; /* Skip this attribute - it's binary */
printf(" %-*s - ", maxname, s);
/* Now print each of the values for the given attribute */
if (values = ldap_get_values(ld, entry, s)) {
char **val;
for (val = values; *val; ) {
char *nl;
char *v = *val;
/* Watch out for values that have embedded \n characters */
while (nl = strchr(v, '\n')) {
*nl = 0;
puts(v);
v = nl + 1;
if (*v)
printf(" %*s", maxname + 3, "");
}
if (*v)
puts(v);
if (*++val)
printf(" %*s", maxname + 3, "");
}
ldap_value_free(values);
} else
putchar('\n');
}
}
if (ldap_result2error(ld, result, 0))
ldap_perror(ld, progname);
}
int do_command(char *cmd)
{
char *cmdargv[128];
int cmdargc = 0;
int i;
/* Tokenize the input command, allowing for quoting */
for (;;) {
cmd = skip_whitespace(cmd);
if (!cmd || !*cmd)
break; /* end of input */
cmdargv[cmdargc++] = cmd;
if (*cmd == '\'' || *cmd == '"') {
cmdargv[cmdargc - 1]++; /* Skip over the opening quote */
cmd = skip_to_char(cmd + 1, *cmd);
if (!cmd || !*cmd) {
puts("Command is missing a trailing quote");
return 0;
}
*cmd++ = 0;
} else {
cmd = skip_to_whitespace(cmd);
if (cmd && *cmd)
*cmd++ = 0;
}
}
#ifdef DEBUG
printf("cmdargc = %d\n", cmdargc);
for (i = 0; i < cmdargc; i++)
puts(cmdargv[i]);
#endif
if (cmdargv[0][0] == '?')
return cmd_help(cmdargv, cmdargc);
for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
if (strncasecmp(cmdargv[0], cmdtable[i].cmd, strlen(cmdargv[0])) == 0)
return (*cmdtable[i].func)(cmdargv, cmdargc);
if (!is_whitespace(cmdargv[0])) {
printf("Unrecognized command - %s\n", cmdargv[0]);
cmd_help(cmdargv, 1);
}
return 0;
}
void do_commands(FILE *file)
{
char cmd_buf[BUFSIZ];
int tty = isatty(fileno(file));
char *buf = cmd_buf;
int status;
1998-08-09 08:43:13 +08:00
for (;;) {
if (tty)
{
char prompt[40];
sprintf(prompt, (strlen(default_dn) < 18
? "saucer dn=%s> "
: "saucer dn=%.15s..> "), default_dn);
#ifndef HAVE_READLINE
fputs (prompt, stdout);
#else
buf = readline (prompt);
if (!buf)
break;
add_history (buf);
#endif
}
#ifdef HAVE_READLINE
else
#endif
{
if (!fgets(cmd_buf, sizeof(cmd_buf), file))
break;
}
status = do_command(buf);
#ifdef HAVE_READLINE
if (tty)
free(buf);
#endif
if (status)
1998-08-09 08:43:13 +08:00
break;
}
}
int is_whitespace(register char *s)
{
if (!s)
return 1;
while (*s && isspace((unsigned char) *s))
1998-08-09 08:43:13 +08:00
++s;
return !*s;
}
int main(int argc, char **argv)
{
int error_flag = 0;
int tmp;
1998-08-09 08:43:13 +08:00
FILE *rc;
progname = argv[0];
while ((option = getopt(argc, argv, "h:p:u:c:d:")) != EOF)
switch (option) {
case 'c':
credentials = optarg;
break;
case 'd':
#ifdef LDAP_DEBUG
tmp = atoi(optarg);
Vienna Bulk Commit This commit includes many changes. All changes compile under NT but have not been tested under UNIX. A Summary of changes (likely incomplete): NT changes: Removed lint. Clean up configuration support for "Debug", "Release", "SDebug", and "SRelease" configurations. Share output directories for clients, libraries, and slapd. (maybe they should be combined further and moved to build/{,S}{Debug,Release}). Enable threading when _MT is defined. Enable debuging when _DEBUG is defined. Disable setting of NDEBUG under Release/SRelease. Asserts are disabled in <ac/assert.h> when LDAP_DEBUG is not defined. Added 'build/main.dsp' Master project. Removed non-slapd projects from slapd.dsp (see main.dsp). Removed replaced many uses of _WIN32 macro with feature based macros. ldap_cdefs.h changes #define LDAP_CONST const (see below) #define LDAP_F(type) LDAP_F_PRE type LDAP_F_POST To allow specifiers to be added before and after the type declaration. (For DLL handling) LBER/LDAP changes Namespace changes: s/lber_/ber_/ for here and there. s/NAME_ERROR/LDAP_NAME_ERROR/g Deleted NULLMSG and other NULL* macros for namespace reasons. "const" libraries. Installed headers (ie: lber.h, ldap.h) use LDAP_CONST macro. Normally set to 'const' when __STDC__. Can be set externally to enable/disable 'constification' of external interface. Internal interface always uses 'const'. Did not fix warnings in -lldif (in lieu of new LDIF parser). Added _ext API implementations (excepting search and bind). Need to implement ldap_int_get_controls() for reponses with controls. Added numberous assert() checks. LDAP_R _MT defines HAVE_NT_THREADS Added numberous assert() checks. Changed ldap_pthread_t back to unsigned long. Used cast to HANDLE in _join(). LDBM Replaced _WIN32 with HAVE_SYSLOG ud Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). slapd Made connection sockbuf field a pointer to a sockbuf. This removed slap.h dependency on lber-int.h. lber-int.h now only included by those files needing to mess with the sockbuf. Used ber_* functions/macros to access sockbuf internals whenever possible. Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). Removed FD_SET unsigned lint slapd/tools Used EXEEXT to added ".exe" to routines. Need to define EXEEXT under UNIX. ldappasswd Added ldappasswd.dsp. Ported to NT. Used getpid() to seed rand(). nt_debug Minor cleanup. Added "portable.h" include and used <ac/*.h> where appropriate. Added const to char* format argument.
1999-05-19 09:12:33 +08:00
ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &tmp);
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &tmp);
1998-08-09 08:43:13 +08:00
#endif
break;
case 'h':
hostname = optarg;
break;
case 'p':
portnum = atoi(optarg);
break;
case 'u':
username = optarg;
break;
case '?':
error_flag = 1;
}
if (error_flag) {
fprintf(stderr, "usage: %s [-h host] [-p portnumber] [-u X500UserName]\n\t[-c credentials] [-d debug-level]\n",
progname);
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
rc = user_tailor();
if (!(ld = ldap_init(hostname, portnum))) {
fprintf(stderr, "%s: unable to initialize LDAP session (%s:%d)\n",
1998-08-09 08:43:13 +08:00
progname, hostname, portnum);
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
if (!bind_user())
return 1;
if (rc) {
do_commands(rc);
fclose(rc);
}
do_commands(stdin);
ldap_unbind(ld);
return 0;
}
char *make_dn(char *dn, int relative)
{
static char dn_buf[DN_MAXLEN];
if (!dn)
dn = "";
if (!default_dn[0] || !relative)
return dn;
if (!dn[0])
return default_dn;
return strcat(strcat(strcpy(dn_buf, dn), ", "), default_dn);
}
void show_syntax(unsigned int cmdnum)
1998-08-09 08:43:13 +08:00
{
printf("Syntax: %s %s\n", cmdtable[cmdnum].cmd, cmdtable[cmdnum].help_msg);
}
char *skip_to_char(register char *s, register int c)
{
if (!s)
return s;
while (*s && *s != c)
++s;
return s;
}
char *skip_to_whitespace(register char *s)
{
if (!s)
return s;
while (*s && !isspace((unsigned char) *s))
1998-08-09 08:43:13 +08:00
++s;
return s;
}
char *skip_whitespace(register char *s)
{
if (!s)
return s;
while (*s && isspace((unsigned char) *s))
1998-08-09 08:43:13 +08:00
++s;
return s;
}
int table_lookup(const char *word, const char *const *table, int table_count)
1998-08-09 08:43:13 +08:00
{
register int i;
int wordlen;
if (!word || !*word)
return -1;
wordlen = strlen(word);
for (i = 0; i < table_count; i++)
if (strncasecmp(word, table[i], wordlen) == 0)
return i;
return -1;
}
FILE *user_tailor(void)
{
char rcfile[BUFSIZ];
rcfile[0] = 0;
#ifdef unix
{
#include <pwd.h>
struct passwd *pwent;
if (pwent = getpwuid(getuid()))
strcat(strcpy(rcfile, pwent->pw_dir), "/");
strcat(rcfile, ".saucerrc");
}
#else
strcpy(rcfile, "saucer.rc");
#endif
return fopen(rcfile, "r");
}