diff options
-rw-r--r-- | auth.h | 3 | ||||
-rw-r--r-- | cli-authpubkey.c | 24 | ||||
-rw-r--r-- | cli-runopts.c | 172 | ||||
-rw-r--r-- | cli-session.c | 10 | ||||
-rw-r--r-- | common-runopts.c | 29 | ||||
-rw-r--r-- | debug.h | 2 | ||||
-rw-r--r-- | options.h | 5 | ||||
-rw-r--r-- | runopts.h | 6 | ||||
-rw-r--r-- | session.h | 1 | ||||
-rw-r--r-- | svr-runopts.c | 52 |
10 files changed, 205 insertions, 99 deletions
@@ -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; +} @@ -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 @@ -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 @@ -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; @@ -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 |