- client pubkey auth works

- rearrange the runopts code for client and server (hostkey reading is needed
  by both (if the client is doing pubkey auth. otherwise....))

--HG--
extra : convert_revision : 5420858803bfff1e27dfe7fa877ba6fdd747e0c5
This commit is contained in:
Matt Johnston 2004-08-06 16:18:01 +00:00
parent 68f816e8cf
commit 0bbe2fa862
10 changed files with 205 additions and 99 deletions

3
auth.h
View File

@ -63,9 +63,6 @@ int cli_auth_pubkey();
#define AUTH_METHOD_PASSWORD "password" #define AUTH_METHOD_PASSWORD "password"
#define AUTH_METHOD_PASSWORD_LEN 8 #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 /* This structure is shared between server and client - it contains
* relatively little extraneous bits when used for the client rather than the * relatively little extraneous bits when used for the client rather than the
* server */ * server */

View File

@ -16,7 +16,7 @@ void cli_pubkeyfail() {
TRACE(("enter cli_pubkeyfail")); TRACE(("enter cli_pubkeyfail"));
/* Find the key we failed with, and remove it */ /* 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) { if (keyitem->next == cli_ses.lastpubkey) {
keyitem->next = cli_ses.lastpubkey->next; keyitem->next = cli_ses.lastpubkey->next;
} }
@ -40,6 +40,7 @@ void recv_msg_userauth_pk_ok() {
algotype = buf_getstring(ses.payload, &algolen); algotype = buf_getstring(ses.payload, &algolen);
keytype = signkey_type_from_name(algotype, algolen); keytype = signkey_type_from_name(algotype, algolen);
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype));
m_free(algotype); m_free(algotype);
keybuf = buf_new(MAX_PUBKEY_SIZE); 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 /* Iterate through our keys, find which one it was that matched, and
* send a real request with that key */ * 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) { if (keyitem->type != keytype) {
/* Types differed */ /* Types differed */
TRACE(("types differed"));
continue; continue;
} }
/* Now we compare the contents of the key */ /* Now we compare the contents of the key */
keybuf->pos = keybuf->len = 0; keybuf->pos = keybuf->len = 0;
buf_put_pub_key(keybuf, keyitem->key, keytype); 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 */ /* Lengths differed */
continue; continue;
} }
if (memcmp(buf_getptr(keybuf, remotelen),
if (memcmp(keybuf->data,
buf_getptr(ses.payload, remotelen), remotelen) != 0) { buf_getptr(ses.payload, remotelen), remotelen) != 0) {
/* Data didn't match this key */ /* Data didn't match this key */
TRACE(("data differed"));
continue; continue;
} }
@ -133,10 +141,10 @@ int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey")); TRACE(("enter cli_auth_pubkey"));
if (cli_ses.pubkeys != NULL) { if (cli_opts.pubkeys != NULL) {
/* Send a trial request */ /* Send a trial request */
send_msg_userauth_pubkey(cli_ses.pubkeys->key, send_msg_userauth_pubkey(cli_opts.pubkeys->key,
cli_ses.pubkeys->type, 0); cli_opts.pubkeys->type, 0);
TRACE(("leave cli_auth_pubkey-success")); TRACE(("leave cli_auth_pubkey-success"));
return 1; return 1;
} else { } else {

View File

@ -31,17 +31,24 @@
cli_runopts cli_opts; /* GLOBAL */ 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" fprintf(stderr, "Dropbear client v%s\n"
"Usage: %s [options] user@host[:port]\n" "Usage: %s [options] user@host\n"
"Options are:\n" "Options are:\n"
"user Remote username\n" "-p <remoteport>\n"
"host Remote host\n" "-t Allocate a pty"
"port Remote port\n" "-T Don't allocate a pty"
,DROPBEAR_VERSION, progname); #ifdef DROPBEAR_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)"
#endif
,DROPBEAR_VERSION, cli_opts.progname);
} }
void cli_getopts(int argc, char ** argv) { void cli_getopts(int argc, char ** argv) {
@ -49,12 +56,11 @@ void cli_getopts(int argc, char ** argv) {
unsigned int i, j; unsigned int i, j;
char ** next = 0; char ** next = 0;
unsigned int cmdlen; unsigned int cmdlen;
#ifdef DROPBEAR_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */ 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 */ /* see printhelp() for options */
cli_opts.progname = argv[0]; cli_opts.progname = argv[0];
@ -62,7 +68,10 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.remoteport = NULL; cli_opts.remoteport = NULL;
cli_opts.username = NULL; cli_opts.username = NULL;
cli_opts.cmd = 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.nolocaltcp = 0;
opts.noremotetcp = 0; opts.noremotetcp = 0;
/* not yet /* not yet
@ -70,17 +79,18 @@ void cli_getopts(int argc, char ** argv) {
opts.ipv6 = 1; opts.ipv6 = 1;
*/ */
if (argc != 2) { /* Iterate all the arguments */
printhelp(argv[0]);
exit(EXIT_FAILURE);
}
for (i = 1; i < (unsigned int)argc; i++) { for (i = 1; i < (unsigned int)argc; i++) {
#ifdef DROPBEAR_PUBKEY_AUTH
if (nextiskey) { if (nextiskey) {
/* XXX do stuff */ /* Load a hostkey since the previous argument was "-i" */
break; loadidentityfile(argv[i]);
nextiskey = 0;
continue;
} }
#endif
if (next) { if (next) {
/* The previous flag set a value to assign */
*next = argv[i]; *next = argv[i];
if (*next == NULL) { if (*next == NULL) {
dropbear_exit("Invalid null argument"); dropbear_exit("Invalid null argument");
@ -90,59 +100,43 @@ void cli_getopts(int argc, char ** argv) {
} }
if (argv[i][0] == '-') { if (argv[i][0] == '-') {
/* A flag *waves* */ /* A flag *waves* */
switch (argv[i][1]) { switch (argv[i][1]) {
case 'p': case 'p': /* remoteport */
next = &cli_opts.remoteport; next = &cli_opts.remoteport;
break; break;
#ifdef DROPBEAR_PUBKEY_AUTH #ifdef DROPBEAR_PUBKEY_AUTH
case 'i': case 'i': /* an identityfile */
nextiskey = 1; nextiskey = 1;
break; break;
#endif #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: default:
fprintf(stderr, "Unknown argument %s\n", argv[i]); fprintf(stderr, "Unknown argument '%s'\n", argv[i]);
printhelp(argv[0]); printhelp();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
break; break;
} /* Switch */ } /* Switch */
continue; /* next argument */
} else { } else {
TRACE(("non-flag arg"));
/* Either the hostname or commands */ /* Either the hostname or commands */
/* Hostname is first up, must be set before we get the cmds */
if (cli_opts.remotehost == NULL) { 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, '@'); parsehostname(argv[i]);
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);
}
if (cli_opts.remotehost[0] == '\0') {
dropbear_exit("Bad hostname");
}
} else { } else {
/* this is part of the commands to send - after this we /* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the * don't parse any more options, and flags are sent as the
* command */ * 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");
}
} }

View File

@ -88,6 +88,10 @@ static void cli_session_init() {
cli_ses.tty_raw_mode = 0; cli_ses.tty_raw_mode = 0;
cli_ses.winchange = 0; cli_ses.winchange = 0;
/* Auth */
cli_ses.lastpubkey = NULL;
cli_ses.lastauthtype = NULL;
/* For printing "remote host closed" for the user */ /* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed; ses.remoteclosed = cli_remoteclosed;
ses.buf_match_algo = cli_buf_match_algo; ses.buf_match_algo = cli_buf_match_algo;
@ -160,6 +164,7 @@ static void cli_sessionloop() {
TRACE(("leave cli_sessionloop: cli_auth_try")); TRACE(("leave cli_sessionloop: cli_auth_try"));
return; return;
/*
case USERAUTH_SUCCESS_RCVD: case USERAUTH_SUCCESS_RCVD:
send_msg_service_request(SSH_SERVICE_CONNECTION); send_msg_service_request(SSH_SERVICE_CONNECTION);
cli_ses.state = SERVICE_CONN_REQ_SENT; cli_ses.state = SERVICE_CONN_REQ_SENT;
@ -171,14 +176,13 @@ static void cli_sessionloop() {
TRACE(("leave cli_sessionloop: cli_send_chansess_request")); TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
cli_ses.state = SESSION_RUNNING; cli_ses.state = SESSION_RUNNING;
return; return;
*/
/*
case USERAUTH_SUCCESS_RCVD: case USERAUTH_SUCCESS_RCVD:
cli_send_chansess_request(); cli_send_chansess_request();
TRACE(("leave cli_sessionloop: cli_send_chansess_request")); TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
cli_ses.state = SESSION_RUNNING; cli_ses.state = SESSION_RUNNING;
return; return;
*/
case SESSION_RUNNING: case SESSION_RUNNING:
if (ses.chancount < 1) { if (ses.chancount < 1) {
@ -236,7 +240,7 @@ static void cli_remoteclosed() {
void cleantext(unsigned char* dirtytext) { void cleantext(unsigned char* dirtytext) {
unsigned int i, j; unsigned int i, j;
unsigned char c, lastchar; unsigned char c;
j = 0; j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) { for (i = 0; dirtytext[i] != '\0'; i++) {

View File

@ -24,5 +24,34 @@
#include "includes.h" #include "includes.h"
#include "runopts.h" #include "runopts.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
runopts opts; /* GLOBAL */ 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;
}

View File

@ -36,7 +36,7 @@
/* Define this to print trace statements - very verbose */ /* Define this to print trace statements - very verbose */
/* Caution: Don't use this in an unfriendly environment (ie unfirewalled), /* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing does not sanitise strings etc */ * since the printing does not sanitise strings etc */
//#define DEBUG_TRACE #define DEBUG_TRACE
/* All functions writing to the cleartext payload buffer call /* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're * CHECKCLEARTOWRITE() before writing. This is only really useful if you're

View File

@ -275,6 +275,11 @@
#define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also #define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also
is the max length for a password etc */ 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 #ifndef ENABLE_X11FWD
#define DISABLE_X11FWD #define DISABLE_X11FWD
#endif #endif

View File

@ -28,6 +28,7 @@
#include "includes.h" #include "includes.h"
#include "signkey.h" #include "signkey.h"
#include "buffer.h" #include "buffer.h"
#include "auth.h"
typedef struct runopts { typedef struct runopts {
@ -38,6 +39,8 @@ typedef struct runopts {
extern runopts opts; extern runopts opts;
int readhostkey(const char * filename, sign_key * hostkey, int *type);
typedef struct svr_runopts { typedef struct svr_runopts {
char * rsakeyfile; char * rsakeyfile;
@ -87,6 +90,9 @@ typedef struct cli_runopts {
char *cmd; char *cmd;
int wantpty; int wantpty;
struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
#ifdef DROPBEAR_PUBKEY_AUTH
#endif
/* XXX TODO */ /* XXX TODO */
} cli_runopts; } cli_runopts;

View File

@ -214,7 +214,6 @@ struct clientsession {
int winchange; /* Set to 1 when a windowchange signal happens */ 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, int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */ for the last type of auth we tried */
struct PubkeyList *lastpubkey; struct PubkeyList *lastpubkey;

View File

@ -33,7 +33,6 @@ svr_runopts svr_opts; /* GLOBAL */
static sign_key * loadhostkeys(const char * dsskeyfile, static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile); 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);
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; int i;
buffer *buf;
buf = buf_new(2000); for (i = 0; sshhostkey[i].name != NULL; i++) {
if (sshhostkey[i].val == type) {
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) { sshhostkey[i].usable = 0;
goto out; break;
}
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;
}
} }
fprintf(stderr, "Failed reading '%s', disabling %s\n", filename,
type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
} }
fprintf(stderr, "Failed reading '%s', disabling %s\n", filename,
buf_burn(buf); type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
buf_free(buf);
return ret;
} }
static sign_key * loadhostkeys(const char * dsskeyfile, static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile) { const char * rsakeyfile) {
sign_key * hostkey; sign_key * hostkey;
int ret;
int type;
TRACE(("enter loadhostkeys")); TRACE(("enter loadhostkeys"));
hostkey = new_sign_key(); hostkey = new_sign_key();
#ifdef DROPBEAR_RSA #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 #endif
#ifdef DROPBEAR_DSS #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 #endif
if ( 1 if ( 1