summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2004-07-27 16:30:46 +0000
committerMatt Johnston <matt@ucc.asn.au>2004-07-27 16:30:46 +0000
commit4f3a2de383a3c7ece24e9ae01507ed9fc93b4e20 (patch)
tree52e8706431b92b98d2a86b51699635ea7f29486f
parent04c3545b946502171788e9b45b2969367741c76e (diff)
downloaddropbear-4f3a2de383a3c7ece24e9ae01507ed9fc93b4e20.tar.gz
Progressing client support
-rw-r--r--Makefile.in13
-rw-r--r--auth.h30
-rw-r--r--cli-auth.c148
-rw-r--r--cli-authpasswd.c36
-rw-r--r--cli-kex.c1
-rw-r--r--cli-main.c49
-rw-r--r--cli-service.c62
-rw-r--r--cli-session.c92
-rw-r--r--common-kex.c42
-rw-r--r--common-runopts.c28
-rw-r--r--common-session.c6
-rw-r--r--dbmulti.c8
-rw-r--r--debug.h2
-rw-r--r--kex.h9
-rw-r--r--options.h23
-rw-r--r--packet.c6
-rw-r--r--runopts.h6
-rw-r--r--scp.c7
-rw-r--r--service.h3
-rw-r--r--session.h38
-rw-r--r--svr-agentfwd.c8
-rw-r--r--svr-auth.c72
-rw-r--r--svr-authpasswd.c12
-rw-r--r--svr-authpubkey.c22
-rw-r--r--svr-chansession.c32
-rw-r--r--svr-runopts.c4
-rw-r--r--svr-service.c3
-rw-r--r--svr-session.c13
28 files changed, 599 insertions, 176 deletions
diff --git a/Makefile.in b/Makefile.in
index 645da6d..b8de23e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -27,7 +27,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
- cli-session.o cli-service.o
+ cli-session.o cli-service.o cli-runopts.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
@@ -140,11 +140,12 @@ dbclient: $(dbclientobjs)
dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
-dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM)
+dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
+ Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS)
# scp doesn't use the libs so is special.
-scp: $(SCPOBJS) $(HEADERS)
+scp: $(SCPOBJS) $(HEADERS) Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS)
@@ -155,16 +156,16 @@ ifeq ($(MULTI),1)
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
-dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM)
+dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS)
@echo
@echo "You should now create symlinks to the programs you have included"
@echo "ie 'ln -s dropbearmulti dropbear'"
-$(LTC): $(HEADERS)
+$(LTC): options.h
cd libtomcrypt && $(MAKE) clean && $(MAKE)
-$(LTM): $(HEADERS)
+$(LTM): options.h
cd libtommath && $(MAKE)
ltc-clean:
diff --git a/auth.h b/auth.h
index 8d2db3e..df8ae0c 100644
--- a/auth.h
+++ b/auth.h
@@ -27,12 +27,28 @@
#include "includes.h"
-void authinitialise();
+void svr_authinitialise();
+void cli_authinitialise();
+void svr_auth_password();
+void svr_auth_pubkey();
+
+int cli_auth_password();
+int cli_auth_pubkey();
+
+/* Server functions */
void recv_msg_userauth_request();
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success();
+/* Client functions */
+void recv_msg_userauth_failure();
+void recv_msg_userauth_success();
+void cli_get_user();
+void cli_auth_getmethods();
+void cli_auth_try();
+
+
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
#define AUTH_TYPE_PUBKEY 1 << 0
@@ -46,17 +62,23 @@ void send_msg_userauth_success();
#define AUTH_METHOD_PASSWORD "password"
#define AUTH_METHOD_PASSWORD_LEN 8
+/* This structure is shared between server and client - it contains
+ * relatively little extraneous bits when used for the client rather than the
+ * server */
struct AuthState {
char *username; /* This is the username the client presents to check. It
is updated each run through, used for auth checking */
- char *printableuser; /* stripped of control chars, used for logs etc */
- struct passwd * pw;
unsigned char authtypes; /* Flags indicating which auth types are still
valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/
- unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have */
+ unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
+ client and server (though has differing [obvious]
+ meanings). */
+ /* These are only used for the server */
+ char *printableuser; /* stripped of control chars, used for logs etc */
+ struct passwd * pw;
};
diff --git a/cli-auth.c b/cli-auth.c
new file mode 100644
index 0000000..952546e
--- /dev/null
+++ b/cli-auth.c
@@ -0,0 +1,148 @@
+#include "includes.h"
+#include "session.h"
+#include "auth.h"
+#include "dbutil.h"
+#include "buffer.h"
+#include "ssh.h"
+#include "packet.h"
+#include "runopts.h"
+
+void cli_authinitialise() {
+
+ memset(&ses.authstate, 0, sizeof(ses.authstate));
+}
+
+
+void cli_get_user() {
+
+ uid_t uid;
+ struct passwd *pw;
+
+ TRACE(("enter cli_get_user"));
+ if (cli_opts.username != NULL) {
+ ses.authstate.username = cli_opts.username;
+ } else {
+ uid = getuid();
+
+ pw = getpwuid(uid);
+ if (pw == NULL || pw->pw_name == NULL) {
+ dropbear_exit("Couldn't find username for current user");
+ }
+
+ ses.authstate.username = m_strdup(pw->pw_name);
+ }
+ TRACE(("leave cli_get_user: %s", cli_ses.username));
+}
+
+/* Send a "none" auth request to get available methods */
+void cli_auth_getmethods() {
+
+ TRACE(("enter cli_auth_getmethods"));
+
+ CHECKCLEARTOWRITE();
+
+ buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
+ buf_putstring(ses.writepayload, ses.authstate.username,
+ strlen(ses.authstate.username));
+ buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
+ SSH_SERVICE_CONNECTION_LEN);
+ buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
+
+ encrypt_packet();
+ cli_ses.state = USERAUTH_METHODS_SENT;
+ TRACE(("leave cli_auth_getmethods"));
+
+}
+
+void recv_msg_userauth_failure() {
+
+ unsigned char * methods = NULL;
+ unsigned char * tok = NULL;
+ unsigned int methlen = 0;
+ unsigned int partial = 0;
+ unsigned int i = 0;
+
+ TRACE(("<- MSG_USERAUTH_FAILURE"));
+ TRACE(("enter recv_msg_userauth_failure"));
+
+ methods = buf_getstring(ses.payload, &methlen);
+
+ partial = buf_getbyte(ses.payload);
+
+ if (partial) {
+ dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required");
+ } else {
+ ses.authstate.failcount++;
+ }
+
+ TRACE(("Methods (len %d): '%s'", methlen, methods));
+
+ ses.authstate.authdone=0;
+ ses.authstate.authtypes=0;
+
+ /* Split with nulls rather than commas */
+ for (i = 0; i < methlen; i++) {
+ if (methods[i] == ',') {
+ methods[i] = '\0';
+ }
+ }
+
+ tok = methods; /* tok stores the next method we'll compare */
+ for (i = 0; i <= methlen; i++) {
+ if (methods[i] == '\0') {
+ TRACE(("auth method '%s'\n", tok));
+#ifdef DROPBEAR_PUBKEY_AUTH
+ if (strncmp(AUTH_METHOD_PUBKEY, tok,
+ AUTH_METHOD_PUBKEY_LEN) == 0) {
+ ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
+ }
+#endif
+#ifdef DROPBEAR_PASSWORD_AUTH
+ if (strncmp(AUTH_METHOD_PASSWORD, tok,
+ AUTH_METHOD_PASSWORD_LEN) == 0) {
+ ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
+ }
+#endif
+ tok = &methods[i]; /* Must make sure we don't use it after
+ the last loop, since it'll point
+ to something undefined */
+ }
+ }
+
+ cli_ses.state = USERAUTH_FAIL_RCVD;
+
+ TRACE(("leave recv_msg_userauth_failure"));
+}
+
+void recv_msg_userauth_success() {
+ TRACE(("received msg_userauth_success"));
+ ses.authstate.authdone = 1;
+}
+
+void cli_auth_try() {
+
+ TRACE(("enter cli_auth_try"));
+ int finished = 0;
+
+ CHECKCLEARTOWRITE();
+
+ /* XXX We hardcode that we try a pubkey first */
+#ifdef DROPBEAR_PUBKEY_AUTH
+ if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
+ finished = cli_auth_pubkey();
+ }
+#endif
+
+#ifdef DROPBEAR_PASSWORD_AUTH
+ if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
+ finished = cli_auth_password();
+ }
+#endif
+
+ if (!finished) {
+ dropbear_exit("No auth methods could be used.");
+ }
+
+ cli_ses.state = USERAUTH_REQ_SENT;
+ TRACE(("leave cli_auth_try"));
+}
diff --git a/cli-authpasswd.c b/cli-authpasswd.c
new file mode 100644
index 0000000..6185334
--- /dev/null
+++ b/cli-authpasswd.c
@@ -0,0 +1,36 @@
+#include "includes.h"
+#include "buffer.h"
+#include "dbutil.h"
+#include "session.h"
+#include "ssh.h"
+
+int cli_auth_password() {
+
+ char* password = NULL;
+ TRACE(("enter cli_auth_password"));
+
+ CHECKCLEARTOWRITE();
+ password = getpass("Password: ");
+
+ buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
+
+ buf_putstring(ses.writepayload, ses.authstate.username,
+ strlen(ses.authstate.username));
+
+ buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
+ SSH_SERVICE_CONNECTION_LEN);
+
+ buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
+ AUTH_METHOD_PASSWORD_LEN);
+
+ buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
+
+ buf_putstring(ses.writepayload, password, strlen(password));
+
+ encrypt_packet();
+ m_burn(password, strlen(password));
+
+ TRACE(("leave cli_auth_password"));
+ return 1; /* Password auth can always be tried */
+
+}
diff --git a/cli-kex.c b/cli-kex.c
index 4d26332..2577caf 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -34,6 +34,7 @@
#include "bignum.h"
#include "random.h"
#include "runopts.h"
+#include "signkey.h"
diff --git a/cli-main.c b/cli-main.c
index 2460060..c5d5b3e 100644
--- a/cli-main.c
+++ b/cli-main.c
@@ -1,6 +1,17 @@
-#include <includes.h>
+#include "includes.h"
+#include "dbutil.h"
+#include "runopts.h"
+#include "session.h"
+static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
+static void cli_dropbear_log(int priority, const char* format, va_list param);
+
+#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
+int cli_main(int argc, char ** argv) {
+#else
int main(int argc, char ** argv) {
+#endif
int sock;
char* error = NULL;
@@ -12,6 +23,9 @@ int main(int argc, char ** argv) {
cli_getopts(argc, argv);
+ TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
+ cli_opts.remotehost, cli_opts.remoteport));
+
sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
@@ -23,7 +37,7 @@ int main(int argc, char ** argv) {
len = strlen(cli_opts.remotehost);
len += 10; /* 16 bit port and leeway*/
hostandport = (char*)m_malloc(len);
- snprintf(hostandport, len, "%s%d",
+ snprintf(hostandport, len, "%s:%s",
cli_opts.remotehost, cli_opts.remoteport);
cli_session(sock, hostandport);
@@ -31,3 +45,34 @@ int main(int argc, char ** argv) {
/* not reached */
return -1;
}
+#endif /* DBMULTI stuff */
+
+static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
+
+ char fmtbuf[300];
+
+ if (!sessinitdone) {
+ snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s",
+ format);
+ } else {
+ snprintf(fmtbuf, sizeof(fmtbuf),
+ "connection to %s@%s:%s exited: %s",
+ cli_opts.username, cli_opts.remotehost,
+ cli_opts.remoteport, format);
+ }
+
+ _dropbear_log(LOG_INFO, fmtbuf, param);
+
+ common_session_cleanup();
+ exit(exitcode);
+}
+
+static void cli_dropbear_log(int priority, const char* format, va_list param) {
+
+ char printbuf[1024];
+
+ vsnprintf(printbuf, sizeof(printbuf), format, param);
+
+ fprintf(stderr, "Dropbear: %s\n", printbuf);
+
+}
diff --git a/cli-service.c b/cli-service.c
new file mode 100644
index 0000000..c873919
--- /dev/null
+++ b/cli-service.c
@@ -0,0 +1,62 @@
+#include "includes.h"
+#include "service.h"
+#include "dbutil.h"
+#include "packet.h"
+#include "buffer.h"
+#include "session.h"
+#include "ssh.h"
+
+void send_msg_service_request(char* servicename) {
+
+ TRACE(("enter send_msg_service_request: servicename='%s'", servicename));
+
+ CHECKCLEARTOWRITE();
+
+ buf_putbyte(ses.payload, SSH_MSG_SERVICE_REQUEST);
+ buf_putstring(ses.payload, servicename, strlen(servicename));
+
+ encrypt_packet();
+ TRACE(("leave send_msg_service_request"));
+}
+
+/* This just sets up the state variables right for the main client session loop
+ * to deal with */
+void recv_msg_service_accept() {
+
+ unsigned char* servicename;
+ unsigned int len;
+
+ TRACE(("enter recv_msg_service_accept"));
+
+ servicename = buf_getstring(ses.payload, &len);
+
+ /* ssh-userauth */
+ if (cli_ses.state = SERVICE_AUTH_REQ_SENT
+ && len == SSH_SERVICE_USERAUTH_LEN
+ && strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
+
+ cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
+ m_free(servicename);
+ TRACE(("leave recv_msg_service_accept: done ssh-userauth"));
+ return;
+ }
+
+ /* ssh-connection */
+ if (cli_ses.state = SERVICE_CONN_REQ_SENT
+ && len == SSH_SERVICE_CONNECTION_LEN
+ && strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
+
+ if (ses.authstate.authdone != 1) {
+ dropbear_exit("request for connection before auth");
+ }
+
+ cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
+ m_free(servicename);
+ TRACE(("leave recv_msg_service_accept: done ssh-connection"));
+ return;
+ }
+
+ dropbear_exit("unrecognised service accept");
+ /* m_free(servicename); not reached */
+
+}
diff --git a/cli-session.c b/cli-session.c
index d5afaf9..9f80bd1 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -8,9 +8,11 @@
#include "tcpfwd-remote.h"
#include "channel.h"
#include "random.h"
+#include "service.h"
static void cli_remoteclosed();
static void cli_sessionloop();
+static void cli_session_init();
struct clientsession cli_ses; /* GLOBAL */
@@ -28,6 +30,8 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close},
{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
+ {SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure},
+ {SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success},
{0, 0} /* End */
};
@@ -37,6 +41,7 @@ static const struct ChanType *cli_chantypes[] = {
* that forwarding */
NULL /* Null termination */
};
+
void cli_session(int sock, char* remotehost) {
crypto_init();
@@ -44,11 +49,9 @@ void cli_session(int sock, char* remotehost) {
chaninitialise(cli_chantypes);
- /* For printing "remote host closed" for the user */
- session_remoteclosed = cli_remoteclosed;
- /* packet handlers */
- ses.packettypes = cli_packettypes;
+ /* Set up cli_ses vars */
+ cli_session_init();
/* Ready to go */
sessinitdone = 1;
@@ -66,26 +69,85 @@ void cli_session(int sock, char* remotehost) {
/* Not reached */
+}
+
+static void cli_session_init() {
+ cli_ses.state = STATE_NOTHING;
+ cli_ses.kex_state = KEX_NOTHING;
+
+ /* For printing "remote host closed" for the user */
+ ses.remoteclosed = cli_remoteclosed;
+ ses.buf_match_algo = cli_buf_match_algo;
+
+ /* packet handlers */
+ ses.packettypes = cli_packettypes;
}
+/* This function drives the progress of the session - it initiates KEX,
+ * service, userauth and channel requests */
static void cli_sessionloop() {
- switch (cli_ses.state) {
+ TRACE(("enter cli_sessionloop"));
+
+ if (cli_ses.kex_state == KEX_NOTHING && ses.kexstate.recvkexinit) {
+ cli_ses.state = KEXINIT_RCVD;
+ }
- KEXINIT_RCVD:
- /* We initiate the KEX. If DH wasn't the correct type, the KEXINIT
- * negotiation would have failed. */
- send_msg_kexdh_init();
- cli_ses.state = KEXDH_INIT_SENT;
- break;
+ if (cli_ses.state == KEXINIT_RCVD) {
- default:
- break;
+ /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
+ * negotiation would have failed. */
+ send_msg_kexdh_init();
+ cli_ses.kex_state = KEXDH_INIT_SENT;
+ TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"));
+ return;
}
- if (cli_ses.donefirstkex && !cli_ses.authdone) {
+ /* A KEX has finished, so we should go back to our KEX_NOTHING state */
+ if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
+ && ses.kexstate.sentkexinit == 0) {
+ cli_ses.kex_state = KEX_NOTHING;
+ }
+
+ /* We shouldn't do anything else if a KEX is in progress */
+ if (cli_ses.kex_state != KEX_NOTHING) {
+ TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"));
+ return;
+ }
+ /* We should exit if we haven't donefirstkex: we shouldn't reach here
+ * in normal operation */
+ if (ses.kexstate.donefirstkex == 0) {
+ TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"));
+ }
+
+ switch (cli_ses.state) {
+
+ case STATE_NOTHING:
+ /* We've got the transport layer sorted, we now need to request
+ * userauth */
+ send_msg_service_request(SSH_SERVICE_USERAUTH);
+ cli_ses.state = SERVICE_AUTH_REQ_SENT;
+ return;
+
+ /* userauth code */
+ case SERVICE_AUTH_ACCEPT_RCVD:
+ cli_get_user();
+ cli_auth_getmethods();
+ cli_ses.state = USERAUTH_METHODS_SENT;
+ return;
+
+ case USERAUTH_FAIL_RCVD:
+ cli_auth_try();
+ return;
+
+ /* XXX more here needed */
+
+
+ default:
+ break;
+ }
}
@@ -97,5 +159,5 @@ static void cli_remoteclosed() {
* already sent/received disconnect message(s) ??? */
close(ses.sock);
ses.sock = -1;
- dropbear_exit("%s closed the connection", ses.remotehost);
+ dropbear_exit("remote closed the connection");
}
diff --git a/common-kex.c b/common-kex.c
index 21accb6..9847a48 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -5,7 +5,7 @@
* This code is copied from the larger file "kex.c"
* some functions are verbatim, others are generalized --mihnea
*
- * Copyright (c) 2002,2003 Matt Johnston
+ * Copyright (c) 2002-2004 Matt Johnston
* Portions Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
@@ -54,10 +54,12 @@ const unsigned char dh_p_val[] = {
const int DH_G_VAL = 2;
+static void kexinitialise();
static void gen_new_keys();
#ifndef DISABLE_ZLIB
static void gen_new_zstreams();
#endif
+static void read_kex_algos();
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, int outlen,
const hash_state * hs, unsigned const char X);
@@ -145,6 +147,7 @@ void send_msg_newkeys() {
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"));
ses.dataallowed = 1; /* we can send other packets again now */
+ ses.kexstate.donefirstkex = 1;
} else {
ses.kexstate.sentnewkeys = 1;
TRACE(("SENTNEWKEYS=1"));
@@ -168,6 +171,7 @@ void recv_msg_newkeys() {
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"));
ses.dataallowed = 1; /* we can send other packets again now */
+ ses.kexstate.donefirstkex = 1;
} else {
TRACE(("RECVNEWKEYS=1"));
ses.kexstate.recvnewkeys = 1;
@@ -177,8 +181,15 @@ void recv_msg_newkeys() {
}
-/* Duplicated verbatim from kex.c --mihnea */
-void kexinitialise() {
+/* Set up the kex for the first time */
+void kexfirstinitialise() {
+
+ ses.kexstate.donefirstkex = 0;
+ kexinitialise();
+}
+
+/* Reset the kex state, ready for a new negotiation */
+static void kexinitialise() {
struct timeval tv;
@@ -404,7 +415,7 @@ void recv_msg_kexinit() {
#ifdef DROPBEAR_CLIENT
/* read the peer's choice of algos */
- read_kex_algos(cli_buf_match_algo);
+ read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
@@ -423,14 +434,13 @@ void recv_msg_kexinit() {
buf_getptr(ses.payload, ses.payload->len),
ses.payload->len);
- cli_ses.state = KEXINIT_RCVD;
#endif
} else {
/* SERVER */
#ifdef DROPBEAR_SERVER
/* read the peer's choice of algos */
- read_kex_algos(svr_buf_match_algo);
+ read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
ses.remoteident, strlen((char*)ses.remoteident));
@@ -583,9 +593,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
/* read the other side's algo list. buf_match_algo is a callback to match
* algos for the client or server. */
-void read_kex_algos(
- algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[],
- int *goodguess)) {
+static void read_kex_algos() {
algo_type * algo;
char * erralgo = NULL;
@@ -599,7 +607,7 @@ void read_kex_algos(
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
/* kex_algorithms */
- algo = buf_match_algo(ses.payload, sshkex, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "kex";
@@ -608,7 +616,7 @@ void read_kex_algos(
ses.newkeys->algo_kex = algo->val;
/* server_host_key_algorithms */
- algo = buf_match_algo(ses.payload, sshhostkey, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
@@ -617,7 +625,7 @@ void read_kex_algos(
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
- algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
erralgo = "enc c->s";
goto error;
@@ -625,7 +633,7 @@ void read_kex_algos(
ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;
/* encryption_algorithms_server_to_client */
- algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
erralgo = "enc s->c";
goto error;
@@ -633,7 +641,7 @@ void read_kex_algos(
ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;
/* mac_algorithms_client_to_server */
- algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
erralgo = "mac c->s";
goto error;
@@ -641,7 +649,7 @@ void read_kex_algos(
ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;
/* mac_algorithms_server_to_client */
- algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
erralgo = "mac s->c";
goto error;
@@ -649,7 +657,7 @@ void read_kex_algos(
ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;
/* compression_algorithms_client_to_server */
- algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
erralgo = "comp c->s";
goto error;
@@ -657,7 +665,7 @@ void read_kex_algos(
ses.newkeys->recv_algo_comp = algo->val;
/* compression_algorithms_server_to_client */
- algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
+ algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
erralgo = "comp s->c";
goto error;
diff --git a/common-runopts.c b/common-runopts.c
new file mode 100644
index 0000000..097ab12
--- /dev/null
+++ b/common-runopts.c
@@ -0,0 +1,28 @@
+/*
+ * Dropbear - a SSH2 server
+ *
+ * Copyright (c) 2002,2003 Matt Johnston
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
+#include "includes.h"
+#include "runopts.h"
+
+runopts opts; /* GLOBAL */
diff --git a/common-session.c b/common-session.c
index 70ddbfe..93e7c74 100644
--- a/common-session.c
+++ b/common-session.c
@@ -45,8 +45,6 @@ int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
-void(*session_remoteclosed)() = NULL;
-
static void checktimeouts();
static int ident_readln(int fd, char* buf, int count);
@@ -63,7 +61,7 @@ void common_session_init(int sock, char* remotehost) {
ses.connecttimeout = 0;
- kexinitialise(); /* initialise the kex state */
+ kexfirstinitialise(); /* initialise the kex state */
chaninitialise(); /* initialise the channel state */
ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN);
@@ -104,8 +102,6 @@ void common_session_init(int sock, char* remotehost) {
ses.dh_K = NULL;
ses.remoteident = NULL;
- ses.authdone = 0;
-
ses.chantypes = NULL;
ses.allowprivport = 0;
diff --git a/dbmulti.c b/dbmulti.c
index 8f39227..24adce1 100644
--- a/dbmulti.c
+++ b/dbmulti.c
@@ -19,6 +19,11 @@ int main(int argc, char ** argv) {
return dropbear_main(argc, argv);
}
#endif
+#ifdef DBMULTI_dbclient
+ if (strcmp(progname, "dbclient") == 0) {
+ return cli_main(argc, argv);
+ }
+#endif
#ifdef DBMULTI_dropbearkey
if (strcmp(progname, "dropbearkey") == 0) {
return dropbearkey_main(argc, argv);
@@ -41,6 +46,9 @@ int main(int argc, char ** argv) {
#ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n"
#endif
+#ifdef DBMULTI_dbclient
+ "'dbclient' - the Dropbear client\n"
+#endif
#ifdef DBMULTI_dropbearkey
"'dropbearkey' - the key generator\n"
#endif
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/kex.h b/kex.h
index e6c8ac1..01626ed 100644
--- a/kex.h
+++ b/kex.h
@@ -32,15 +32,11 @@ void send_msg_kexinit();
void recv_msg_kexinit();
void send_msg_newkeys();
void recv_msg_newkeys();
-void kexinitialise();
+void kexfirstinitialise();
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
sign_key *hostkey);
-void read_kex_algos(
- algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[],
- int *goodguess));
-
void recv_msg_kexdh_init(); // server
void send_msg_kexdh_init(); // client
@@ -59,6 +55,9 @@ struct KEXState {
unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/
unsigned recvnewkeys : 1;
+ unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
+ ie the transport layer has been set up */
+
long lastkextime; /* time of the last kex */
unsigned int datatrans; /* data transmitted since last kex */
unsigned int datarecv; /* data received since last kex */
diff --git a/options.h b/options.h
index 3aeac0f..ee0ee60 100644
--- a/options.h
+++ b/options.h
@@ -29,8 +29,6 @@
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
-#define DROPBEAR_SERVER
-//#define DROPBEAR_CLIENT
#ifndef DROPBEAR_PORT
#define DROPBEAR_PORT 22
@@ -48,7 +46,6 @@
* perhaps 20% slower for pubkey operations (it is probably worth experimenting
* if you want to use this) */
/*#define NO_FAST_EXPTMOD*/
-#define DROPBEAR_SMALL_CODE
/* Enable X11 Forwarding */
#define ENABLE_X11FWD
@@ -114,7 +111,7 @@
/* Authentication types to enable, at least one required.
RFC Draft requires pubkey auth, and recommends password */
#define DROPBEAR_PASSWORD_AUTH
-#define DROPBEAR_PUBKEY_AUTH
+//#define DROPBEAR_PUBKEY_AUTH
/* Random device to use - you must specify _one only_.
* DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use
@@ -162,20 +159,8 @@
/* This is used by the scp binary when used as a client binary */
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
-/* Multi-purpose binary configuration - if you want to make the combined
- * binary, first define DROPBEAR_MULTI, and then define which of the three
- * components you want. You should then compile Dropbear with
- * "make clean; make dropbearmulti". You'll need to install the binary
- * manually, see MULTI for details */
-
-/* #define DROPBEAR_MULTI */
-
-/* The three multi binaries: dropbear, dropbearkey, dropbearconvert
- * Comment out these if you don't want some of them */
-#define DBMULTI_DROPBEAR
-#define DBMULTI_KEY
-#define DBMULTI_CONVERT
-
+/* Multi-purpose binary configuration has now moved. Look at the top
+ * of the Makefile for instructions, or INSTALL */
/*******************************************************************
* You shouldn't edit below here unless you know you need to.
@@ -246,7 +231,7 @@
#define DROPBEAR_COMP_ZLIB 1
/* Required for pubkey auth */
-#ifdef DROPBEAR_PUBKEY_AUTH
+#if defined(DROPBEAR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT)
#define DROPBEAR_SIGNKEY_VERIFY
#endif
diff --git a/packet.c b/packet.c
index 886fe67..997bc6f 100644
--- a/packet.c
+++ b/packet.c
@@ -73,7 +73,7 @@ void write_packet() {
}
if (written == 0) {
- session_remoteclosed();
+ ses.remoteclosed();
}
if (written == len) {
@@ -122,7 +122,7 @@ void read_packet() {
len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen);
if (len == 0) {
- session_remoteclosed();
+ ses.remoteclosed();
}
if (len < 0) {
@@ -171,7 +171,7 @@ static void read_packet_init() {
len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen),
maxlen);
if (len == 0) {
- session_remoteclosed();
+ ses.remoteclosed();
}
if (len < 0) {
if (errno == EINTR) {
diff --git a/runopts.h b/runopts.h
index 1bf1539..125d737 100644
--- a/runopts.h
+++ b/runopts.h
@@ -79,7 +79,11 @@ void svr_getopts(int argc, char ** argv);
/* Uncompleted XXX matt */
typedef struct cli_runopts {
- int todo;
+ char *remotehost;
+ char *remoteport;
+
+ char *username;
+ /* XXX TODO */
} cli_runopts;
diff --git a/scp.c b/scp.c
index b23dec6..b6eec88 100644
--- a/scp.c
+++ b/scp.c
@@ -229,8 +229,12 @@ void tolocal(int, char *[]);
void toremote(char *, int, char *[]);
void usage(void);
-int
+#if defined(DBMULTI_scp) || !defined(DROPBEAR_MULTI)
+#if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI)
+int scp_main(int argc, char **argv)
+#else
main(int argc, char **argv)
+#endif
{
int ch, fflag, tflag, status;
double speed;
@@ -379,6 +383,7 @@ main(int argc, char **argv)
}
exit(errs != 0);
}
+#endif /* DBMULTI stuff */
void
toremote(char *targ, int argc, char **argv)
diff --git a/service.h b/service.h
index 0dfcd6e..5f50347 100644
--- a/service.h
+++ b/service.h
@@ -25,6 +25,7 @@
#ifndef _SERVICE_H_
#define _SERVICE_H_
-void recv_msg_service_request();
+void recv_msg_service_request(); /* Server */
+void send_msg_service_request(); /* Client */
#endif /* _SERVICE_H_ */
diff --git a/session.h b/session.h
index d929c1c..4a7e0ac 100644
--- a/session.h
+++ b/session.h
@@ -45,7 +45,6 @@ void common_session_cleanup();
void checktimeouts();
void session_identification();
-extern void(*session_remoteclosed)();
/* Server */
void svr_session(int sock, int childpipe, char *remotehost);
@@ -135,13 +134,18 @@ struct sshsession {
buffer* transkexinit; /* the kexinit packet we send should be kept so we
can add it to the hash when generating keys */
+ algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
+ int *goodguess); /* The function to use to choose which algorithm
+ to use from the ones presented by the remote
+ side. Is specific to the client/server mode,
+ hence the function-pointer callback.*/
- unsigned char authdone; /* Indicates when authentication has been
- completed. This applies to both client and
- server - in the server it gets set to 1 when
- authentication is successful, in the client it
- is set when the server has told us that auth
- succeeded */
+ void(*remoteclosed)(); /* A callback to handle closure of the
+ remote connection */
+
+
+ struct AuthState authstate; /* Common amongst client and server, since most
+ struct elements are common */
/* Channel related */
struct Channel ** channels; /* these pointers may be null */
@@ -165,7 +169,6 @@ struct serversession {
/* Server specific options */
int childpipe; /* kept open until we successfully authenticate */
/* userauth */
- struct AuthState authstate;
struct ChildPid * childpids; /* array of mappings childpid<->channel */
unsigned int childpidsize;
@@ -173,17 +176,30 @@ struct serversession {
};
typedef enum {
- NOTHING,
+ KEX_NOTHING,
KEXINIT_RCVD,
KEXDH_INIT_SENT,
- KEXDH_REPLY_RCVD,
+ KEXDONE,
+
+} cli_kex_state;
+
+typedef enum {
+ STATE_NOTHING,
+ SERVICE_AUTH_REQ_SENT,
+ SERVICE_AUTH_ACCEPT_RCVD,
+ SERVICE_CONN_REQ_SENT,
+ SERVICE_CONN_ACCEPT_RCVD,
+ USERAUTH_METHODS_SENT,
+ USERAUTH_REQ_SENT,
+ USERAUTH_FAIL_RCVD,
} cli_state;
struct clientsession {
mp_int *dh_e, *dh_x; /* Used during KEX */
- cli_state state; /* Used to progress the KEX/auth/channelsession etc */
+ cli_kex_state kex_state; /* Used for progressing KEX */
+ cli_state state; /* Used to progress auth/channelsession etc */
int something; /* XXX */
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
diff --git a/svr-agentfwd.c b/svr-agentfwd.c
index fd068fe..0dad2a4 100644
--- a/svr-agentfwd.c
+++ b/svr-agentfwd.c
@@ -152,8 +152,8 @@ void agentcleanup(struct ChanSess * chansess) {
* for themselves */
uid = getuid();
gid = getgid();
- if ((setegid(svr_ses.authstate.pw->pw_gid)) < 0 ||
- (seteuid(svr_ses.authstate.pw->pw_uid)) < 0) {
+ if ((setegid(ses.authstate.pw->pw_gid)) < 0 ||
+ (seteuid(ses.authstate.pw->pw_uid)) < 0) {
dropbear_exit("failed to set euid");
}
@@ -215,8 +215,8 @@ static int bindagent(int fd, struct ChanSess * chansess) {
/* drop to user privs to make the dir/file */
uid = getuid();
gid = getgid();
- if ((setegid(svr_ses.authstate.pw->pw_gid)) < 0 ||
- (seteuid(svr_ses.authstate.pw->pw_uid)) < 0) {
+ if ((setegid(ses.authstate.pw->pw_gid)) < 0 ||
+ (seteuid(ses.authstate.pw->pw_uid)) < 0) {
dropbear_exit("failed to set euid");
}
diff --git a/svr-auth.c b/svr-auth.c
index 7b588c0..0f0ef67 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -41,9 +41,9 @@ static int checkusername(unsigned char *username, unsigned int userlen);
static void send_msg_userauth_banner();
/* initialise the first time for a session, resetting all parameters */
-void authinitialise() {
+void svr_authinitialise() {
- svr_ses.authstate.failcount = 0;
+ ses.authstate.failcount = 0;
authclear();
}
@@ -53,17 +53,13 @@ void authinitialise() {
* on initialisation */
static void authclear() {
- ses.authdone = 0;
- svr_ses.authstate.pw = NULL;
- svr_ses.authstate.username = NULL;
- svr_ses.authstate.printableuser = NULL;
- svr_ses.authstate.authtypes = 0;
+ memset(&ses.authstate, 0, sizeof(ses.authstate));
#ifdef DROPBEAR_PUBKEY_AUTH
- svr_ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
+ ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
#endif
#ifdef DROPBEAR_PASSWORD_AUTH
if (svr_opts.noauthpass) {
- svr_ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
+ ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
}
#endif
@@ -103,7 +99,7 @@ void recv_msg_userauth_request() {
TRACE(("enter recv_msg_userauth_request"));
/* ignore packets if auth is already done */
- if (ses.authdone == 1) {
+ if (ses.authstate.authdone == 1) {
return;
}
@@ -147,12 +143,12 @@ void recv_msg_userauth_request() {
#ifdef DROPBEAR_PASSWORD_AUTH
if (!svr_opts.noauthpass &&
- !(svr_opts.norootpass && svr_ses.authstate.pw->pw_uid == 0) ) {
+ !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) {
/* user wants to try password auth */
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
- passwordauth();
+ svr_auth_password();
goto out;
}
}
@@ -163,7 +159,7 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
strncmp(methodname, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN) == 0) {
- pubkeyauth();
+ svr_auth_pubkey();
goto out;
}
#endif
@@ -192,21 +188,21 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
}
/* new user or username has changed */
- if (svr_ses.authstate.username == NULL ||
- strcmp(username, svr_ses.authstate.username) != 0) {
+ if (ses.authstate.username == NULL ||
+ strcmp(username, ses.authstate.username) != 0) {
/* the username needs resetting */
- if (svr_ses.authstate.username != NULL) {
+ if (ses.authstate.username != NULL) {
dropbear_log(LOG_WARNING, "client trying multiple usernames");
- m_free(svr_ses.authstate.username);
+ m_free(ses.authstate.username);
}
authclear();
- svr_ses.authstate.pw = getpwnam((char*)username);
- svr_ses.authstate.username = m_strdup(username);
- m_free(svr_ses.authstate.printableuser);
+ ses.authstate.pw = getpwnam((char*)username);
+ ses.authstate.username = m_strdup(username);
+ m_free(ses.authstate.printableuser);
}
/* check that user exists */
- if (svr_ses.authstate.pw == NULL) {
+ if (ses.authstate.pw == NULL) {
TRACE(("leave checkusername: user '%s' doesn't exist", username));
dropbear_log(LOG_WARNING,
"login attempt for nonexistent user");
@@ -215,10 +211,10 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
}
/* We can set it once we know its a real user */
- svr_ses.authstate.printableuser = m_strdup(svr_ses.authstate.pw->pw_name);
+ ses.authstate.printableuser = m_strdup(ses.authstate.pw->pw_name);
/* check for non-root if desired */
- if (svr_opts.norootlogin && svr_ses.authstate.pw->pw_uid == 0) {
+ if (svr_opts.norootlogin && ses.authstate.pw->pw_uid == 0) {
TRACE(("leave checkusername: root login disabled"));
dropbear_log(LOG_WARNING, "root login rejected");
send_msg_userauth_failure(0, 1);
@@ -226,18 +222,18 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
}
/* check for an empty password */
- if (svr_ses.authstate.pw->pw_passwd[0] == '\0') {
+ if (ses.authstate.pw->pw_passwd[0] == '\0') {
TRACE(("leave checkusername: empty pword"));
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
- TRACE(("shell is %s", svr_ses.authstate.pw->pw_shell));
+ TRACE(("shell is %s", ses.authstate.pw->pw_shell));
/* check that the shell is set */
- usershell = svr_ses.authstate.pw->pw_shell;
+ usershell = ses.authstate.pw->pw_shell;
if (usershell[0] == '\0') {
/* empty shell in /etc/passwd means /bin/sh according to passwd(5) */
usershell = "/bin/sh";
@@ -258,7 +254,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
endusershell();
TRACE(("no matching shell"));
dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
@@ -266,7 +262,7 @@ goodshell:
endusershell();
TRACE(("matching shell"));
- TRACE(("uid = %d", svr_ses.authstate.pw->pw_uid));
+ TRACE(("uid = %d", ses.authstate.pw->pw_uid));
TRACE(("leave checkusername"));
return DROPBEAR_SUCCESS;
@@ -290,14 +286,14 @@ void send_msg_userauth_failure(int partial, int incrfail) {
/* put a list of allowed types */
typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
- if (svr_ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
+ if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
- if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
+ if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
buf_putbyte(typebuf, ',');
}
}
- if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
+ if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
}
@@ -311,18 +307,18 @@ void send_msg_userauth_failure(int partial, int incrfail) {
if (incrfail) {
usleep(300000); /* XXX improve this */
- svr_ses.authstate.failcount++;
+ ses.authstate.failcount++;
}
- if (svr_ses.authstate.failcount >= MAX_AUTH_TRIES) {
+ if (ses.authstate.failcount >= MAX_AUTH_TRIES) {
char * userstr;
/* XXX - send disconnect ? */
TRACE(("Max auth tries reached, exiting"));
- if (svr_ses.authstate.printableuser == NULL) {
+ if (ses.authstate.printableuser == NULL) {
userstr = "is invalid";
} else {
- userstr = svr_ses.authstate.printableuser;
+ userstr = ses.authstate.printableuser;
}
dropbear_exit("Max auth tries reached - user %s", userstr);
}
@@ -340,9 +336,9 @@ void send_msg_userauth_success() {
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS);
encrypt_packet();
- ses.authdone = 1;
+ ses.authstate.authdone = 1;
- if (svr_ses.authstate.pw->pw_uid == 0) {
+ if (ses.authstate.pw->pw_uid == 0) {
ses.allowprivport = 1;
}
diff --git a/svr-authpasswd.c b/svr-authpasswd.c
index 859cfd5..f161b69 100644
--- a/svr-authpasswd.c
+++ b/svr-authpasswd.c
@@ -35,7 +35,7 @@
/* Process a password auth request, sending success or failure messages as
* appropriate */
-void passwordauth() {
+void svr_auth_password() {
#ifdef HAVE_SHADOW_H
struct spwd *spasswd;
@@ -47,10 +47,10 @@ void passwordauth() {
unsigned char changepw;
- passwdcrypt = svr_ses.authstate.pw->pw_passwd;
+ passwdcrypt = ses.authstate.pw->pw_passwd;
#ifdef HAVE_SHADOW_H
/* get the shadow password if possible */
- spasswd = getspnam(svr_ses.authstate.pw->pw_name);
+ spasswd = getspnam(ses.authstate.pw->pw_name);
if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
passwdcrypt = spasswd->sp_pwdp;
}
@@ -66,7 +66,7 @@ void passwordauth() {
* in auth.c */
if (passwdcrypt[0] == '\0') {
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
return;
}
@@ -92,12 +92,12 @@ void passwordauth() {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"password auth succeeded for '%s'",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"bad password attempt for '%s'",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
}
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index e3e6947..9c58a8d 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -50,7 +50,7 @@ static int getauthline(buffer * line, FILE * authfile);
/* process a pubkey auth request, sending success or failure message as
* appropriate */
-void pubkeyauth() {
+void svr_auth_pubkey() {
unsigned char testkey; /* whether we're just checking if a key is usable */
unsigned char* algo = NULL; /* pubkey algo */
@@ -113,12 +113,12 @@ void pubkeyauth() {
signbuf->len) == DROPBEAR_SUCCESS) {
dropbear_log(LOG_NOTICE,
"pubkey auth succeeded for '%s' with key %s",
- svr_ses.authstate.printableuser, fp);
+ ses.authstate.printableuser, fp);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"pubkey auth bad signature for '%s' with key %s",
- svr_ses.authstate.printableuser, fp);
+ ses.authstate.printableuser, fp);
send_msg_userauth_failure(0, 1);
}
m_free(fp);
@@ -178,7 +178,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
if (have_algo(algo, algolen, sshhostkey) == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING,
"pubkey auth attempt with unknown algo for '%s'",
- svr_ses.authstate.printableuser);
+ ses.authstate.printableuser);
goto out;
}
@@ -190,12 +190,12 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
/* we don't need to check pw and pw_dir for validity, since
* its been done in checkpubkeyperms. */
- len = strlen(svr_ses.authstate.pw->pw_dir);
+ len = strlen(ses.authstate.pw->pw_dir);
/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
- svr_ses.authstate.pw->pw_dir);
+ ses.authstate.pw->pw_dir);
/* open the file */
authfile = fopen(filename, "r");
@@ -352,19 +352,19 @@ static int checkpubkeyperms() {
TRACE(("enter checkpubkeyperms"));
- assert(svr_ses.authstate.pw);
- if (svr_ses.authstate.pw->pw_dir == NULL) {
+ assert(ses.authstate.pw);
+ if (ses.authstate.pw->pw_dir == NULL) {
goto out;
}
- if ((len = strlen(svr_ses.authstate.pw->pw_dir)) == 0) {
+ if ((len = strlen(ses.authstate.pw->pw_dir)) == 0) {
goto out;
}
/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
- strncpy(filename, svr_ses.authstate.pw->pw_dir, len+1);
+ strncpy(filename, ses.authstate.pw->pw_dir, len+1);
/* check ~ */
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
@@ -406,7 +406,7 @@ static int checkfileperm(char * filename) {
return DROPBEAR_FAILURE;
}
/* check ownership - user or root only*/
- if (filestat.st_uid != svr_ses.authstate.pw->pw_uid
+ if (filestat.st_uid != ses.authstate.pw->pw_uid
&& filestat.st_uid != 0) {
TRACE(("leave checkfileperm: wrong ownership"));
return DROPBEAR_FAILURE;
diff --git a/svr-chansession.c b/svr-chansession.c
index cbc7ebe..50e0a5e 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -239,7 +239,7 @@ static void closechansess(struct Channel *channel) {
if (chansess->tty) {
/* write the utmp/wtmp login record */
- li = login_alloc_entry(chansess->pid, svr_ses.authstate.username,
+ li = login_alloc_entry(chansess->pid, ses.authstate.username,
ses.remotehost, chansess->tty);
login_logout(li);
login_free_entry(li);
@@ -425,7 +425,7 @@ static int sessionpty(struct ChanSess * chansess) {
dropbear_exit("out of memory"); /* TODO disconnect */
}
- pty_setowner(svr_ses.authstate.pw, chansess->tty);
+ pty_setowner(ses.authstate.pw, chansess->tty);
pty_change_window_size(chansess->master, chansess->termr, chansess->termc,
chansess->termw, chansess->termh);
@@ -683,7 +683,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* write the utmp/wtmp login record - must be after changing the
* terminal used for stdout with the dup2 above */
- li= login_alloc_entry(getpid(), svr_ses.authstate.username,
+ li= login_alloc_entry(getpid(), ses.authstate.username,
ses.remotehost, chansess->tty);
login_login(li);
login_free_entry(li);
@@ -695,10 +695,10 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* don't show the motd if ~/.hushlogin exists */
/* 11 == strlen("/hushlogin\0") */
- len = strlen(svr_ses.authstate.pw->pw_dir) + 11;
+ len = strlen(ses.authstate.pw->pw_dir) + 11;
hushpath = m_malloc(len);
- snprintf(hushpath, len, "%s/hushlogin", svr_ses.authstate.pw->pw_dir);
+ snprintf(hushpath, len, "%s/hushlogin", ses.authstate.pw->pw_dir);
if (stat(hushpath, &sb) < 0) {
/* more than a screenful is stupid IMHO */
@@ -808,10 +808,10 @@ static void execchild(struct ChanSess *chansess) {
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
- if ((setgid(svr_ses.authstate.pw->pw_gid) < 0) ||
- (initgroups(svr_ses.authstate.pw->pw_name,
- svr_ses.authstate.pw->pw_gid) < 0) ||
- (setuid(svr_ses.authstate.pw->pw_uid) < 0)) {
+ if ((setgid(ses.authstate.pw->pw_gid) < 0) ||
+ (initgroups(ses.authstate.pw->pw_name,
+ ses.authstate.pw->pw_gid) < 0) ||
+ (setuid(ses.authstate.pw->pw_uid) < 0)) {
dropbear_exit("error changing user");
}
} else {
@@ -822,29 +822,29 @@ static void execchild(struct ChanSess *chansess) {
* usernames with the same uid, but differing groups, then the
* differing groups won't be set (as with initgroups()). The solution
* is for the sysadmin not to give out the UID twice */
- if (getuid() != svr_ses.authstate.pw->pw_uid) {
+ if (getuid() != ses.authstate.pw->pw_uid) {
dropbear_exit("couldn't change user as non-root");
}
}
/* an empty shell should be interpreted as "/bin/sh" */
- if (svr_ses.authstate.pw->pw_shell[0] == '\0') {
+ if (ses.authstate.pw->pw_shell[0] == '\0') {
usershell = "/bin/sh";
} else {
- usershell = svr_ses.authstate.pw->pw_shell;
+ usershell = ses.authstate.pw->pw_shell;
}
/* set env vars */
- addnewvar("USER", svr_ses.authstate.pw->pw_name);
- addnewvar("LOGNAME", svr_ses.authstate.pw->pw_name);
- addnewvar("HOME", svr_ses.authstate.pw->pw_dir);
+ addnewvar("USER", ses.authstate.pw->pw_name);
+ addnewvar("LOGNAME", ses.authstate.pw->pw_name);
+ addnewvar("HOME", ses.authstate.pw->pw_dir);
addnewvar("SHELL", usershell);
if (chansess->term != NULL) {
addnewvar("TERM", chansess->term);
}
/* change directory */
- if (chdir(svr_ses.authstate.pw->pw_dir) < 0) {
+ if (chdir(ses.authstate.pw->pw_dir) < 0) {
dropbear_exit("error changing directory");
}
diff --git a/svr-runopts.c b/svr-runopts.c
index 1f5b0c6..c79208c 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -106,8 +106,8 @@ void svr_getopts(int argc, char ** argv) {
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
/* not yet
- svr_opts.ipv4 = 1;
- svr_opts.ipv6 = 1;
+ opts.ipv4 = 1;
+ opts.ipv6 = 1;
*/
#ifdef DO_MOTD
svr_opts.domotd = 1;
diff --git a/svr-service.c b/svr-service.c
index 7b717bf..e823490 100644
--- a/svr-service.c
+++ b/svr-service.c
@@ -56,7 +56,7 @@ void recv_msg_service_request() {
/* ssh-connection */
if (len == SSH_SERVICE_CONNECTION_LEN &&
(strncmp(SSH_SERVICE_CONNECTION, name, len) == 0)) {
- if (ses.authdone != 1) {
+ if (ses.authstate.authdone != 1) {
dropbear_exit("request for connection before auth");
}
@@ -70,7 +70,6 @@ void recv_msg_service_request() {
/* TODO this should be a MSG_DISCONNECT */
dropbear_exit("unrecognised SSH_MSG_SERVICE_REQUEST");
- TRACE(("leave recv_msg_service_request"));
}
diff --git a/svr-session.c b/svr-session.c
index cb309fe..80c622a 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -79,7 +79,7 @@ void svr_session(int sock, int childpipe, char* remotehost) {
/* Initialise server specific parts of the session */
svr_ses.childpipe = childpipe;
- authinitialise();
+ svr_authinitialise();
chaninitialise(svr_chantypes);
svr_chansessinitialise();
@@ -90,10 +90,11 @@ void svr_session(int sock, int childpipe, char* remotehost) {
ses.connecttimeout = timeout.tv_sec + AUTH_TIMEOUT;
/* set up messages etc */
- session_remoteclosed = svr_remoteclosed;
+ ses.remoteclosed = svr_remoteclosed;
/* packet handlers */
ses.packettypes = svr_packettypes;
+ ses.buf_match_algo = svr_buf_match_algo;
/* We're ready to go now */
sessinitdone = 1;
@@ -123,16 +124,16 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
/* before session init */
snprintf(fmtbuf, sizeof(fmtbuf),
"premature exit: %s", format);
- } else if (svr_ses.authstate.authdone) {
+ } else if (ses.authstate.authdone) {
/* user has authenticated */
snprintf(fmtbuf, sizeof(fmtbuf),
"exit after auth (%s): %s",
- svr_ses.authstate.printableuser, format);
- } else if (svr_ses.authstate.printableuser) {
+ ses.authstate.printableuser, format);
+ } else if (ses.authstate.printableuser) {
/* we have a potential user */
snprintf(fmtbuf, sizeof(fmtbuf),
"exit before auth (user '%s', %d fails): %s",
- svr_ses.authstate.printableuser, svr_ses.authstate.failcount, format);
+ ses.authstate.printableuser, ses.authstate.failcount, format);
} else {
/* before userauth */
snprintf(fmtbuf, sizeof(fmtbuf),