1
0
mirror of https://github.com/clearml/dropbear synced 2025-04-23 15:44:35 +00:00

Progressing client support

--HG--
extra : convert_revision : 48946be1cef774d1c33b0f78689962b18720c627
This commit is contained in:
Matt Johnston 2004-07-27 16:30:46 +00:00
parent 052bf7df93
commit a76b1ba068
28 changed files with 601 additions and 178 deletions

View File

@ -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:

30
auth.h
View File

@ -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;
};

148
cli-auth.c Normal file
View File

@ -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"));
}

36
cli-authpasswd.c Normal file
View File

@ -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 */
}

View File

@ -34,6 +34,7 @@
#include "bignum.h"
#include "random.h"
#include "runopts.h"
#include "signkey.h"

View File

@ -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);
}

62
cli-service.c Normal file
View File

@ -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 */
}

View File

@ -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,27 +69,86 @@ 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() {
TRACE(("enter cli_sessionloop"));
if (cli_ses.kex_state == KEX_NOTHING && ses.kexstate.recvkexinit) {
cli_ses.state = KEXINIT_RCVD;
}
if (cli_ses.state == KEXINIT_RCVD) {
/* 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;
}
/* 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) {
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;
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;
default:
break;
/* 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;
}
if (cli_ses.donefirstkex && !cli_ses.authdone) {
}
@ -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");
}

View File

@ -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;

28
common-runopts.c Normal file
View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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

9
kex.h
View File

@ -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 */

View File

@ -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

View File

@ -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) {

View File

@ -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;

7
scp.c
View File

@ -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)

View File

@ -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_ */

View File

@ -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 */

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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;

View File

@ -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"));
}

View File

@ -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),