mirror of
https://github.com/clearml/dropbear
synced 2025-05-07 21:44:45 +00:00
merge of '48fdaa8706d1acda35e9d564adc9a1fbc96c18c8'
and '658fd03abd21e0da7c4c89b9fff9dc693c72daae' --HG-- extra : convert_revision : 8064882fcaa13d586651021462b9014b74332107
This commit is contained in:
commit
ddbfdb0799
Makefile.inagentfwd.halgo.hauth.hbuffer.cbuffer.hchannel.hchansession.hcli-agentfwd.ccli-auth.ccli-authpubkey.ccli-chansession.ccli-kex.ccli-main.ccli-runopts.ccli-session.ccli-tcpfwd.ccommon-algo.ccommon-kex.ccommon-session.cconfigure.indbclient.1dbutil.cdbutil.hdebug.hdropbear.8list.clist.hoptions.hpacket.cpacket.hrandom.crunopts.hscp.csession.hsignkey.csignkey.hssh.hsvr-agentfwd.csvr-auth.csvr-authpam.csvr-authpubkeyoptions.csvr-chansession.csvr-main.csvr-runopts.csvr-session.csysoptions.htcpfwd.h
@ -20,16 +20,17 @@ COMMONOBJS=dbutil.o buffer.o \
|
||||
dss.o bignum.o \
|
||||
signkey.o rsa.o random.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
|
||||
svr-tcpfwd.o svr-authpam.o
|
||||
svr-tcpfwd.o svr-authpam.o @CRYPTLIB@
|
||||
|
||||
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
|
||||
cli-agentfwd.o list.o
|
||||
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
@ -40,7 +41,7 @@ KEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
|
||||
CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
|
||||
|
||||
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
|
||||
|
25
agentfwd.h
25
agentfwd.h
@ -23,21 +23,34 @@
|
||||
* SOFTWARE. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "auth.h"
|
||||
#include "list.h"
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
#define MAX_AGENT_REPLY 10000
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
int agentreq(struct ChanSess * chansess);
|
||||
void agentsetauth(struct ChanSess *chansess);
|
||||
void agentcleanup(struct ChanSess * chansess);
|
||||
void agentset(struct ChanSess *chansess);
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
#define setegid(a) setresgid(-1, (a), -1)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD */
|
||||
extern const struct ChanType cli_chan_agent;
|
||||
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
|
3
algo.h
3
algo.h
@ -50,7 +50,8 @@ extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type sshcompress[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_none;
|
||||
|
18
auth.h
18
auth.h
@ -26,6 +26,7 @@
|
||||
#define _AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
#include "chansession.h"
|
||||
|
||||
void svr_authinitialise();
|
||||
@ -73,6 +74,7 @@ void cli_auth_password();
|
||||
int cli_auth_pubkey();
|
||||
void cli_auth_interactive();
|
||||
char* getpass_or_cancel(char* prompt);
|
||||
void cli_auth_pubkey_cleanup();
|
||||
|
||||
|
||||
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
|
||||
@ -97,7 +99,6 @@ char* getpass_or_cancel(char* prompt);
|
||||
* 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 */
|
||||
unsigned char authtypes; /* Flags indicating which auth types are still
|
||||
@ -120,19 +121,6 @@ struct AuthState {
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
struct PubKeyOptions* pubkey_options;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct SignKeyList;
|
||||
/* A singly linked list of signing keys */
|
||||
struct SignKeyList {
|
||||
|
||||
sign_key *key;
|
||||
int type; /* The type of key */
|
||||
struct SignKeyList *next;
|
||||
/* filename? or the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
@ -145,7 +133,7 @@ struct PubKeyOptions {
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
unsigned char * forced_command;
|
||||
|
||||
unsigned char * original_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
14
buffer.c
14
buffer.c
@ -223,6 +223,20 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
buffer *ret;
|
||||
unsigned char* str;
|
||||
unsigned int len;
|
||||
str = buf_getstring(buf, &len);
|
||||
ret = m_malloc(sizeof(*ret));
|
||||
ret->data = str;
|
||||
ret->len = len;
|
||||
ret->size = len;
|
||||
ret->pos = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
|
1
buffer.h
1
buffer.h
@ -55,6 +55,7 @@ void buf_putbyte(buffer* buf, unsigned char val);
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
|
@ -58,7 +58,7 @@ struct Channel {
|
||||
unsigned int recvmaxpacket, transmaxpacket;
|
||||
void* typedata; /* a pointer to type specific data */
|
||||
int writefd; /* read from wire, written to insecure side */
|
||||
int readfd; /* read from insecure size, written to wire */
|
||||
int readfd; /* read from insecure side, written to wire */
|
||||
int errfd; /* used like writefd or readfd, depending if it's client or server.
|
||||
Doesn't exactly belong here, but is cleaner here */
|
||||
circbuffer *writebuf; /* data from the wire, for local consumption */
|
||||
|
@ -50,6 +50,10 @@ struct ChanSess {
|
||||
|
||||
/* exit details */
|
||||
struct exitinfo exit;
|
||||
|
||||
/* Used to set $SSH_CONNECTION in the child session.
|
||||
Is only set temporarily before forking */
|
||||
char *connection_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
struct Listener * x11listener;
|
||||
@ -60,7 +64,7 @@ struct ChanSess {
|
||||
unsigned char x11singleconn;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
struct Listener * agentlistener;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
@ -81,6 +85,7 @@ void cli_chansess_winchange();
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
void cli_send_netcat_request();
|
||||
#endif
|
||||
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
void svr_chansessinitialise();
|
||||
extern const struct ChanType svrchansess;
|
||||
|
311
cli-agentfwd.c
Normal file
311
cli-agentfwd.c
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2005 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"
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "dbutil.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "atomicio.h"
|
||||
#include "signkey.h"
|
||||
#include "auth.h"
|
||||
|
||||
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
|
||||
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
|
||||
|
||||
static int new_agent_chan(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
new_agent_chan,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int connect_agent() {
|
||||
|
||||
int fd = -1;
|
||||
char* agent_sock = NULL;
|
||||
|
||||
agent_sock = getenv("SSH_AUTH_SOCK");
|
||||
if (agent_sock == NULL)
|
||||
return -1;
|
||||
|
||||
fd = connect_unix(agent_sock);
|
||||
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_INFO, "Failed to connect to agent");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
// handle a request for a connection to the locally running ssh-agent
|
||||
// or forward.
|
||||
static int new_agent_chan(struct Channel * channel) {
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if (!cli_opts.agent_fwd)
|
||||
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
return SSH_OPEN_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
setnonblocking(fd);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, fd);
|
||||
|
||||
channel->readfd = fd;
|
||||
channel->writefd = fd;
|
||||
|
||||
// success
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sends a request to the agent, returning a newly allocated buffer
|
||||
* with the response */
|
||||
/* This function will block waiting for a response - it will
|
||||
* only be used by client authentication (not for forwarded requests)
|
||||
* won't cause problems for interactivity. */
|
||||
/* Packet format (from draft-ylonen)
|
||||
4 bytes Length, msb first. Does not include length itself.
|
||||
1 byte Packet type. The value 255 is reserved for future extensions.
|
||||
data Any data, depending on packet type. Encoding as in the ssh packet
|
||||
protocol.
|
||||
*/
|
||||
static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
|
||||
buffer * payload = NULL;
|
||||
buffer * inbuf = NULL;
|
||||
size_t readlen = 0;
|
||||
ssize_t ret;
|
||||
const int fd = cli_opts.agent_fd;
|
||||
unsigned int data_len = 0;
|
||||
if (data)
|
||||
{
|
||||
data_len = data->len;
|
||||
}
|
||||
|
||||
payload = buf_new(4 + 1 + data_len);
|
||||
|
||||
buf_putint(payload, 1 + data_len);
|
||||
buf_putbyte(payload, type);
|
||||
if (data) {
|
||||
buf_putbytes(payload, data->data, data->len);
|
||||
}
|
||||
buf_setpos(payload, 0);
|
||||
|
||||
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
|
||||
if ((size_t)ret != payload->len) {
|
||||
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf_free(payload);
|
||||
payload = NULL;
|
||||
TRACE(("Wrote out bytes for agent_request"))
|
||||
/* Now we read the response */
|
||||
inbuf = buf_new(4);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
|
||||
if (ret != 4) {
|
||||
TRACE(("read of length failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_setpos(inbuf, 0);
|
||||
buf_setlen(inbuf, ret);
|
||||
|
||||
readlen = buf_getint(inbuf);
|
||||
if (readlen > MAX_AGENT_REPLY) {
|
||||
TRACE(("agent reply is too big"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE(("agent_request readlen is %d", readlen))
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
if ((size_t)ret != readlen) {
|
||||
TRACE(("read of data failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrwritepos(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
TRACE(("agent_request success, length %d", readlen))
|
||||
|
||||
out:
|
||||
if (payload)
|
||||
buf_free(payload);
|
||||
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
static void agent_get_key_list(m_list * ret_list)
|
||||
{
|
||||
buffer * inbuf = NULL;
|
||||
unsigned int num = 0;
|
||||
unsigned char packet_type;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
|
||||
if (!inbuf) {
|
||||
TRACE(("agent_request failed returning identities"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The reply has a format of:
|
||||
byte SSH2_AGENT_IDENTITIES_ANSWER
|
||||
uint32 num_keys
|
||||
Followed by zero or more consecutive keys, encoded as:
|
||||
string key_blob
|
||||
string key_comment
|
||||
*/
|
||||
packet_type = buf_getbyte(inbuf);
|
||||
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = buf_getint(inbuf);
|
||||
for (i = 0; i < num; i++) {
|
||||
sign_key * pubkey = NULL;
|
||||
int key_type = DROPBEAR_SIGNKEY_ANY;
|
||||
buffer * key_buf;
|
||||
|
||||
/* each public key is encoded as a string */
|
||||
key_buf = buf_getstringbuf(inbuf);
|
||||
pubkey = new_sign_key();
|
||||
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
|
||||
buf_free(key_buf);
|
||||
if (ret != DROPBEAR_SUCCESS) {
|
||||
/* This is slack, properly would cleanup vars etc */
|
||||
dropbear_exit("Bad pubkey received from agent");
|
||||
}
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
}
|
||||
|
||||
out:
|
||||
if (inbuf) {
|
||||
buf_free(inbuf);
|
||||
inbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_setup_agent(struct Channel *channel) {
|
||||
if (!getenv("SSH_AUTH_SOCK")) {
|
||||
return;
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
/* Returned keys are prepended to ret_list, which will
|
||||
be updated. */
|
||||
void cli_load_agent_keys(m_list *ret_list) {
|
||||
/* agent_fd will be closed after successful auth */
|
||||
cli_opts.agent_fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
agent_get_key_list(ret_list);
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
buffer *request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
buffer *response;
|
||||
unsigned int keylen, siglen;
|
||||
int packet_type;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
string key_blob
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
/* We write the key, then figure how long it was and write that */
|
||||
//buf_putint(request_data, 0);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
keylen = request_data->len - 4;
|
||||
//buf_setpos(request_data, 0);
|
||||
//buf_putint(request_data, keylen);
|
||||
|
||||
//buf_setpos(request_data, request_data->len);
|
||||
buf_putstring(request_data, data, len);
|
||||
buf_putint(request_data, 0);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
buf_free(request_data);
|
||||
|
||||
if (!response) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
packet_type = buf_getbyte(response);
|
||||
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Response format
|
||||
byte SSH2_AGENT_SIGN_RESPONSE
|
||||
string signature_blob
|
||||
*/
|
||||
siglen = buf_getint(response);
|
||||
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
|
||||
buf_free(response);
|
||||
|
||||
return;
|
||||
fail:
|
||||
/* XXX don't fail badly here. instead propagate a failure code back up to
|
||||
the cli auth pubkey code, and just remove this key from the list of
|
||||
ones to try. */
|
||||
dropbear_exit("Agent failed signing key");
|
||||
}
|
||||
|
||||
#endif
|
@ -91,7 +91,7 @@ void recv_msg_userauth_banner() {
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s\n", banner);
|
||||
fprintf(stderr, "%s\n", banner);
|
||||
|
||||
out:
|
||||
m_free(banner);
|
||||
@ -234,6 +234,10 @@ void recv_msg_userauth_success() {
|
||||
ses.authstate.authdone = 1;
|
||||
cli_ses.state = USERAUTH_SUCCESS_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_auth_pubkey_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void cli_auth_try() {
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
#include "auth.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
@ -37,30 +38,23 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
void cli_pubkeyfail() {
|
||||
|
||||
struct SignKeyList *keyitem;
|
||||
struct SignKeyList **previtem;
|
||||
|
||||
TRACE(("enter cli_pubkeyfail"))
|
||||
previtem = &cli_opts.privkeys;
|
||||
|
||||
/* Find the key we failed with, and remove it */
|
||||
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
if (keyitem == cli_ses.lastprivkey) {
|
||||
*previtem = keyitem->next;
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *iter_key = (sign_key*)iter->item;
|
||||
|
||||
if (iter_key == cli_ses.lastprivkey)
|
||||
{
|
||||
/* found the failing key */
|
||||
list_remove(iter);
|
||||
sign_key_free(iter_key);
|
||||
cli_ses.lastprivkey = NULL;
|
||||
return;
|
||||
}
|
||||
previtem = &keyitem;
|
||||
}
|
||||
|
||||
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
|
||||
m_free(cli_ses.lastprivkey);
|
||||
|
||||
TRACE(("leave cli_pubkeyfail"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_pk_ok() {
|
||||
|
||||
struct SignKeyList *keyitem = NULL;
|
||||
m_list_elem *iter;
|
||||
buffer* keybuf = NULL;
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
@ -80,9 +74,9 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
/* Iterate through our keys, find which one it was that matched, and
|
||||
* send a real request with that key */
|
||||
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
|
||||
if (keyitem->type != keytype) {
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *key = (sign_key*)iter->item;
|
||||
if (key->type != keytype) {
|
||||
/* Types differed */
|
||||
TRACE(("types differed"))
|
||||
continue;
|
||||
@ -90,7 +84,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
/* Now we compare the contents of the key */
|
||||
keybuf->pos = keybuf->len = 0;
|
||||
buf_put_pub_key(keybuf, keyitem->key, keytype);
|
||||
buf_put_pub_key(keybuf, key, keytype);
|
||||
buf_setpos(keybuf, 0);
|
||||
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
|
||||
remotelen) which has already been taken from
|
||||
@ -114,11 +108,11 @@ void recv_msg_userauth_pk_ok() {
|
||||
}
|
||||
buf_free(keybuf);
|
||||
|
||||
if (keyitem != NULL) {
|
||||
if (iter != NULL) {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey(keyitem->key, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
@ -126,6 +120,25 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len)
|
||||
{
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data, len);
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
buf_free(sigblob);
|
||||
} else {
|
||||
buf_put_sign(buf, key, type, data, len);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
@ -161,7 +174,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
|
||||
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
@ -169,20 +182,41 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
TRACE(("leave send_msg_userauth_pubkey"))
|
||||
}
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
if (cli_opts.privkeys != NULL) {
|
||||
if (!cli_opts.agent_keys_loaded) {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(cli_opts.privkeys->key,
|
||||
cli_opts.privkeys->type, 0);
|
||||
cli_ses.lastprivkey = cli_opts.privkeys;
|
||||
send_msg_userauth_pubkey(key, key->type, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
} else {
|
||||
/* no more keys left */
|
||||
TRACE(("leave cli_auth_pubkey-failure"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_auth_pubkey_cleanup() {
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
m_close(cli_opts.agent_fd);
|
||||
cli_opts.agent_fd = -1;
|
||||
#endif
|
||||
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
}
|
||||
}
|
||||
#endif /* Pubkey auth */
|
||||
|
@ -33,13 +33,12 @@
|
||||
#include "runopts.h"
|
||||
#include "termcodes.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
static void cli_closechansess(struct Channel *channel);
|
||||
static int cli_initchansess(struct Channel *channel);
|
||||
static void cli_chansessreq(struct Channel *channel);
|
||||
|
||||
static void start_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
|
||||
@ -92,7 +91,7 @@ static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
|
||||
}
|
||||
|
||||
static void start_channel_request(struct Channel *channel,
|
||||
void cli_start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
@ -287,7 +286,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_chansess_pty_req"))
|
||||
|
||||
start_channel_request(channel, "pty-req");
|
||||
cli_start_send_channel_request(channel, "pty-req");
|
||||
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
@ -330,7 +329,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
|
||||
reqtype = "shell";
|
||||
}
|
||||
|
||||
start_channel_request(channel, reqtype);
|
||||
cli_start_send_channel_request(channel, reqtype);
|
||||
|
||||
/* XXX TODO */
|
||||
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
|
||||
@ -361,6 +360,12 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
cli_init_stdpipe_sess(channel);
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
if (cli_opts.agent_fwd) {
|
||||
cli_setup_agent(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
send_chansess_pty_req(channel);
|
||||
}
|
||||
@ -376,20 +381,20 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
|
||||
const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
};
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
const unsigned char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
};
|
||||
|
||||
cli_opts.wantpty = 0;
|
||||
|
||||
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
|
||||
@ -424,16 +429,3 @@ void cli_send_chansess_request() {
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
while (cli_opts.localfwds != NULL) {
|
||||
ret = cli_localtcp(cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
#endif
|
||||
|
@ -304,7 +304,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
buf_putbytes(line, ses.remotehost, hostlen);
|
||||
buf_putbytes(line, cli_opts.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
@ -327,4 +327,5 @@ out:
|
||||
if (line != NULL) {
|
||||
buf_free(line);
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
16
cli-main.c
16
cli-main.c
@ -32,7 +32,9 @@
|
||||
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);
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out);
|
||||
#endif
|
||||
|
||||
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
|
||||
@ -43,8 +45,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
int sock_in, sock_out;
|
||||
char* error = NULL;
|
||||
char* hostandport;
|
||||
int len;
|
||||
|
||||
_dropbear_exit = cli_dropbear_exit;
|
||||
_dropbear_log = cli_dropbear_log;
|
||||
@ -63,6 +63,7 @@ int main(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
cli_proxy_cmd(&sock_in, &sock_out);
|
||||
m_free(cli_opts.proxycmd);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@ -75,14 +76,7 @@ int main(int argc, char ** argv) {
|
||||
dropbear_exit("%s", error);
|
||||
}
|
||||
|
||||
/* Set up the host:port log */
|
||||
len = strlen(cli_opts.remotehost);
|
||||
len += 10; /* 16 bit port and leeway*/
|
||||
hostandport = (char*)m_malloc(len);
|
||||
snprintf(hostandport, len, "%s:%s",
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
|
||||
cli_session(sock_in, sock_out, hostandport);
|
||||
cli_session(sock_in, sock_out);
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
@ -132,6 +126,7 @@ static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
dropbear_exit("Failed to run '%s'\n", cmd);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
|
||||
int ret;
|
||||
|
||||
@ -144,3 +139,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
|
||||
*sock_in = *sock_out = -1;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_CLI_PROXYCMD
|
||||
|
145
cli-runopts.c
145
cli-runopts.c
@ -29,6 +29,7 @@
|
||||
#include "dbutil.h"
|
||||
#include "algo.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "list.h"
|
||||
|
||||
cli_runopts cli_opts; /* GLOBAL */
|
||||
|
||||
@ -40,7 +41,7 @@ static void fill_own_user();
|
||||
static void loadidentityfile(const char* filename);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, struct TCPFwdList** fwdlist);
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
static void add_netcat(const char *str);
|
||||
@ -66,6 +67,9 @@ static void printhelp() {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
"-L <listenport:remotehost:remoteport> Local port forwarding\n"
|
||||
"-g Allow remote hosts to connect to forwarded ports\n"
|
||||
@ -91,7 +95,6 @@ static void printhelp() {
|
||||
}
|
||||
|
||||
void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
unsigned int i, j;
|
||||
char ** next = 0;
|
||||
unsigned int cmdlen;
|
||||
@ -112,6 +115,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
char* recv_window_arg = NULL;
|
||||
char* keepalive_arg = NULL;
|
||||
char* idle_timeout_arg = NULL;
|
||||
char *host_arg = NULL;
|
||||
|
||||
/* see printhelp() for options */
|
||||
cli_opts.progname = argv[0];
|
||||
@ -125,17 +129,24 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.always_accept_key = 0;
|
||||
cli_opts.is_subsystem = 0;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_opts.privkeys = NULL;
|
||||
cli_opts.privkeys = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
cli_opts.localfwds = NULL;
|
||||
cli_opts.localfwds = list_new();
|
||||
opts.listen_fwd_all = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
cli_opts.remotefwds = NULL;
|
||||
cli_opts.remotefwds = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
cli_opts.agent_fwd = 0;
|
||||
cli_opts.agent_keys_loaded = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
#endif
|
||||
/* not yet
|
||||
opts.ipv4 = 1;
|
||||
@ -158,7 +169,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
if (nextisremote) {
|
||||
TRACE(("nextisremote true"))
|
||||
addforward(argv[i], &cli_opts.remotefwds);
|
||||
addforward(argv[i], cli_opts.remotefwds);
|
||||
nextisremote = 0;
|
||||
continue;
|
||||
}
|
||||
@ -166,7 +177,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
if (nextislocal) {
|
||||
TRACE(("nextislocal true"))
|
||||
addforward(argv[i], &cli_opts.localfwds);
|
||||
addforward(argv[i], cli_opts.localfwds);
|
||||
nextislocal = 0;
|
||||
continue;
|
||||
}
|
||||
@ -266,6 +277,11 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'I':
|
||||
next = &idle_timeout_arg;
|
||||
break;
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
case 'A':
|
||||
cli_opts.agent_fwd = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
@ -304,12 +320,8 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* Either the hostname or commands */
|
||||
|
||||
if (cli_opts.remotehost == NULL) {
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
parse_multihop_hostname(argv[i], argv[0]);
|
||||
#else
|
||||
parse_hostname(argv[i]);
|
||||
#endif
|
||||
if (host_arg == NULL) {
|
||||
host_arg = argv[i];
|
||||
} else {
|
||||
|
||||
/* this is part of the commands to send - after this we
|
||||
@ -338,7 +350,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
if (cli_opts.remotehost == NULL) {
|
||||
if (host_arg == NULL) {
|
||||
printhelp();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -369,15 +381,19 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
if (keepalive_arg) {
|
||||
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
|
||||
}
|
||||
opts.keepalive_secs = val;
|
||||
}
|
||||
|
||||
if (idle_timeout_arg) {
|
||||
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
|
||||
}
|
||||
opts.idle_timeout_secs = val;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
@ -385,36 +401,73 @@ void cli_getopts(int argc, char ** argv) {
|
||||
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
parse_multihop_hostname(host_arg, argv[0]);
|
||||
#else
|
||||
parse_hostname(host_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
|
||||
struct SignKeyList * nextkey;
|
||||
sign_key *key;
|
||||
int keytype;
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
|
||||
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
sign_key_free(key);
|
||||
|
||||
} else {
|
||||
|
||||
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
|
||||
nextkey->key = key;
|
||||
nextkey->next = cli_opts.privkeys;
|
||||
nextkey->type = keytype;
|
||||
cli_opts.privkeys = nextkey;
|
||||
key->type = keytype;
|
||||
key->source = SIGNKEY_SOURCE_RAW_FILE;
|
||||
key->filename = m_strdup(filename);
|
||||
list_append(cli_opts.privkeys, key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
|
||||
static char*
|
||||
multihop_passthrough_args() {
|
||||
char *ret;
|
||||
int total;
|
||||
unsigned int len = 0;
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i and -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
len += 20; // space for -W <size>, terminator.
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
|
||||
if (opts.recv_window != DEFAULT_RECV_WINDOW)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
|
||||
total += written;
|
||||
}
|
||||
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
const size_t size = len - total;
|
||||
int written = snprintf(ret+total, size, "-i %s", key->filename);
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sets up 'onion-forwarding' connections. This will spawn
|
||||
* a separate dbclient process for each hop.
|
||||
* As an example, if the cmdline is
|
||||
@ -429,7 +482,8 @@ static void loadidentityfile(const char* filename) {
|
||||
*/
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
|
||||
char *userhostarg = NULL;
|
||||
char *last_hop = NULL;;
|
||||
char *hostbuf = NULL;
|
||||
char *last_hop = NULL;
|
||||
char *remainder = NULL;
|
||||
|
||||
/* both scp and rsync parse a user@host argument
|
||||
@ -441,11 +495,12 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
&& strchr(cli_opts.username, ',')
|
||||
&& strchr(cli_opts.username, '@')) {
|
||||
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
|
||||
userhostarg = m_malloc(len);
|
||||
snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
|
||||
hostbuf = m_malloc(len);
|
||||
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
|
||||
} else {
|
||||
userhostarg = m_strdup(orighostarg);
|
||||
hostbuf = m_strdup(orighostarg);
|
||||
}
|
||||
userhostarg = hostbuf;
|
||||
|
||||
last_hop = strrchr(userhostarg, ',');
|
||||
if (last_hop) {
|
||||
@ -463,19 +518,28 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
if (last_hop) {
|
||||
/* Set up the proxycmd */
|
||||
unsigned int cmd_len = 0;
|
||||
char *passthrough_args = multihop_passthrough_args();
|
||||
if (cli_opts.proxycmd) {
|
||||
dropbear_exit("-J can't be used with multihop mode");
|
||||
}
|
||||
if (cli_opts.remoteport == NULL) {
|
||||
cli_opts.remoteport = "22";
|
||||
}
|
||||
cmd_len = strlen(remainder)
|
||||
cmd_len = strlen(argv0) + strlen(remainder)
|
||||
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
|
||||
+ strlen(argv0) + 30;
|
||||
+ strlen(passthrough_args)
|
||||
+ 30;
|
||||
cli_opts.proxycmd = m_malloc(cmd_len);
|
||||
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
|
||||
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
|
||||
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
|
||||
argv0, cli_opts.remotehost, cli_opts.remoteport,
|
||||
passthrough_args, remainder);
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* The stream will be incompressible since it's encrypted. */
|
||||
opts.enable_compress = 0;
|
||||
#endif
|
||||
m_free(passthrough_args);
|
||||
}
|
||||
m_free(hostbuf);
|
||||
}
|
||||
#endif /* !ENABLE_CLI_MULTIHOP */
|
||||
|
||||
@ -566,14 +630,14 @@ static void fill_own_user() {
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
|
||||
* set, and add it to the forwarding list */
|
||||
static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
static void addforward(const char* origstr, m_list *fwdlist) {
|
||||
|
||||
char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
|
||||
char * listenaddr = NULL;
|
||||
char * listenport = NULL;
|
||||
char * connectaddr = NULL;
|
||||
char * connectport = NULL;
|
||||
struct TCPFwdList* newfwd = NULL;
|
||||
struct TCPFwdEntry* newfwd = NULL;
|
||||
char * str = NULL;
|
||||
|
||||
TRACE(("enter addforward"))
|
||||
@ -618,7 +682,9 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
connectport = part3;
|
||||
}
|
||||
|
||||
newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
|
||||
}
|
||||
|
||||
newfwd = m_malloc(sizeof(struct TCPFwdEntry));
|
||||
|
||||
/* Now we check the ports - note that the port ints are unsigned,
|
||||
* the check later only checks for >= MAX_PORT */
|
||||
@ -646,8 +712,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
}
|
||||
|
||||
newfwd->have_reply = 0;
|
||||
newfwd->next = *fwdlist;
|
||||
*fwdlist = newfwd;
|
||||
list_append(fwdlist, newfwd);
|
||||
|
||||
TRACE(("leave addforward: done"))
|
||||
return;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "service.h"
|
||||
#include "runopts.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
@ -74,17 +75,20 @@ static const packettype cli_packettypes[] = {
|
||||
static const struct ChanType *cli_chantypes[] = {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
&cli_chan_tcpremote,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
&cli_chan_agent,
|
||||
#endif
|
||||
NULL /* Null termination */
|
||||
};
|
||||
|
||||
void cli_session(int sock_in, int sock_out, char* remotehost) {
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
seedrandom();
|
||||
|
||||
crypto_init();
|
||||
|
||||
common_session_init(sock_in, sock_out, remotehost);
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
@ -231,7 +235,7 @@ static void cli_sessionloop() {
|
||||
cli_send_netcat_request();
|
||||
} else
|
||||
#endif
|
||||
if (!cli_opts.no_cmd) {
|
||||
if (!cli_opts.no_cmd) {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
TRACE(("leave cli_sessionloop: running"))
|
||||
|
102
cli-tcpfwd.c
102
cli-tcpfwd.c
@ -61,30 +61,25 @@ static const struct ChanType cli_chan_tcplocal = {
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
void setup_localtcp() {
|
||||
|
||||
m_list_elem *iter;
|
||||
int ret;
|
||||
|
||||
TRACE(("enter setup_localtcp"))
|
||||
|
||||
if (cli_opts.localfwds == NULL) {
|
||||
TRACE(("cli_opts.localfwds == NULL"))
|
||||
}
|
||||
|
||||
while (cli_opts.localfwds != NULL) {
|
||||
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
|
||||
ret = cli_localtcp(
|
||||
cli_opts.localfwds->listenaddr,
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
|
||||
cli_opts.localfwds->listenaddr,
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
}
|
||||
|
||||
cli_opts.localfwds = cli_opts.localfwds->next;
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
}
|
||||
}
|
||||
TRACE(("leave setup_localtcp"))
|
||||
|
||||
@ -156,63 +151,49 @@ static void send_msg_global_request_remotetcp(const char *addr, int port) {
|
||||
* being in the same order as we sent the requests. This is the ordering
|
||||
* of the cli_opts.remotefwds list */
|
||||
void cli_recv_msg_request_success() {
|
||||
|
||||
/* Nothing in the packet. We just mark off that we have received the reply,
|
||||
* so that we can report failure for later ones. */
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
while (iter != NULL) {
|
||||
if (!iter->have_reply)
|
||||
{
|
||||
iter->have_reply = 1;
|
||||
m_list_elem * iter = NULL;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
return;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_recv_msg_request_failure() {
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
while (iter != NULL) {
|
||||
if (!iter->have_reply)
|
||||
{
|
||||
iter->have_reply = 1;
|
||||
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
|
||||
return;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
void setup_remotetcp() {
|
||||
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter setup_remotetcp"))
|
||||
|
||||
if (cli_opts.remotefwds == NULL) {
|
||||
TRACE(("cli_opts.remotefwds == NULL"))
|
||||
}
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
if (!iter->listenaddr)
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->listenaddr)
|
||||
{
|
||||
// we store the addresses so that we can compare them
|
||||
// when the server sends them back
|
||||
if (opts.listen_fwd_all) {
|
||||
iter->listenaddr = m_strdup("");
|
||||
fwd->listenaddr = m_strdup("");
|
||||
} else {
|
||||
iter->listenaddr = m_strdup("localhost");
|
||||
fwd->listenaddr = m_strdup("localhost");
|
||||
}
|
||||
}
|
||||
send_msg_global_request_remotetcp(iter->listenaddr, iter->listenport);
|
||||
iter = iter->next;
|
||||
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
|
||||
}
|
||||
|
||||
TRACE(("leave setup_remotetcp"))
|
||||
}
|
||||
|
||||
@ -220,7 +201,8 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
|
||||
char *origaddr = NULL;
|
||||
unsigned int origport;
|
||||
struct TCPFwdList * iter = NULL;
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd;
|
||||
char portstring[NI_MAXSERV];
|
||||
int sock;
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
@ -229,14 +211,12 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* Find which port corresponds */
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
if (origport == iter->listenport
|
||||
&& (strcmp(origaddr, iter->listenaddr) == 0)) {
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport
|
||||
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
|
||||
break;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
if (iter == NULL) {
|
||||
@ -247,8 +227,8 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
|
||||
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
|
||||
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
|
||||
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
|
||||
if (sock < 0) {
|
||||
TRACE(("leave newtcpdirect: sock failed"))
|
||||
err = SSH_OPEN_CONNECT_FAILED;
|
||||
@ -265,7 +245,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
err = SSH_OPEN_IN_PROGRESS;
|
||||
|
||||
out:
|
||||
m_free(origaddr);
|
||||
m_free(origaddr);
|
||||
TRACE(("leave newtcpdirect: err %d", err))
|
||||
return err;
|
||||
}
|
||||
|
@ -31,7 +31,9 @@
|
||||
|
||||
static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
unsigned long len, void *cipher_state) {
|
||||
memcpy(out, in, len);
|
||||
if (in != out) {
|
||||
memmove(out, in, len);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@ -166,11 +168,16 @@ algo_type sshhashes[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshcompress[] = {
|
||||
#ifndef DISABLE_ZLIB
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
#endif
|
||||
|
||||
algo_type ssh_nocompress[] = {
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
135
common-kex.c
135
common-kex.c
@ -33,6 +33,7 @@
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
static const unsigned char dh_p_val[] = {
|
||||
@ -91,10 +92,10 @@ void send_msg_kexinit() {
|
||||
buf_put_algolist(ses.writepayload, sshhashes);
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
buf_put_algolist(ses.writepayload, ses.compress_algos);
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
buf_put_algolist(ses.writepayload, ses.compress_algos);
|
||||
|
||||
/* languages_client_to_server */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
@ -180,8 +181,16 @@ void recv_msg_newkeys() {
|
||||
|
||||
/* Set up the kex for the first time */
|
||||
void kexfirstinitialise() {
|
||||
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (opts.enable_compress) {
|
||||
ses.compress_algos = ssh_compress;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
}
|
||||
kexinitialise();
|
||||
}
|
||||
|
||||
@ -272,8 +281,8 @@ void gen_new_keys() {
|
||||
recv_IV = S2C_IV;
|
||||
trans_key = C2S_key;
|
||||
recv_key = S2C_key;
|
||||
C2S_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
mactransletter = 'E';
|
||||
macrecvletter = 'F';
|
||||
} else {
|
||||
@ -281,8 +290,8 @@ void gen_new_keys() {
|
||||
recv_IV = C2S_IV;
|
||||
trans_key = S2C_key;
|
||||
recv_key = C2S_key;
|
||||
C2S_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
mactransletter = 'F';
|
||||
macrecvletter = 'E';
|
||||
}
|
||||
@ -292,31 +301,33 @@ void gen_new_keys() {
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
|
||||
recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("crypto error");
|
||||
if (ses.newkeys->recv_crypt_mode->start(recv_cipher,
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv_cipher_state) != CRYPT_OK) {
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
|
||||
trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("crypto error");
|
||||
if (ses.newkeys->trans_crypt_mode->start(trans_cipher,
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans_cipher_state) != CRYPT_OK) {
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
|
||||
/* MAC keys */
|
||||
hashkeys(ses.newkeys->transmackey,
|
||||
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recvmackey,
|
||||
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstreams();
|
||||
@ -334,15 +345,15 @@ void gen_new_keys() {
|
||||
#ifndef DISABLE_ZLIB
|
||||
|
||||
int is_compress_trans() {
|
||||
return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| (ses.authstate.authdone
|
||||
&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
int is_compress_recv() {
|
||||
return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| (ses.authstate.authdone
|
||||
&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
@ -350,47 +361,49 @@ int is_compress_recv() {
|
||||
static void gen_new_zstreams() {
|
||||
|
||||
/* create new zstreams */
|
||||
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv_zstream->zfree = Z_NULL;
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zfree = Z_NULL;
|
||||
|
||||
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
|
||||
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->recv_zstream = NULL;
|
||||
ses.newkeys->recv.zstream = NULL;
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans_zstream->zfree = Z_NULL;
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zfree = Z_NULL;
|
||||
|
||||
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
|
||||
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
|
||||
DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
|
||||
!= Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->trans_zstream = NULL;
|
||||
ses.newkeys->trans.zstream = NULL;
|
||||
}
|
||||
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv_zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv_zstream);
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
if (ses.keys->trans_zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
|
||||
if (ses.keys->trans.zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
m_free(ses.keys->trans_zstream);
|
||||
m_free(ses.keys->trans.zstream);
|
||||
}
|
||||
}
|
||||
#endif /* DISABLE_ZLIB */
|
||||
@ -666,7 +679,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@ -674,7 +687,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@ -698,36 +711,36 @@ static void read_kex_algos() {
|
||||
|
||||
/* Handle the asymmetry */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
ses.newkeys->recv_algo_crypt =
|
||||
ses.newkeys->recv.algo_crypt =
|
||||
(struct dropbear_cipher*)s2c_cipher_algo->data;
|
||||
ses.newkeys->trans_algo_crypt =
|
||||
ses.newkeys->trans.algo_crypt =
|
||||
(struct dropbear_cipher*)c2s_cipher_algo->data;
|
||||
ses.newkeys->recv_crypt_mode =
|
||||
ses.newkeys->recv.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->trans_crypt_mode =
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->recv_algo_mac =
|
||||
ses.newkeys->recv.algo_mac =
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->trans_algo_mac =
|
||||
ses.newkeys->trans.algo_mac =
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
|
||||
} else {
|
||||
/* SERVER */
|
||||
ses.newkeys->recv_algo_crypt =
|
||||
ses.newkeys->recv.algo_crypt =
|
||||
(struct dropbear_cipher*)c2s_cipher_algo->data;
|
||||
ses.newkeys->trans_algo_crypt =
|
||||
ses.newkeys->trans.algo_crypt =
|
||||
(struct dropbear_cipher*)s2c_cipher_algo->data;
|
||||
ses.newkeys->recv_crypt_mode =
|
||||
ses.newkeys->recv.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->trans_crypt_mode =
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->recv_algo_mac =
|
||||
ses.newkeys->recv.algo_mac =
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->trans_algo_mac =
|
||||
ses.newkeys->trans.algo_mac =
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
|
||||
}
|
||||
|
||||
/* reserved for future extensions */
|
||||
|
@ -52,12 +52,10 @@ int exitflag = 0; /* GLOBAL */
|
||||
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
ses.remotehost = remotehost;
|
||||
|
||||
ses.sock_in = sock_in;
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
@ -71,6 +69,9 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
}
|
||||
setnonblocking(ses.signal_pipe[0]);
|
||||
setnonblocking(ses.signal_pipe[1]);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
@ -78,7 +79,6 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
ses.transseq = 0;
|
||||
|
||||
ses.readbuf = NULL;
|
||||
ses.decryptreadbuf = NULL;
|
||||
ses.payload = NULL;
|
||||
ses.recvseq = 0;
|
||||
|
||||
@ -95,22 +95,22 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
/* set all the algos to none */
|
||||
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
ses.newkeys = NULL;
|
||||
ses.keys->recv_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv_crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->trans_crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->recv.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv.crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->trans.crypt_mode = &dropbear_mode_none;
|
||||
|
||||
ses.keys->recv_algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans_algo_mac = &dropbear_nohash;
|
||||
ses.keys->recv.algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans.algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
ses.keys->recv_zstream = NULL;
|
||||
ses.keys->trans_zstream = NULL;
|
||||
ses.keys->recv.zstream = NULL;
|
||||
ses.keys->trans.zstream = NULL;
|
||||
#endif
|
||||
|
||||
/* key exchange buffers */
|
||||
|
@ -82,7 +82,8 @@ AC_CHECK_DECL(__UCLIBC__,
|
||||
],,,)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
|
||||
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
|
||||
AC_SUBST(CRYPTLIB)
|
||||
|
||||
# Check if zlib is needed
|
||||
AC_ARG_WITH(zlib,
|
||||
@ -145,6 +146,7 @@ AC_ARG_ENABLE(pam,
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling PAM)
|
||||
AC_CHECK_FUNCS(pam_fail_delay)
|
||||
else
|
||||
AC_DEFINE(DISABLE_PAM,, Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
|
@ -82,6 +82,11 @@ by the ssh server.
|
||||
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
|
||||
connection will abort as normal.
|
||||
.TP
|
||||
.B \-A
|
||||
Forward agent connections to the remote host. dbclient will use any
|
||||
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
|
||||
public key authentication. Forwarding is only enabled if -A is specified.
|
||||
.TP
|
||||
.B \-W \fIwindowsize
|
||||
Specify the per-channel receive window buffer size. Increasing this
|
||||
may improve network performance at the expense of memory use. Use -h to see the
|
||||
|
144
dbutil.c
144
dbutil.c
@ -295,6 +295,28 @@ int dropbear_listen(const char* address, const char* port,
|
||||
return nsock;
|
||||
}
|
||||
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
struct sockaddr_un addr;
|
||||
int fd = -1;
|
||||
|
||||
memset((void*)&addr, 0x0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
TRACE(("Failed to open unix socket"))
|
||||
return -1;
|
||||
}
|
||||
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
TRACE(("Failed to connect to '%s' socket", path))
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
|
||||
* return immediately if nonblocking is set. On failure, if errstring
|
||||
* wasn't null, it will be a newly malloced error message */
|
||||
@ -341,15 +363,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
|
||||
}
|
||||
|
||||
if (nonblocking) {
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
close(sock);
|
||||
sock = -1;
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
*errstring = m_strdup("Failed non-blocking");
|
||||
}
|
||||
TRACE(("Failed non-blocking: %s", strerror(errno)))
|
||||
continue;
|
||||
}
|
||||
setnonblocking(sock);
|
||||
}
|
||||
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
@ -525,14 +539,47 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
|
||||
execv(usershell, argv);
|
||||
}
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (local_host || local_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, local_host, local_port, host_lookup);
|
||||
}
|
||||
if (remote_host || remote_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, remote_host, remote_port, host_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
char *retstring = NULL;
|
||||
int ret;
|
||||
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
|
||||
|
||||
#ifndef DO_HOST_LOOKUP
|
||||
host_lookup = 0;
|
||||
#endif
|
||||
|
||||
if (host_lookup) {
|
||||
flags = NI_NUMERICSERV;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
@ -550,67 +597,28 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
/* This is a fairly bad failure - it'll fallback to IP if it
|
||||
* just can't resolve */
|
||||
dropbear_exit("failed lookup (%d, %d)", ret, errno);
|
||||
if (host_lookup) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
getaddrstring(addr, ret_host, ret_port, 0);
|
||||
return;
|
||||
} else {
|
||||
/* if we can't do a numeric lookup, something's gone terribly wrong */
|
||||
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (withport) {
|
||||
len = strlen(hbuf) + 2 + strlen(sbuf);
|
||||
retstring = (char*)m_malloc(len);
|
||||
snprintf(retstring, len, "%s:%s", hbuf, sbuf);
|
||||
} else {
|
||||
retstring = m_strdup(hbuf);
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
|
||||
return retstring;
|
||||
|
||||
}
|
||||
|
||||
/* Get the hostname corresponding to the address addr. On failure, the IP
|
||||
* address is returned. The return value is allocated with strdup() */
|
||||
char* getaddrhostname(struct sockaddr_storage * addr) {
|
||||
|
||||
char hbuf[NI_MAXHOST];
|
||||
char sbuf[NI_MAXSERV];
|
||||
int ret;
|
||||
unsigned int len;
|
||||
#ifdef DO_HOST_LOOKUP
|
||||
const int flags = NI_NUMERICSERV;
|
||||
#else
|
||||
const int flags = NI_NUMERICHOST | NI_NUMERICSERV;
|
||||
#endif
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), flags);
|
||||
|
||||
if (ret != 0) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
return getaddrstring(addr, 0);
|
||||
}
|
||||
|
||||
return m_strdup(hbuf);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
|
9
dbutil.h
9
dbutil.h
@ -46,15 +46,20 @@ void printhex(const char * label, const unsigned char * buf, int len);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
char * stripcontrol(const char * text);
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
int *writefd, int *readfd, int *errfd, pid_t *pid);
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* addr);
|
||||
#endif
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring);
|
||||
char* getaddrhostname(struct sockaddr_storage * addr);
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
|
2
debug.h
2
debug.h
@ -39,7 +39,7 @@
|
||||
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/*#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
|
||||
|
30
dropbear.8
30
dropbear.8
@ -7,7 +7,7 @@ dropbear \- lightweight SSH2 server
|
||||
.I banner\fR] [\-d
|
||||
.I dsskey\fR] [\-r
|
||||
.I rsakey\fR] [\-p
|
||||
.IR port ]
|
||||
.IR [address:]port ]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a SSH 2 server designed to be small enough to be used in small memory
|
||||
@ -154,6 +154,34 @@ By default the file /etc/motd will be printed for any login shell (unless
|
||||
disabled at compile-time). This can also be disabled per-user
|
||||
by creating a file ~/.hushlogin .
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
|
||||
|
||||
The variables below are set for sessions as appropriate.
|
||||
|
||||
.TP
|
||||
.B SSH_TTY
|
||||
This is set to the allocated TTY if a PTY was used.
|
||||
|
||||
.TP
|
||||
.B SSH_CONNECTION
|
||||
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
|
||||
|
||||
.TP
|
||||
.B DISPLAY
|
||||
Set X11 forwarding is used.
|
||||
|
||||
.TP
|
||||
.B SSH_ORIGINAL_COMMAND
|
||||
If a 'command=' authorized_keys option was used, the original command is specified
|
||||
in this variable. If a shell was requested this is set to an empty value.
|
||||
|
||||
.TP
|
||||
.B SSH_AUTH_SOCK
|
||||
Set to a forwarded ssh-agent connection.
|
||||
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
|
49
list.c
Normal file
49
list.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include "options.h"
|
||||
#include "dbutil.h"
|
||||
#include "list.h"
|
||||
|
||||
void list_append(m_list *list, void *item) {
|
||||
m_list_elem *elem;
|
||||
|
||||
elem = m_malloc(sizeof(*elem));
|
||||
elem->item = item;
|
||||
elem->list = list;
|
||||
elem->next = NULL;
|
||||
if (!list->first) {
|
||||
list->first = elem;
|
||||
elem->prev = NULL;
|
||||
} else {
|
||||
elem->prev = list->last;
|
||||
list->last->next = elem;
|
||||
}
|
||||
list->last = elem;
|
||||
}
|
||||
|
||||
m_list * list_new() {
|
||||
m_list *ret = m_malloc(sizeof(m_list));
|
||||
ret->first = ret->last = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * list_remove(m_list_elem *elem) {
|
||||
void *item = elem->item;
|
||||
m_list *list = elem->list;
|
||||
if (list->first == elem)
|
||||
{
|
||||
list->first = elem->next;
|
||||
}
|
||||
if (list->last == elem)
|
||||
{
|
||||
list->last = elem->prev;
|
||||
}
|
||||
if (elem->prev)
|
||||
{
|
||||
elem->prev->next = elem->next;
|
||||
}
|
||||
if (elem->next)
|
||||
{
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
m_free(elem);
|
||||
return item;
|
||||
}
|
28
list.h
Normal file
28
list.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _DROPBEAR_LIST_H
|
||||
#define _DROPBEAR_LIST_H
|
||||
|
||||
struct _m_list;
|
||||
|
||||
struct _m_list_elem {
|
||||
void *item;
|
||||
struct _m_list_elem *next;
|
||||
struct _m_list_elem *prev;
|
||||
struct _m_list *list;
|
||||
};
|
||||
|
||||
typedef struct _m_list_elem m_list_elem;
|
||||
|
||||
struct _m_list {
|
||||
m_list_elem *first;
|
||||
m_list_elem *last;
|
||||
};
|
||||
|
||||
typedef struct _m_list m_list;
|
||||
|
||||
m_list * list_new();
|
||||
void list_append(m_list *list, void *item);
|
||||
/* returns the item for the element removed */
|
||||
void * list_remove(m_list_elem *elem);
|
||||
|
||||
|
||||
#endif /* _DROPBEAR_LIST_H */
|
39
options.h
39
options.h
@ -46,9 +46,10 @@
|
||||
/*#define NO_FAST_EXPTMOD*/
|
||||
|
||||
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
|
||||
several kB in binary size, however will make the symmetrical ciphers (AES, DES
|
||||
etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define DROPBEAR_SMALL_CODE
|
||||
several kB in binary size however will make the symmetrical ciphers and hashes
|
||||
slower, perhaps by 50%. Recommended for small systems that aren't doing
|
||||
much traffic. */
|
||||
/*#define DROPBEAR_SMALL_CODE*/
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define ENABLE_X11FWD
|
||||
@ -64,7 +65,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define ENABLE_SVR_REMOTETCPFWD
|
||||
|
||||
/* Enable Authentication Agent Forwarding - server only for now */
|
||||
#define ENABLE_AGENTFWD
|
||||
#define ENABLE_SVR_AGENTFWD
|
||||
#define ENABLE_CLI_AGENTFWD
|
||||
|
||||
|
||||
/* Note: Both ENABLE_CLI_PROXYCMD and ENABLE_CLI_NETCAT must be set to
|
||||
@ -85,7 +87,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define DROPBEAR_AES128
|
||||
#define DROPBEAR_3DES
|
||||
#define DROPBEAR_AES256
|
||||
#define DROPBEAR_BLOWFISH
|
||||
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
|
||||
/*#define DROPBEAR_BLOWFISH*/
|
||||
#define DROPBEAR_TWOFISH256
|
||||
#define DROPBEAR_TWOFISH128
|
||||
|
||||
@ -128,6 +131,21 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
* if the random number source isn't good. In general this isn't required */
|
||||
/* #define DSS_PROTOK */
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8, memLevel=1 for least memory usage, see your system's
|
||||
* zlib.h for full details.
|
||||
* Default settings (windowBits=15, memLevel=8) will use
|
||||
* 256kB for compression + 32kB for decompression.
|
||||
* windowBits=8, memLevel=1 will use 10kB compression + 32kB decompression.
|
||||
* Note that windowBits is only set for deflate() - inflate() always uses the
|
||||
* default of 15 so as to interoperate with other clients. */
|
||||
#ifndef DROPBEAR_ZLIB_WINDOW_BITS
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
#endif
|
||||
#ifndef DROPBEAR_ZLIB_MEM_LEVEL
|
||||
#define DROPBEAR_ZLIB_MEM_LEVEL 8
|
||||
#endif
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
#define DO_HOST_LOOKUP
|
||||
|
||||
@ -154,7 +172,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
/*#define ENABLE_SVR_PAM_AUTH*/
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
|
||||
/* Wether to ake public key options in authorized_keys file into account */
|
||||
/* Whether to take public key options in
|
||||
* authorized_keys file into account */
|
||||
#ifdef ENABLE_SVR_PUBKEY_AUTH
|
||||
#define ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#endif
|
||||
@ -220,7 +239,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#ifndef XAUTH_COMMAND
|
||||
#define XAUTH_COMMAND "/usr/X11R6/bin/xauth -q"
|
||||
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
|
||||
#endif
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
@ -246,13 +265,19 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
significant difference to network performance. 24kB was empirically
|
||||
chosen for a 100mbit ethernet network. The value can be altered at
|
||||
runtime with the -W argument. */
|
||||
#ifndef DEFAULT_RECV_WINDOW
|
||||
#define DEFAULT_RECV_WINDOW 24576
|
||||
#endif
|
||||
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
|
||||
in order to interoperate with other implementations */
|
||||
#ifndef RECV_MAX_PAYLOAD_LEN
|
||||
#define RECV_MAX_PAYLOAD_LEN 32768
|
||||
#endif
|
||||
/* Maximum size of a transmitted data packet - this can be any value,
|
||||
though increasing it may not make a significant difference. */
|
||||
#ifndef TRANS_MAX_PAYLOAD_LEN
|
||||
#define TRANS_MAX_PAYLOAD_LEN 16384
|
||||
#endif
|
||||
|
||||
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
|
||||
be overridden at runtime with -K. 0 disables keepalives */
|
||||
|
308
packet.c
308
packet.c
@ -35,9 +35,11 @@
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
|
||||
static void read_packet_init();
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf);
|
||||
static int checkmac(buffer* hashbuf, buffer* readbuf);
|
||||
static int read_packet_init();
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
buffer * clear_buf, unsigned int clear_len,
|
||||
unsigned char *output_mac);
|
||||
static int checkmac();
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
|
||||
#define ZLIB_DECOMPRESS_INCR 100
|
||||
@ -102,18 +104,18 @@ void read_packet() {
|
||||
unsigned char blocksize;
|
||||
|
||||
TRACE(("enter read_packet"))
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
|
||||
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
|
||||
int ret;
|
||||
/* In the first blocksize of a packet */
|
||||
|
||||
/* Read the first blocksize of the packet, so we can decrypt it and
|
||||
* find the length of the whole packet */
|
||||
read_packet_init();
|
||||
ret = read_packet_init();
|
||||
|
||||
/* If we don't have the length of decryptreadbuf, we didn't read
|
||||
* a whole blocksize and should exit */
|
||||
if (ses.decryptreadbuf->len == 0) {
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* didn't read enough to determine the length */
|
||||
TRACE(("leave read_packet: packetinit done"))
|
||||
return;
|
||||
}
|
||||
@ -121,7 +123,6 @@ void read_packet() {
|
||||
|
||||
/* Attempt to read the remainder of the packet, note that there
|
||||
* mightn't be any available (EAGAIN) */
|
||||
dropbear_assert(ses.readbuf != NULL);
|
||||
maxlen = ses.readbuf->len - ses.readbuf->pos;
|
||||
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
|
||||
|
||||
@ -151,60 +152,61 @@ void read_packet() {
|
||||
|
||||
/* Function used to read the initial portion of a packet, and determine the
|
||||
* length. Only called during the first BLOCKSIZE of a packet. */
|
||||
static void read_packet_init() {
|
||||
/* Returns DROPBEAR_SUCCESS if the length is determined,
|
||||
* DROPBEAR_FAILURE otherwise */
|
||||
static int read_packet_init() {
|
||||
|
||||
unsigned int maxlen;
|
||||
int len;
|
||||
unsigned char blocksize;
|
||||
unsigned char macsize;
|
||||
int slen;
|
||||
unsigned int len;
|
||||
unsigned int blocksize;
|
||||
unsigned int macsize;
|
||||
|
||||
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
if (ses.readbuf == NULL) {
|
||||
/* start of a new packet */
|
||||
ses.readbuf = buf_new(INIT_READBUF);
|
||||
dropbear_assert(ses.decryptreadbuf == NULL);
|
||||
ses.decryptreadbuf = buf_new(blocksize);
|
||||
}
|
||||
|
||||
maxlen = blocksize - ses.readbuf->pos;
|
||||
|
||||
/* read the rest of the packet if possible */
|
||||
len = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
|
||||
slen = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
|
||||
maxlen);
|
||||
if (len == 0) {
|
||||
if (slen == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
if (len < 0) {
|
||||
if (slen < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave read_packet_init: EINTR"))
|
||||
return;
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
dropbear_exit("error reading: %s", strerror(errno));
|
||||
}
|
||||
|
||||
buf_incrwritepos(ses.readbuf, len);
|
||||
buf_incrwritepos(ses.readbuf, slen);
|
||||
|
||||
if ((unsigned int)len != maxlen) {
|
||||
if ((unsigned int)slen != maxlen) {
|
||||
/* don't have enough bytes to determine length, get next time */
|
||||
return;
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* now we have the first block, need to get packet length, so we decrypt
|
||||
* the first block (only need first 4 bytes) */
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
if (ses.keys->recv_crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf,blocksize),
|
||||
if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.readbuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->recv_cipher_state) != CRYPT_OK) {
|
||||
&ses.keys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
buf_setlen(ses.decryptreadbuf, blocksize);
|
||||
len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
/* check packet length */
|
||||
if ((len > RECV_MAX_PACKET_LEN) ||
|
||||
@ -213,9 +215,12 @@ static void read_packet_init() {
|
||||
dropbear_exit("bad packet size %d", len);
|
||||
}
|
||||
|
||||
buf_resize(ses.readbuf, len);
|
||||
if (len > ses.readbuf->size) {
|
||||
buf_resize(ses.readbuf, len);
|
||||
}
|
||||
buf_setlen(ses.readbuf, len);
|
||||
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* handle the received packet */
|
||||
@ -227,69 +232,58 @@ void decrypt_packet() {
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter decrypt_packet"))
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
ses.kexstate.datarecv += ses.readbuf->len;
|
||||
|
||||
/* we've already decrypted the first blocksize in read_packet_init */
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
|
||||
buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
|
||||
buf_setpos(ses.decryptreadbuf, blocksize);
|
||||
|
||||
/* decrypt it */
|
||||
while (ses.readbuf->pos < ses.readbuf->len - macsize) {
|
||||
if (ses.keys->recv_crypt_mode->decrypt(
|
||||
buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->recv_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
buf_incrpos(ses.readbuf, blocksize);
|
||||
buf_incrwritepos(ses.decryptreadbuf, blocksize);
|
||||
/* decrypt it in-place */
|
||||
len = ses.readbuf->len - macsize - ses.readbuf->pos;
|
||||
if (ses.keys->recv.crypt_mode->decrypt(
|
||||
buf_getptr(ses.readbuf, len),
|
||||
buf_getwriteptr(ses.readbuf, len),
|
||||
len,
|
||||
&ses.keys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
buf_incrpos(ses.readbuf, len);
|
||||
|
||||
/* check the hmac */
|
||||
buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
|
||||
if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
|
||||
if (checkmac() != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Integrity error");
|
||||
}
|
||||
|
||||
/* readbuf no longer required */
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
|
||||
/* get padding length */
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
|
||||
padlen = buf_getbyte(ses.decryptreadbuf);
|
||||
buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
|
||||
padlen = buf_getbyte(ses.readbuf);
|
||||
|
||||
/* payload length */
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.decryptreadbuf->len - padlen - 4 - 1;
|
||||
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
|
||||
dropbear_exit("bad packet size");
|
||||
}
|
||||
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (is_compress_recv()) {
|
||||
/* decompress */
|
||||
ses.payload = buf_decompress(ses.decryptreadbuf, len);
|
||||
ses.payload = buf_decompress(ses.readbuf, len);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* copy payload */
|
||||
ses.payload = buf_new(len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
buf_incrlen(ses.payload, len);
|
||||
}
|
||||
|
||||
buf_free(ses.decryptreadbuf);
|
||||
ses.decryptreadbuf = NULL;
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
buf_setpos(ses.payload, 0);
|
||||
|
||||
ses.recvseq++;
|
||||
@ -297,49 +291,22 @@ void decrypt_packet() {
|
||||
TRACE(("leave decrypt_packet"))
|
||||
}
|
||||
|
||||
/* Checks the mac in hashbuf, for the data in readbuf.
|
||||
/* Checks the mac at the end of a decrypted readbuf.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int checkmac(buffer* macbuf, buffer* sourcebuf) {
|
||||
static int checkmac() {
|
||||
|
||||
unsigned int macsize;
|
||||
hmac_state hmac;
|
||||
unsigned char tempbuf[MAX_MAC_LEN];
|
||||
unsigned long bufsize;
|
||||
unsigned int len;
|
||||
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
if (macsize == 0) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->recv_algo_mac->hashdesc->name),
|
||||
ses.keys->recvmackey,
|
||||
ses.keys->recv_algo_mac->keysize)
|
||||
!= CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
unsigned int mac_size, contents_len;
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.recvseq, tempbuf);
|
||||
if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
contents_len = ses.readbuf->len - mac_size;
|
||||
|
||||
buf_setpos(sourcebuf, 0);
|
||||
len = sourcebuf->len;
|
||||
if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
bufsize = sizeof(tempbuf);
|
||||
if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
|
||||
buf_setpos(ses.readbuf, contents_len);
|
||||
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
@ -354,7 +321,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
buffer * ret;
|
||||
z_streamp zstream;
|
||||
|
||||
zstream = ses.keys->recv_zstream;
|
||||
zstream = ses.keys->recv.zstream;
|
||||
ret = buf_new(len);
|
||||
|
||||
zstream->avail_in = len;
|
||||
@ -450,11 +417,12 @@ void maybe_flush_reply_queue() {
|
||||
void encrypt_packet() {
|
||||
|
||||
unsigned char padlen;
|
||||
unsigned char blocksize, macsize;
|
||||
buffer * writebuf; /* the packet which will go on the wire */
|
||||
buffer * clearwritebuf; /* unencrypted, possibly compressed */
|
||||
unsigned char blocksize, mac_size;
|
||||
buffer * writebuf; /* the packet which will go on the wire. This is
|
||||
encrypted in-place. */
|
||||
unsigned char type;
|
||||
unsigned int clear_len;
|
||||
unsigned int len, encrypt_buf_size;
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
|
||||
type = ses.writepayload->data[0];
|
||||
TRACE(("enter encrypt_packet()"))
|
||||
@ -468,34 +436,36 @@ void encrypt_packet() {
|
||||
return;
|
||||
}
|
||||
|
||||
blocksize = ses.keys->trans_algo_crypt->blocksize;
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
blocksize = ses.keys->trans.algo_crypt->blocksize;
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
|
||||
/* Encrypted packet len is payload+5, then worst case is if we are 3 away
|
||||
* from a blocksize multiple. In which case we need to pad to the
|
||||
* multiple, then add another blocksize (or MIN_PACKET_LEN) */
|
||||
clear_len = (ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3;
|
||||
encrypt_buf_size = (ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3;
|
||||
/* add space for the MAC at the end */
|
||||
encrypt_buf_size += mac_size;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
clear_len += ZLIB_COMPRESS_INCR; /* bit of a kludge, but we can't know len*/
|
||||
encrypt_buf_size += ZLIB_COMPRESS_INCR; /* bit of a kludge, but we can't know len*/
|
||||
#endif
|
||||
clearwritebuf = buf_new(clear_len);
|
||||
buf_setlen(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
writebuf = buf_new(encrypt_buf_size);
|
||||
buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compression */
|
||||
if (is_compress_trans()) {
|
||||
buf_compress(clearwritebuf, ses.writepayload, ses.writepayload->len);
|
||||
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
memcpy(buf_getwriteptr(clearwritebuf, ses.writepayload->len),
|
||||
memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
|
||||
buf_getptr(ses.writepayload, ses.writepayload->len),
|
||||
ses.writepayload->len);
|
||||
buf_incrwritepos(clearwritebuf, ses.writepayload->len);
|
||||
buf_incrwritepos(writebuf, ses.writepayload->len);
|
||||
}
|
||||
|
||||
/* finished with payload */
|
||||
@ -504,53 +474,45 @@ void encrypt_packet() {
|
||||
|
||||
/* length of padding - packet length must be a multiple of blocksize,
|
||||
* with a minimum of 4 bytes of padding */
|
||||
padlen = blocksize - (clearwritebuf->len) % blocksize;
|
||||
padlen = blocksize - (writebuf->len) % blocksize;
|
||||
if (padlen < 4) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
/* check for min packet length */
|
||||
if (clearwritebuf->len + padlen < MIN_PACKET_LEN) {
|
||||
if (writebuf->len + padlen < MIN_PACKET_LEN) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
buf_setpos(writebuf, 0);
|
||||
/* packet length excluding the packetlength uint32 */
|
||||
buf_putint(clearwritebuf, clearwritebuf->len + padlen - 4);
|
||||
buf_putint(writebuf, writebuf->len + padlen - 4);
|
||||
|
||||
/* padding len */
|
||||
buf_putbyte(clearwritebuf, padlen);
|
||||
buf_putbyte(writebuf, padlen);
|
||||
/* actual padding */
|
||||
buf_setpos(clearwritebuf, clearwritebuf->len);
|
||||
buf_incrlen(clearwritebuf, padlen);
|
||||
genrandom(buf_getptr(clearwritebuf, padlen), padlen);
|
||||
buf_setpos(writebuf, writebuf->len);
|
||||
buf_incrlen(writebuf, padlen);
|
||||
genrandom(buf_getptr(writebuf, padlen), padlen);
|
||||
|
||||
/* do the actual encryption */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
/* create a new writebuffer, this is freed when it has been put on the
|
||||
* wire by writepacket() */
|
||||
writebuf = buf_new(clearwritebuf->len + macsize);
|
||||
make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
|
||||
|
||||
/* encrypt it */
|
||||
while (clearwritebuf->pos < clearwritebuf->len) {
|
||||
if (ses.keys->trans_crypt_mode->encrypt(
|
||||
buf_getptr(clearwritebuf, blocksize),
|
||||
buf_getwriteptr(writebuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->trans_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error encrypting");
|
||||
}
|
||||
buf_incrpos(clearwritebuf, blocksize);
|
||||
buf_incrwritepos(writebuf, blocksize);
|
||||
/* do the actual encryption, in-place */
|
||||
buf_setpos(writebuf, 0);
|
||||
/* encrypt it in-place*/
|
||||
len = writebuf->len;
|
||||
if (ses.keys->trans.crypt_mode->encrypt(
|
||||
buf_getptr(writebuf, len),
|
||||
buf_getwriteptr(writebuf, len),
|
||||
len,
|
||||
&ses.keys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error encrypting");
|
||||
}
|
||||
buf_incrpos(writebuf, len);
|
||||
|
||||
/* now add a hmac and we're done */
|
||||
writemac(writebuf, clearwritebuf);
|
||||
/* stick the MAC on it */
|
||||
buf_putbytes(writebuf, mac_bytes, mac_size);
|
||||
|
||||
/* clearwritebuf is finished with */
|
||||
buf_free(clearwritebuf);
|
||||
clearwritebuf = NULL;
|
||||
|
||||
/* enqueue the packet for sending */
|
||||
/* enqueue the packet for sending. It will get freed after transmission. */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, (void*)writebuf);
|
||||
|
||||
@ -563,47 +525,43 @@ void encrypt_packet() {
|
||||
|
||||
|
||||
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
|
||||
|
||||
unsigned int macsize;
|
||||
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
buffer * clear_buf, unsigned int clear_len,
|
||||
unsigned char *output_mac) {
|
||||
unsigned char seqbuf[4];
|
||||
unsigned char tempbuf[MAX_MAC_LEN];
|
||||
unsigned long bufsize;
|
||||
hmac_state hmac;
|
||||
|
||||
TRACE(("enter writemac"))
|
||||
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
if (macsize > 0) {
|
||||
if (key_state->algo_mac->hashsize > 0) {
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->trans_algo_mac->hashdesc->name),
|
||||
ses.keys->transmackey,
|
||||
ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
|
||||
key_state->hash_index,
|
||||
key_state->mackey,
|
||||
key_state->algo_mac->keysize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.transseq, seqbuf);
|
||||
STORE32H(seqno, seqbuf);
|
||||
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* the actual contents */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
buf_setpos(clear_buf, 0);
|
||||
if (hmac_process(&hmac,
|
||||
buf_getptr(clearwritebuf,
|
||||
clearwritebuf->len),
|
||||
clearwritebuf->len) != CRYPT_OK) {
|
||||
buf_getptr(clear_buf, clear_len),
|
||||
clear_len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
bufsize = sizeof(tempbuf);
|
||||
if (hmac_done(&hmac, tempbuf, &bufsize)
|
||||
!= CRYPT_OK) {
|
||||
bufsize = MAX_MAC_LEN;
|
||||
if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
buf_putbytes(outputbuffer, tempbuf, macsize);
|
||||
}
|
||||
TRACE(("leave writemac"))
|
||||
}
|
||||
@ -620,29 +578,29 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
while (1) {
|
||||
|
||||
ses.keys->trans_zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans_zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans_zstream->avail_in);
|
||||
ses.keys->trans.zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans.zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans.zstream->avail_in);
|
||||
|
||||
ses.keys->trans_zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans_zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out);
|
||||
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans.zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
|
||||
|
||||
result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH);
|
||||
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
|
||||
|
||||
buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out);
|
||||
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
if (ses.keys->trans_zstream->avail_in == 0) {
|
||||
if (ses.keys->trans.zstream->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dropbear_assert(ses.keys->trans_zstream->avail_out == 0);
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
|
||||
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
|
2
packet.h
2
packet.h
@ -44,6 +44,6 @@ typedef struct PacketType {
|
||||
#define PACKET_PADDING_OFF 4
|
||||
#define PACKET_PAYLOAD_OFF 5
|
||||
|
||||
#define INIT_READBUF 200
|
||||
#define INIT_READBUF 128
|
||||
|
||||
#endif /* _PACKET_H_ */
|
||||
|
6
random.c
6
random.c
@ -69,12 +69,8 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
memset((void*)&egdsock, 0x0, sizeof(egdsock));
|
||||
egdsock.sun_family = AF_UNIX;
|
||||
strlcpy(egdsock.sun_path, DROPBEAR_PRNGD_SOCKET,
|
||||
sizeof(egdsock.sun_path));
|
||||
readfd = connect_unix(DROPBEAR_PRNGD_SOCKET);
|
||||
|
||||
readfd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (readfd < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
}
|
||||
|
26
runopts.h
26
runopts.h
@ -37,8 +37,16 @@ typedef struct runopts {
|
||||
int listen_fwd_all;
|
||||
#endif
|
||||
unsigned int recv_window;
|
||||
unsigned int keepalive_secs;
|
||||
unsigned int idle_timeout_secs;
|
||||
time_t keepalive_secs;
|
||||
time_t idle_timeout_secs;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* TODO: add a commandline flag. Currently this is on by default if compression
|
||||
* is compiled in, but disabled for a client's non-final multihop stages. (The
|
||||
* intermediate stages are compressed streams, so are uncompressible. */
|
||||
int enable_compress;
|
||||
#endif
|
||||
|
||||
|
||||
} runopts;
|
||||
|
||||
@ -112,13 +120,20 @@ typedef struct cli_runopts {
|
||||
int backgrounded;
|
||||
int is_subsystem;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
struct SignKeyList *privkeys; /* Keys to use for public-key auth */
|
||||
m_list *privkeys; /* Keys to use for public-key auth */
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
struct TCPFwdList * remotefwds;
|
||||
m_list * remotefwds;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
struct TCPFwdList * localfwds;
|
||||
m_list * localfwds;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
int agent_fwd;
|
||||
int agent_keys_loaded; /* whether pubkeys has been populated with a
|
||||
list of keys held by the agent */
|
||||
int agent_fd; /* The agent fd is only set during authentication. Forwarded
|
||||
agent sessions have their own file descriptors */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
@ -128,7 +143,6 @@ typedef struct cli_runopts {
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
char *proxycmd;
|
||||
#endif
|
||||
|
||||
} cli_runopts;
|
||||
|
||||
extern cli_runopts cli_opts;
|
||||
|
6
scp.c
6
scp.c
@ -343,7 +343,7 @@ main(int argc, char **argv)
|
||||
addargs(&args, "-p%s", optarg);
|
||||
break;
|
||||
case 'B':
|
||||
addargs(&args, "-oBatchmode yes");
|
||||
fprintf(stderr, "Note: -B option is disabled in this version of scp");
|
||||
break;
|
||||
case 'l':
|
||||
speed = strtod(optarg, &endp);
|
||||
@ -492,9 +492,13 @@ toremote(char *targ, int argc, char **argv)
|
||||
addargs(&alist, "%s", ssh_program);
|
||||
if (verbose_mode)
|
||||
addargs(&alist, "-v");
|
||||
#if 0
|
||||
// Disabled since dbclient won't understand them
|
||||
// and scp works fine without them.
|
||||
addargs(&alist, "-x");
|
||||
addargs(&alist, "-oClearAllForwardings yes");
|
||||
addargs(&alist, "-n");
|
||||
#endif
|
||||
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
|
71
session.h
71
session.h
@ -41,7 +41,7 @@
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out, char* remotehost);
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void common_session_cleanup();
|
||||
void session_identification();
|
||||
@ -51,51 +51,45 @@ const char* get_user_shell();
|
||||
void fill_passwd(const char* username);
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, int childpipe, char *remotehost, char *addrstring);
|
||||
void svr_session(int sock, int childpipe);
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out, char *remotehost);
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cli_session_cleanup();
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
|
||||
struct key_context {
|
||||
|
||||
const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher_mode *recv_crypt_mode;
|
||||
const struct dropbear_cipher_mode *trans_crypt_mode;
|
||||
const struct dropbear_hash *recv_algo_mac; /* NULL for none */
|
||||
const struct dropbear_hash *trans_algo_mac; /* NULL for none */
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
|
||||
char recv_algo_comp; /* compression */
|
||||
char trans_algo_comp;
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
struct key_context_directional {
|
||||
const struct dropbear_cipher *algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher_mode *crypt_mode;
|
||||
const struct dropbear_hash *algo_mac; /* NULL for none */
|
||||
int hash_index; /* lookup for libtomcrypt */
|
||||
char algo_comp; /* compression */
|
||||
#ifndef DISABLE_ZLIB
|
||||
z_streamp recv_zstream;
|
||||
z_streamp trans_zstream;
|
||||
z_streamp zstream;
|
||||
#endif
|
||||
|
||||
/* actual keys */
|
||||
union {
|
||||
symmetric_CBC cbc;
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
symmetric_CTR ctr;
|
||||
#endif
|
||||
} recv_cipher_state;
|
||||
union {
|
||||
symmetric_CBC cbc;
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
symmetric_CTR ctr;
|
||||
#endif
|
||||
} trans_cipher_state;
|
||||
unsigned char recvmackey[MAX_MAC_KEY];
|
||||
unsigned char transmackey[MAX_MAC_KEY];
|
||||
} cipher_state;
|
||||
unsigned char mackey[MAX_MAC_KEY];
|
||||
};
|
||||
|
||||
struct key_context {
|
||||
|
||||
struct key_context_directional recv;
|
||||
struct key_context_directional trans;
|
||||
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
};
|
||||
|
||||
struct packetlist;
|
||||
@ -116,8 +110,6 @@ struct sshsession {
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
|
||||
unsigned char *remotehost; /* the peer hostname */
|
||||
|
||||
unsigned char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
@ -128,8 +120,7 @@ struct sshsession {
|
||||
throughout the code, as handlers fill out this
|
||||
buffer with the packet to send. */
|
||||
struct Queue writequeue; /* A queue of encrypted packets to send */
|
||||
buffer *readbuf; /* Encrypted */
|
||||
buffer *decryptreadbuf; /* Post-decryption */
|
||||
buffer *readbuf; /* From the wire, decrypted in-place */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet */
|
||||
unsigned int transseq, recvseq; /* Sequence IDs */
|
||||
|
||||
@ -169,6 +160,9 @@ struct sshsession {
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
|
||||
/* Enables/disables compression */
|
||||
algo_type *compress_algos;
|
||||
|
||||
/* a list of queued replies that should be sent after a KEX has
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
@ -220,6 +214,13 @@ struct serversession {
|
||||
/* The numeric address they connected from, used for logging */
|
||||
char * addrstring;
|
||||
|
||||
/* The resolved remote address, used for lastlog etc */
|
||||
char *remotehost;
|
||||
|
||||
#ifdef __uClinux__
|
||||
pid_t server_pid;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -268,7 +269,7 @@ struct clientsession {
|
||||
info request from the server for
|
||||
interactive auth.*/
|
||||
#endif
|
||||
struct SignKeyList *lastprivkey;
|
||||
sign_key *lastprivkey;
|
||||
|
||||
int retval; /* What the command exit status was - we emulate it */
|
||||
#if 0
|
||||
|
13
signkey.c
13
signkey.c
@ -40,8 +40,10 @@ sign_key * new_sign_key() {
|
||||
#ifdef DROPBEAR_RSA
|
||||
ret->rsakey = NULL;
|
||||
#endif
|
||||
ret->filename = NULL;
|
||||
ret->type = DROPBEAR_SIGNKEY_NONE;
|
||||
ret->source = SIGNKEY_SOURCE_INVALID;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
|
||||
@ -81,6 +83,8 @@ int signkey_type_from_name(const char* name, int namelen) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("signkey_type_from_name unexpected key type."))
|
||||
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
@ -101,8 +105,11 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
m_free(ident);
|
||||
|
||||
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
|
||||
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, type))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("buf_get_pub_key keytype is %d"))
|
||||
|
||||
*type = keytype;
|
||||
|
||||
@ -255,6 +262,8 @@ void sign_key_free(sign_key *key) {
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
|
||||
m_free(key->filename);
|
||||
|
||||
m_free(key);
|
||||
TRACE(("leave sign_key_free"))
|
||||
}
|
||||
@ -358,7 +367,6 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
|
||||
buffer *sigblob;
|
||||
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
@ -374,7 +382,6 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
if (sigblob->len == 0) {
|
||||
dropbear_exit("non-matching signing type");
|
||||
}
|
||||
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
14
signkey.h
14
signkey.h
@ -29,8 +29,22 @@
|
||||
#include "dss.h"
|
||||
#include "rsa.h"
|
||||
|
||||
|
||||
/* Sources for signing keys */
|
||||
typedef enum {
|
||||
SIGNKEY_SOURCE_RAW_FILE,
|
||||
SIGNKEY_SOURCE_AGENT,
|
||||
SIGNKEY_SOURCE_INVALID,
|
||||
} signkey_source;
|
||||
|
||||
struct SIGN_key {
|
||||
|
||||
int type; /* The type of key (dss or rsa) */
|
||||
signkey_source source;
|
||||
char *filename;
|
||||
/* the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key * dsskey;
|
||||
#endif
|
||||
|
11
ssh.h
11
ssh.h
@ -105,3 +105,14 @@
|
||||
#define SSH_SIGNKEY_DSS_LEN 7
|
||||
#define SSH_SIGNKEY_RSA "ssh-rsa"
|
||||
#define SSH_SIGNKEY_RSA_LEN 7
|
||||
|
||||
/* Agent commands. These aren't part of the spec, and are defined
|
||||
* only on the openssh implementation. */
|
||||
#define SSH_AGENT_FAILURE 5
|
||||
#define SSH_AGENT_SUCCESS 6
|
||||
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||
#define SSH2_AGENT_SIGN_RESPONSE 14
|
||||
|
||||
#define SSH2_AGENT_FAILURE 30
|
||||
|
@ -49,10 +49,12 @@ static void agentaccept(struct Listener * listener, int sock);
|
||||
|
||||
/* Handles client requests to start agent forwarding, sets up listening socket.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int agentreq(struct ChanSess * chansess) {
|
||||
int svr_agentreq(struct ChanSess * chansess) {
|
||||
|
||||
int fd;
|
||||
|
||||
TRACE(("enter svr_agentreq"))
|
||||
|
||||
if (!svr_pubkey_allows_agentfwd()) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
@ -89,10 +91,12 @@ int agentreq(struct ChanSess * chansess) {
|
||||
}
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
TRACE(("success"))
|
||||
|
||||
fail:
|
||||
TRACE(("fail"))
|
||||
/* cleanup */
|
||||
agentcleanup(chansess);
|
||||
svr_agentcleanup(chansess);
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
@ -118,7 +122,7 @@ static void agentaccept(struct Listener *UNUSED(listener), int sock) {
|
||||
|
||||
/* set up the environment variable pointing to the socket. This is called
|
||||
* just before command/shell execution, after dropping priveleges */
|
||||
void agentset(struct ChanSess * chansess) {
|
||||
void svr_agentset(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
int len;
|
||||
@ -137,7 +141,7 @@ void agentset(struct ChanSess * chansess) {
|
||||
}
|
||||
|
||||
/* close the socket, remove the socket-file */
|
||||
void agentcleanup(struct ChanSess * chansess) {
|
||||
void svr_agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
uid_t uid;
|
||||
@ -181,7 +185,7 @@ void agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
}
|
||||
|
||||
static const struct ChanType chan_agent = {
|
||||
static const struct ChanType chan_svr_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
NULL,
|
||||
@ -194,7 +198,7 @@ static const struct ChanType chan_agent = {
|
||||
/* helper for accepting an agent request */
|
||||
static int send_msg_channel_open_agent(int fd) {
|
||||
|
||||
if (send_msg_channel_open_init(fd, &chan_agent) == DROPBEAR_SUCCESS) {
|
||||
if (send_msg_channel_open_init(fd, &chan_svr_agent) == DROPBEAR_SUCCESS) {
|
||||
encrypt_packet();
|
||||
return DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "packet.h"
|
||||
#include "auth.h"
|
||||
#include "runopts.h"
|
||||
#include "random.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
@ -337,7 +338,12 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
encrypt_packet();
|
||||
|
||||
if (incrfail) {
|
||||
usleep(300000); /* XXX improve this */
|
||||
unsigned int delay;
|
||||
genrandom((unsigned char*)&delay, sizeof(delay));
|
||||
/* We delay for 300ms +- 50ms, 0.1ms granularity */
|
||||
delay = 250000 + (delay % 1000)*100;
|
||||
usleep(delay);
|
||||
dropbear_log(LOG_INFO, "delay is %d", delay);
|
||||
ses.authstate.failcount++;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ pamConvFunc(int num_msg,
|
||||
/* We don't recognise the prompt as asking for a password,
|
||||
so can't handle it. Add more above as required for
|
||||
different pam modules/implementations */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (no echo)",
|
||||
compare_message);
|
||||
rc = PAM_CONV_ERR;
|
||||
break;
|
||||
@ -123,12 +123,15 @@ pamConvFunc(int num_msg,
|
||||
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
|
||||
if (!((strcmp(compare_message, "login:" ) == 0)
|
||||
|| (strcmp(compare_message, "please enter username:") == 0))) {
|
||||
if (!(
|
||||
(strcmp(compare_message, "login:" ) == 0)
|
||||
|| (strcmp(compare_message, "please enter username:") == 0)
|
||||
|| (strcmp(compare_message, "username:") == 0)
|
||||
)) {
|
||||
/* We don't recognise the prompt as asking for a username,
|
||||
so can't handle it. Add more above as required for
|
||||
different pam modules/implementations */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (with echo)",
|
||||
compare_message);
|
||||
rc = PAM_CONV_ERR;
|
||||
break;
|
||||
@ -212,7 +215,10 @@ void svr_auth_pam() {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAM_FAIL_DELAY
|
||||
/* We have our own random delay code already, disable PAM's */
|
||||
(void) pam_fail_delay(pamHandlep, 0 /* musec_delay */);
|
||||
#endif
|
||||
|
||||
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
|
||||
|
||||
|
@ -88,10 +88,20 @@ int svr_pubkey_allows_pty() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set chansession command to the one forced by 'command' public key option */
|
||||
/* Set chansession command to the one forced
|
||||
* by any 'command' public key option. */
|
||||
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
|
||||
if (ses.authstate.pubkey_options)
|
||||
if (ses.authstate.pubkey_options) {
|
||||
ses.authstate.pubkey_options->original_command = chansess->cmd;
|
||||
if (!chansess->cmd)
|
||||
{
|
||||
ses.authstate.pubkey_options->original_command = m_strdup("");
|
||||
}
|
||||
chansess->cmd = ses.authstate.pubkey_options->forced_command;
|
||||
#ifdef LOG_COMMANDS
|
||||
dropbear_log(LOG_INFO, "command forced to '%s'", ses.authstate.pubkey_options->original_command);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Free potential public key options */
|
||||
@ -124,7 +134,6 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
|
||||
TRACE(("enter addpubkeyoptions"))
|
||||
|
||||
ses.authstate.pubkey_options = (struct PubKeyOptions*)m_malloc(sizeof( struct PubKeyOptions ));
|
||||
memset(ses.authstate.pubkey_options, '\0', sizeof(*ses.authstate.pubkey_options));
|
||||
|
||||
buf_setpos(options_buf, 0);
|
||||
while (options_buf->pos < options_buf->len) {
|
||||
|
@ -222,6 +222,7 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
|
||||
chansess->cmd = NULL;
|
||||
chansess->connection_string = NULL;
|
||||
chansess->pid = 0;
|
||||
|
||||
/* pty details */
|
||||
@ -250,6 +251,14 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
}
|
||||
|
||||
static struct logininfo*
|
||||
chansess_login_alloc(struct ChanSess *chansess) {
|
||||
struct logininfo * li;
|
||||
li = login_alloc_entry(chansess->pid, ses.authstate.username,
|
||||
svr_ses.remotehost, chansess->tty);
|
||||
return li;
|
||||
}
|
||||
|
||||
/* clean a session channel */
|
||||
static void closechansess(struct Channel *channel) {
|
||||
|
||||
@ -273,8 +282,7 @@ static void closechansess(struct Channel *channel) {
|
||||
|
||||
if (chansess->tty) {
|
||||
/* write the utmp/wtmp login record */
|
||||
li = login_alloc_entry(chansess->pid, ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
li = chansess_login_alloc(chansess);
|
||||
login_logout(li);
|
||||
login_free_entry(li);
|
||||
|
||||
@ -287,7 +295,7 @@ static void closechansess(struct Channel *channel) {
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
agentcleanup(chansess);
|
||||
svr_agentcleanup(chansess);
|
||||
#endif
|
||||
|
||||
/* clear child pid entries */
|
||||
@ -346,7 +354,7 @@ static void chansessionrequest(struct Channel *channel) {
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
} else if (strcmp(type, "auth-agent-req@openssh.com") == 0) {
|
||||
ret = agentreq(chansess);
|
||||
ret = svr_agentreq(chansess);
|
||||
#endif
|
||||
} else if (strcmp(type, "signal") == 0) {
|
||||
ret = sessionsignal(chansess);
|
||||
@ -570,6 +578,21 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
static char* make_connection_string() {
|
||||
char *local_ip, *local_port, *remote_ip, *remote_port;
|
||||
size_t len;
|
||||
char *ret;
|
||||
get_socket_address(ses.sock_in, &local_ip, &local_port, &remote_ip, &remote_port, 0);
|
||||
len = strlen(local_ip) + strlen(local_port) + strlen(remote_ip) + strlen(remote_port) + 4;
|
||||
ret = m_malloc(len);
|
||||
snprintf(ret, len, "%s %s %s %s", remote_ip, remote_port, local_ip, local_port);
|
||||
m_free(local_ip);
|
||||
m_free(local_port);
|
||||
m_free(remote_ip);
|
||||
m_free(remote_port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Handle a command request from the client. This is used for both shell
|
||||
* and command-execution requests, and passes the command to
|
||||
* noptycommand or ptycommand as appropriate.
|
||||
@ -589,9 +612,6 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* take public key option 'command' into account */
|
||||
svr_pubkey_set_forced_command(chansess);
|
||||
|
||||
if (iscmd) {
|
||||
/* "exec" */
|
||||
if (chansess->cmd == NULL) {
|
||||
@ -616,6 +636,9 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* take public key option 'command' into account */
|
||||
svr_pubkey_set_forced_command(chansess);
|
||||
|
||||
#ifdef LOG_COMMANDS
|
||||
if (chansess->cmd) {
|
||||
@ -627,6 +650,12 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* uClinux will vfork(), so there'll be a race as
|
||||
connection_string is freed below. */
|
||||
#ifndef __uClinux__
|
||||
chansess->connection_string = make_connection_string();
|
||||
#endif
|
||||
|
||||
if (chansess->term == NULL) {
|
||||
/* no pty */
|
||||
ret = noptycommand(channel, chansess);
|
||||
@ -635,6 +664,10 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
ret = ptycommand(channel, chansess);
|
||||
}
|
||||
|
||||
#ifndef __uClinux__
|
||||
m_free(chansess->connection_string);
|
||||
#endif
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(chansess->cmd);
|
||||
}
|
||||
@ -736,13 +769,10 @@ 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(), ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
li = chansess_login_alloc(chansess);
|
||||
login_login(li);
|
||||
login_free_entry(li);
|
||||
|
||||
m_free(chansess->tty);
|
||||
|
||||
#ifdef DO_MOTD
|
||||
if (svr_opts.domotd) {
|
||||
/* don't show the motd if ~/.hushlogin exists */
|
||||
@ -883,6 +913,22 @@ static void execchild(void *user_data) {
|
||||
addnewvar("TERM", chansess->term);
|
||||
}
|
||||
|
||||
if (chansess->tty) {
|
||||
addnewvar("SSH_TTY", chansess->tty);
|
||||
}
|
||||
|
||||
if (chansess->connection_string) {
|
||||
addnewvar("SSH_CONNECTION", chansess->connection_string);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
if (ses.authstate.pubkey_options &&
|
||||
ses.authstate.pubkey_options->original_command) {
|
||||
addnewvar("SSH_ORIGINAL_COMMAND",
|
||||
ses.authstate.pubkey_options->original_command);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* change directory */
|
||||
if (chdir(ses.authstate.pw_dir) < 0) {
|
||||
dropbear_exit("error changing directory");
|
||||
@ -894,7 +940,7 @@ static void execchild(void *user_data) {
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
/* set up agent env variable */
|
||||
agentset(chansess);
|
||||
svr_agentset(chansess);
|
||||
#endif
|
||||
|
||||
usershell = m_strdup(get_user_shell());
|
||||
|
51
svr-main.c
51
svr-main.c
@ -77,22 +77,16 @@ int main(int argc, char ** argv)
|
||||
|
||||
#ifdef INETD_MODE
|
||||
static void main_inetd() {
|
||||
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen;
|
||||
char * addrstring = NULL;
|
||||
char *host, *port = NULL;
|
||||
|
||||
/* Set up handlers, syslog, seed random */
|
||||
commonsetup();
|
||||
|
||||
remoteaddrlen = sizeof(remoteaddr);
|
||||
if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
|
||||
dropbear_exit("Unable to getpeername: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* In case our inetd was lax in logging source addresses */
|
||||
addrstring = getaddrstring(&remoteaddr, 1);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
|
||||
get_socket_address(0, NULL, NULL, &host, &port, 0);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
|
||||
m_free(host);
|
||||
m_free(port);
|
||||
|
||||
/* Don't check the return value - it may just fail since inetd has
|
||||
* already done setsid() after forking (xinetd on Darwin appears to do
|
||||
@ -102,7 +96,7 @@ static void main_inetd() {
|
||||
/* Start service program
|
||||
* -1 is a dummy childpipe, just something we can close() without
|
||||
* mattering. */
|
||||
svr_session(0, -1, getaddrhostname(&remoteaddr), addrstring);
|
||||
svr_session(0, -1);
|
||||
|
||||
/* notreached */
|
||||
}
|
||||
@ -133,7 +127,7 @@ void main_noinetd() {
|
||||
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
|
||||
childpipes[i] = -1;
|
||||
}
|
||||
bzero(preauth_addrs, sizeof(preauth_addrs));
|
||||
memset(preauth_addrs, 0x0, sizeof(preauth_addrs));
|
||||
|
||||
/* Set up the listening sockets */
|
||||
listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
|
||||
@ -218,14 +212,13 @@ void main_noinetd() {
|
||||
|
||||
/* handle each socket which has something to say */
|
||||
for (i = 0; i < listensockcount; i++) {
|
||||
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen = 0;
|
||||
size_t num_unauthed_for_addr = 0;
|
||||
size_t num_unauthed_total = 0;
|
||||
char * remote_addr_str = NULL;
|
||||
char *remote_host = NULL, *remote_port = NULL;
|
||||
pid_t fork_ret = 0;
|
||||
size_t conn_idx = 0;
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen;
|
||||
|
||||
if (!FD_ISSET(listensocks[i], &fds))
|
||||
continue;
|
||||
@ -240,14 +233,14 @@ void main_noinetd() {
|
||||
}
|
||||
|
||||
/* Limit the number of unauthenticated connections per IP */
|
||||
remote_addr_str = getaddrstring(&remoteaddr, 0);
|
||||
getaddrstring(&remoteaddr, &remote_host, NULL, 0);
|
||||
|
||||
num_unauthed_for_addr = 0;
|
||||
num_unauthed_total = 0;
|
||||
for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
|
||||
if (childpipes[j] >= 0) {
|
||||
num_unauthed_total++;
|
||||
if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) {
|
||||
if (strcmp(remote_host, preauth_addrs[j]) == 0) {
|
||||
num_unauthed_for_addr++;
|
||||
}
|
||||
} else {
|
||||
@ -280,21 +273,21 @@ void main_noinetd() {
|
||||
/* parent */
|
||||
childpipes[conn_idx] = childpipe[0];
|
||||
m_close(childpipe[1]);
|
||||
preauth_addrs[conn_idx] = remote_addr_str;
|
||||
remote_addr_str = NULL;
|
||||
preauth_addrs[conn_idx] = remote_host;
|
||||
remote_host = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
/* child */
|
||||
char * addrstring = NULL;
|
||||
#ifdef DEBUG_FORKGPROF
|
||||
extern void _start(void), etext(void);
|
||||
monstartup((u_long)&_start, (u_long)&etext);
|
||||
#endif /* DEBUG_FORKGPROF */
|
||||
|
||||
m_free(remote_addr_str);
|
||||
addrstring = getaddrstring(&remoteaddr, 1);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
|
||||
getaddrstring(&remoteaddr, NULL, &remote_port, 0);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s:%s", remote_host, remote_port);
|
||||
m_free(remote_host);
|
||||
m_free(remote_port);
|
||||
|
||||
#ifndef DEBUG_NOFORK
|
||||
if (setsid() < 0) {
|
||||
@ -310,9 +303,7 @@ void main_noinetd() {
|
||||
m_close(childpipe[0]);
|
||||
|
||||
/* start the session */
|
||||
svr_session(childsock, childpipe[1],
|
||||
getaddrhostname(&remoteaddr),
|
||||
addrstring);
|
||||
svr_session(childsock, childpipe[1]);
|
||||
/* don't return */
|
||||
dropbear_assert(0);
|
||||
}
|
||||
@ -320,8 +311,8 @@ void main_noinetd() {
|
||||
out:
|
||||
/* This section is important for the parent too */
|
||||
m_close(childsock);
|
||||
if (remote_addr_str) {
|
||||
m_free(remote_addr_str);
|
||||
if (remote_host) {
|
||||
m_free(remote_host);
|
||||
}
|
||||
}
|
||||
} /* for(;;) loop */
|
||||
|
@ -124,6 +124,9 @@ void svr_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
svr_opts.noremotetcp = 0;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
#endif
|
||||
/* not yet
|
||||
opts.ipv4 = 1;
|
||||
@ -296,15 +299,19 @@ void svr_getopts(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
if (keepalive_arg) {
|
||||
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
|
||||
}
|
||||
opts.keepalive_secs = val;
|
||||
}
|
||||
|
||||
if (idle_timeout_arg) {
|
||||
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
|
||||
}
|
||||
opts.idle_timeout_secs = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,23 +74,36 @@ static const struct ChanType *svr_chantypes[] = {
|
||||
NULL /* Null termination is mandatory. */
|
||||
};
|
||||
|
||||
void svr_session(int sock, int childpipe,
|
||||
char* remotehost, char *addrstring) {
|
||||
|
||||
void svr_session(int sock, int childpipe) {
|
||||
char *host, *port;
|
||||
size_t len;
|
||||
reseedrandom();
|
||||
|
||||
crypto_init();
|
||||
common_session_init(sock, sock, remotehost);
|
||||
common_session_init(sock, sock);
|
||||
|
||||
/* Initialise server specific parts of the session */
|
||||
svr_ses.childpipe = childpipe;
|
||||
svr_ses.addrstring = addrstring;
|
||||
#ifdef __uClinux__
|
||||
svr_ses.server_pid = getpid();
|
||||
#endif
|
||||
svr_authinitialise();
|
||||
chaninitialise(svr_chantypes);
|
||||
svr_chansessinitialise();
|
||||
|
||||
ses.connect_time = time(NULL);
|
||||
|
||||
/* for logging the remote address */
|
||||
get_socket_address(ses.sock_in, NULL, NULL, &host, &port, 0);
|
||||
len = strlen(host) + strlen(port) + 2;
|
||||
svr_ses.addrstring = m_malloc(len);
|
||||
snprintf(svr_ses.addrstring, len, "%s:%s", host, port);
|
||||
m_free(host);
|
||||
m_free(port);
|
||||
|
||||
get_socket_address(ses.sock_in, NULL, NULL,
|
||||
&svr_ses.remotehost, NULL, 1);
|
||||
|
||||
/* set up messages etc */
|
||||
ses.remoteclosed = svr_remoteclosed;
|
||||
|
||||
@ -144,11 +157,20 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
#ifdef __uClinux__
|
||||
/* only the main server process should cleanup - we don't want
|
||||
* forked children doing that */
|
||||
if (svr_ses.server_pid == getpid())
|
||||
#else
|
||||
if (1)
|
||||
#endif
|
||||
{
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
|
||||
/* must be after we've done with username etc */
|
||||
common_session_cleanup();
|
||||
/* must be after we've done with username etc */
|
||||
common_session_cleanup();
|
||||
}
|
||||
|
||||
exit(exitcode);
|
||||
|
||||
|
15
sysoptions.h
15
sysoptions.h
@ -146,10 +146,6 @@
|
||||
#define DISABLE_X11FWD
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_AGENTFWD
|
||||
#define DISABLE_AGENTFWD
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
|
||||
#define ENABLE_CLI_ANYTCPFWD
|
||||
#endif
|
||||
@ -160,7 +156,7 @@
|
||||
|
||||
#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) || \
|
||||
defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_SVR_LOCALTCPFWD) || \
|
||||
defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD)
|
||||
defined(ENABLE_SVR_AGENTFWD) || defined(ENABLE_X11FWD)
|
||||
#define USING_LISTENERS
|
||||
#endif
|
||||
|
||||
@ -168,6 +164,10 @@
|
||||
#define ENABLE_CLI_MULTIHOP
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_AGENTFWD) || defined(DROPBEAR_PRNGD_SOCKET)
|
||||
#define ENABLE_CONNECT_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
|
||||
#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
|
||||
#endif
|
||||
@ -202,5 +202,8 @@
|
||||
#define IS_DROPBEAR_CLIENT 1
|
||||
|
||||
#else
|
||||
#error You must compiled with either DROPBEAR_CLIENT or DROPBEAR_SERVER selected
|
||||
/* Just building key utils? */
|
||||
#define IS_DROPBEAR_SERVER 0
|
||||
#define IS_DROPBEAR_CLIENT 0
|
||||
|
||||
#endif
|
||||
|
9
tcpfwd.h
9
tcpfwd.h
@ -25,6 +25,7 @@
|
||||
#define _TCPFWD_H
|
||||
|
||||
#include "channel.h"
|
||||
#include "list.h"
|
||||
|
||||
struct TCPListener {
|
||||
|
||||
@ -43,17 +44,14 @@ struct TCPListener {
|
||||
enum {direct, forwarded} tcp_type;
|
||||
};
|
||||
|
||||
/* A link in a list of forwards */
|
||||
struct TCPFwdList {
|
||||
|
||||
/* A forwarding entry */
|
||||
struct TCPFwdEntry {
|
||||
const unsigned char* connectaddr;
|
||||
unsigned int connectport;
|
||||
const unsigned char* listenaddr;
|
||||
unsigned int listenport;
|
||||
unsigned int have_reply; /* is set to 1 after a reply has been received
|
||||
when setting up the forwarding */
|
||||
struct TCPFwdList * next;
|
||||
|
||||
};
|
||||
|
||||
/* Server */
|
||||
@ -71,5 +69,4 @@ void cli_recv_msg_request_failure();
|
||||
/* Common */
|
||||
int listen_tcpfwd(struct TCPListener* tcpinfo);
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user