summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--auth.h3
-rw-r--r--cli-authpubkey.c24
-rw-r--r--cli-runopts.c172
-rw-r--r--cli-session.c10
-rw-r--r--common-runopts.c29
-rw-r--r--debug.h2
-rw-r--r--options.h5
-rw-r--r--runopts.h6
-rw-r--r--session.h1
-rw-r--r--svr-runopts.c52
10 files changed, 205 insertions, 99 deletions
diff --git a/auth.h b/auth.h
index 061c8c4..edac5a9 100644
--- a/auth.h
+++ b/auth.h
@@ -63,9 +63,6 @@ int cli_auth_pubkey();
#define AUTH_METHOD_PASSWORD "password"
#define AUTH_METHOD_PASSWORD_LEN 8
-/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
-#define MAX_PUBKEY_SIZE 1600
-
/* This structure is shared between server and client - it contains
* relatively little extraneous bits when used for the client rather than the
* server */
diff --git a/cli-authpubkey.c b/cli-authpubkey.c
index dd5a711..6b6ab51 100644
--- a/cli-authpubkey.c
+++ b/cli-authpubkey.c
@@ -16,7 +16,7 @@ void cli_pubkeyfail() {
TRACE(("enter cli_pubkeyfail"));
/* Find the key we failed with, and remove it */
- for (keyitem = cli_ses.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+ for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem->next == cli_ses.lastpubkey) {
keyitem->next = cli_ses.lastpubkey->next;
}
@@ -40,6 +40,7 @@ void recv_msg_userauth_pk_ok() {
algotype = buf_getstring(ses.payload, &algolen);
keytype = signkey_type_from_name(algotype, algolen);
+ TRACE(("recv_msg_userauth_pk_ok: type %d", keytype));
m_free(algotype);
keybuf = buf_new(MAX_PUBKEY_SIZE);
@@ -48,25 +49,32 @@ void recv_msg_userauth_pk_ok() {
/* Iterate through our keys, find which one it was that matched, and
* send a real request with that key */
- for (keyitem = cli_ses.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+ for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem->type != keytype) {
/* Types differed */
+ TRACE(("types differed"));
continue;
}
/* Now we compare the contents of the key */
keybuf->pos = keybuf->len = 0;
buf_put_pub_key(keybuf, keyitem->key, keytype);
+ buf_setpos(keybuf, 0);
+ buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
+ remotelen) which has already been taken from
+ the remote buffer */
- if (keybuf->len != remotelen) {
+
+ if (keybuf->len-4 != remotelen) {
+ TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen));
/* Lengths differed */
continue;
}
-
- if (memcmp(keybuf->data,
+ if (memcmp(buf_getptr(keybuf, remotelen),
buf_getptr(ses.payload, remotelen), remotelen) != 0) {
/* Data didn't match this key */
+ TRACE(("data differed"));
continue;
}
@@ -133,10 +141,10 @@ int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey"));
- if (cli_ses.pubkeys != NULL) {
+ if (cli_opts.pubkeys != NULL) {
/* Send a trial request */
- send_msg_userauth_pubkey(cli_ses.pubkeys->key,
- cli_ses.pubkeys->type, 0);
+ send_msg_userauth_pubkey(cli_opts.pubkeys->key,
+ cli_opts.pubkeys->type, 0);
TRACE(("leave cli_auth_pubkey-success"));
return 1;
} else {
diff --git a/cli-runopts.c b/cli-runopts.c
index a1915da..6c16343 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -31,17 +31,24 @@
cli_runopts cli_opts; /* GLOBAL */
-static void printhelp(const char * progname);
+static void printhelp();
+static void parsehostname(char* userhostarg);
+#ifdef DROPBEAR_PUBKEY_AUTH
+static void loadidentityfile(const char* filename);
+#endif
-static void printhelp(const char * progname) {
+static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
- "Usage: %s [options] user@host[:port]\n"
+ "Usage: %s [options] user@host\n"
"Options are:\n"
- "user Remote username\n"
- "host Remote host\n"
- "port Remote port\n"
- ,DROPBEAR_VERSION, progname);
+ "-p <remoteport>\n"
+ "-t Allocate a pty"
+ "-T Don't allocate a pty"
+#ifdef DROPBEAR_PUBKEY_AUTH
+ "-i <identityfile> (multiple allowed)"
+#endif
+ ,DROPBEAR_VERSION, cli_opts.progname);
}
void cli_getopts(int argc, char ** argv) {
@@ -49,12 +56,11 @@ void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
+#ifdef DROPBEAR_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */
+#endif
- uid_t uid;
- struct passwd *pw = NULL;
- char* userhostarg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -62,7 +68,10 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.remoteport = NULL;
cli_opts.username = NULL;
cli_opts.cmd = NULL;
- cli_opts.wantpty = 1;
+ cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
+#ifdef DROPBEAR_PUBKEY_AUTH
+ cli_opts.pubkeys = NULL;
+#endif
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
/* not yet
@@ -70,17 +79,18 @@ void cli_getopts(int argc, char ** argv) {
opts.ipv6 = 1;
*/
- if (argc != 2) {
- printhelp(argv[0]);
- exit(EXIT_FAILURE);
- }
-
+ /* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) {
+#ifdef DROPBEAR_PUBKEY_AUTH
if (nextiskey) {
- /* XXX do stuff */
- break;
+ /* Load a hostkey since the previous argument was "-i" */
+ loadidentityfile(argv[i]);
+ nextiskey = 0;
+ continue;
}
+#endif
if (next) {
+ /* The previous flag set a value to assign */
*next = argv[i];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
@@ -90,59 +100,43 @@ void cli_getopts(int argc, char ** argv) {
}
if (argv[i][0] == '-') {
-
/* A flag *waves* */
+
switch (argv[i][1]) {
- case 'p':
+ case 'p': /* remoteport */
next = &cli_opts.remoteport;
break;
#ifdef DROPBEAR_PUBKEY_AUTH
- case 'i':
+ case 'i': /* an identityfile */
nextiskey = 1;
break;
#endif
+ case 't': /* we want a pty */
+ cli_opts.wantpty = 1;
+ break;
+ case 'T': /* don't want a pty */
+ cli_opts.wantpty = 0;
+ break;
default:
- fprintf(stderr, "Unknown argument %s\n", argv[i]);
- printhelp(argv[0]);
+ fprintf(stderr, "Unknown argument '%s'\n", argv[i]);
+ printhelp();
exit(EXIT_FAILURE);
break;
} /* Switch */
+ continue; /* next argument */
+
} else {
+ TRACE(("non-flag arg"));
/* Either the hostname or commands */
- /* Hostname is first up, must be set before we get the cmds */
if (cli_opts.remotehost == NULL) {
- /* We'll be editing it, should probably make a copy */
- userhostarg = m_strdup(argv[1]);
-
- cli_opts.remotehost = strchr(userhostarg, '@');
- if (cli_opts.remotehost == NULL) {
- /* no username portion, the cli-auth.c code can figure the
- * local user's name */
- cli_opts.remotehost = userhostarg;
- } else {
- cli_opts.remotehost[0] = '\0'; /* Split the user/host */
- cli_opts.remotehost++;
- cli_opts.username = userhostarg;
- }
-
- if (cli_opts.username == NULL) {
- uid = getuid();
-
- pw = getpwuid(uid);
- if (pw == NULL || pw->pw_name == NULL) {
- dropbear_exit("I don't know my own [user]name");
- }
- cli_opts.username = m_strdup(pw->pw_name);
- }
+ parsehostname(argv[i]);
- if (cli_opts.remotehost[0] == '\0') {
- dropbear_exit("Bad hostname");
- }
} else {
+
/* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the
* command */
@@ -166,4 +160,82 @@ void cli_getopts(int argc, char ** argv) {
}
}
}
+
+ if (cli_opts.remotehost == NULL) {
+ dropbear_exit("Bad syntax");
+ }
+
+ if (cli_opts.remoteport == NULL) {
+ cli_opts.remoteport = "22";
+ }
+
+ /* If not explicitly specified with -t or -T, we don't want a pty if
+ * there's a command, but we do otherwise */
+ if (cli_opts.wantpty == 9) {
+ if (cli_opts.cmd == NULL) {
+ cli_opts.wantpty = 1;
+ } else {
+ cli_opts.wantpty = 0;
+ }
+ }
+}
+
+#ifdef DROPBEAR_PUBKEY_AUTH
+static void loadidentityfile(const char* filename) {
+
+ struct PubkeyList * nextkey;
+ sign_key *key;
+ int keytype;
+
+ key = new_sign_key();
+ keytype = DROPBEAR_SIGNKEY_ANY;
+ if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
+
+ fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
+ sign_key_free(key);
+
+ } else {
+
+ nextkey = (struct PubkeyList*)m_malloc(sizeof(struct PubkeyList));
+ nextkey->key = key;
+ nextkey->next = cli_opts.pubkeys;
+ nextkey->type = keytype;
+ cli_opts.pubkeys = nextkey;
+ }
+}
+#endif
+
+
+/* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
+ * - note that it will be modified */
+static void parsehostname(char* userhostarg) {
+
+ uid_t uid;
+ struct passwd *pw = NULL;
+
+ cli_opts.remotehost = strchr(userhostarg, '@');
+ if (cli_opts.remotehost == NULL) {
+ /* no username portion, the cli-auth.c code can figure the
+ * local user's name */
+ cli_opts.remotehost = userhostarg;
+ } else {
+ cli_opts.remotehost[0] = '\0'; /* Split the user/host */
+ cli_opts.remotehost++;
+ cli_opts.username = userhostarg;
+ }
+
+ if (cli_opts.username == NULL) {
+ uid = getuid();
+
+ pw = getpwuid(uid);
+ if (pw == NULL || pw->pw_name == NULL) {
+ dropbear_exit("Unknown own user");
+ }
+
+ cli_opts.username = m_strdup(pw->pw_name);
+ }
+
+ if (cli_opts.remotehost[0] == '\0') {
+ dropbear_exit("Bad hostname");
+ }
}
diff --git a/cli-session.c b/cli-session.c
index 987a79b..973e9c7 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -88,6 +88,10 @@ static void cli_session_init() {
cli_ses.tty_raw_mode = 0;
cli_ses.winchange = 0;
+ /* Auth */
+ cli_ses.lastpubkey = NULL;
+ cli_ses.lastauthtype = NULL;
+
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
ses.buf_match_algo = cli_buf_match_algo;
@@ -160,6 +164,7 @@ static void cli_sessionloop() {
TRACE(("leave cli_sessionloop: cli_auth_try"));
return;
+ /*
case USERAUTH_SUCCESS_RCVD:
send_msg_service_request(SSH_SERVICE_CONNECTION);
cli_ses.state = SERVICE_CONN_REQ_SENT;
@@ -171,14 +176,13 @@ static void cli_sessionloop() {
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
cli_ses.state = SESSION_RUNNING;
return;
+ */
- /*
case USERAUTH_SUCCESS_RCVD:
cli_send_chansess_request();
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
cli_ses.state = SESSION_RUNNING;
return;
- */
case SESSION_RUNNING:
if (ses.chancount < 1) {
@@ -236,7 +240,7 @@ static void cli_remoteclosed() {
void cleantext(unsigned char* dirtytext) {
unsigned int i, j;
- unsigned char c, lastchar;
+ unsigned char c;
j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) {
diff --git a/common-runopts.c b/common-runopts.c
index 097ab12..2de036e 100644
--- a/common-runopts.c
+++ b/common-runopts.c
@@ -24,5 +24,34 @@
#include "includes.h"
#include "runopts.h"
+#include "signkey.h"
+#include "buffer.h"
+#include "dbutil.h"
+#include "auth.h"
runopts opts; /* GLOBAL */
+
+/* returns success or failure, and the keytype in *type. If we want
+ * to restrict the type, type can contain a type to return */
+int readhostkey(const char * filename, sign_key * hostkey, int *type) {
+
+ int ret = DROPBEAR_FAILURE;
+ buffer *buf;
+
+ buf = buf_new(MAX_PRIVKEY_SIZE);
+
+ if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
+ goto out;
+ }
+ buf_setpos(buf, 0);
+ if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
+ goto out;
+ }
+
+ ret = DROPBEAR_SUCCESS;
+out:
+
+ buf_burn(buf);
+ buf_free(buf);
+ return ret;
+}
diff --git a/debug.h b/debug.h
index 736690a..d619a58 100644
--- a/debug.h
+++ b/debug.h
@@ -36,7 +36,7 @@
/* Define this to print trace statements - very verbose */
/* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing does not sanitise strings etc */
-//#define DEBUG_TRACE
+#define DEBUG_TRACE
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
diff --git a/options.h b/options.h
index 02f36bc..55755b2 100644
--- a/options.h
+++ b/options.h
@@ -275,6 +275,11 @@
#define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also
is the max length for a password etc */
+/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
+#define MAX_PUBKEY_SIZE 1600
+/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
+#define MAX_PRIVKEY_SIZE 1600
+
#ifndef ENABLE_X11FWD
#define DISABLE_X11FWD
#endif
diff --git a/runopts.h b/runopts.h
index 26d15ef..c74dab5 100644
--- a/runopts.h
+++ b/runopts.h
@@ -28,6 +28,7 @@
#include "includes.h"
#include "signkey.h"
#include "buffer.h"
+#include "auth.h"
typedef struct runopts {
@@ -38,6 +39,8 @@ typedef struct runopts {
extern runopts opts;
+int readhostkey(const char * filename, sign_key * hostkey, int *type);
+
typedef struct svr_runopts {
char * rsakeyfile;
@@ -87,6 +90,9 @@ typedef struct cli_runopts {
char *cmd;
int wantpty;
+ struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
+#ifdef DROPBEAR_PUBKEY_AUTH
+#endif
/* XXX TODO */
} cli_runopts;
diff --git a/session.h b/session.h
index 6d69508..4a9d4ed 100644
--- a/session.h
+++ b/session.h
@@ -214,7 +214,6 @@ struct clientsession {
int winchange; /* Set to 1 when a windowchange signal happens */
- struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
struct PubkeyList *lastpubkey;
diff --git a/svr-runopts.c b/svr-runopts.c
index c79208c..996c15c 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -33,7 +33,6 @@ svr_runopts svr_opts; /* GLOBAL */
static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile);
-static int readhostkey(const char * filename, sign_key * hostkey, int type);
static void printhelp(const char * progname);
static void printhelp(const char * progname) {
@@ -263,57 +262,44 @@ void svr_getopts(int argc, char ** argv) {
}
+static void disablekey(int type, const char* filename) {
-/* returns success or failure */
-static int readhostkey(const char * filename, sign_key * hostkey, int type) {
-
- int ret = DROPBEAR_FAILURE;
int i;
- buffer *buf;
-
- buf = buf_new(2000);
- if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
- goto out;
- }
- buf_setpos(buf, 0);
- if (buf_get_priv_key(buf, hostkey, &type) == DROPBEAR_FAILURE) {
- goto out;
- }
-
- ret = DROPBEAR_SUCCESS;
-out:
- if (ret == DROPBEAR_FAILURE) {
- for (i = 0; sshhostkey[i].name != NULL; i++) {
- if (sshhostkey[i].val == type) {
- sshhostkey[i].usable = 0;
- break;
- }
+ for (i = 0; sshhostkey[i].name != NULL; i++) {
+ if (sshhostkey[i].val == type) {
+ sshhostkey[i].usable = 0;
+ break;
}
- fprintf(stderr, "Failed reading '%s', disabling %s\n", filename,
- type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
}
-
- buf_burn(buf);
- buf_free(buf);
- return ret;
+ fprintf(stderr, "Failed reading '%s', disabling %s\n", filename,
+ type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
}
static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile) {
sign_key * hostkey;
+ int ret;
+ int type;
TRACE(("enter loadhostkeys"));
hostkey = new_sign_key();
#ifdef DROPBEAR_RSA
- (void)readhostkey(rsakeyfile, hostkey, DROPBEAR_SIGNKEY_RSA);
+ type = DROPBEAR_SIGNKEY_RSA;
+ ret = readhostkey(rsakeyfile, hostkey, &type);
+ if (ret == DROPBEAR_FAILURE) {
+ disablekey(DROPBEAR_SIGNKEY_RSA, rsakeyfile);
+ }
#endif
-
#ifdef DROPBEAR_DSS
- (void)readhostkey(dsskeyfile, hostkey, DROPBEAR_SIGNKEY_DSS);
+ type = DROPBEAR_SIGNKEY_RSA;
+ ret = readhostkey(dsskeyfile, hostkey, &type);
+ if (ret == DROPBEAR_FAILURE) {
+ disablekey(DROPBEAR_SIGNKEY_DSS, dsskeyfile);
+ }
#endif
if ( 1