mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Uppity: add a --listen mode, protected by /proc/net/tcp.
Uppity is not secure enough to listen on a TCP port as if it was a normal SSH server. Until now, I've been using it by means of a local proxy command, i.e. PuTTY invokes Uppity in the same way it might invoke 'plink -nc'. This rigorously prevents any hostile user from connecting to my utterly insecure test server, but it's a thundering inconvenience as soon as you want to attach a debugger to the Uppity process itself - you have to stick a gdbserver somewhere in the middle of your already complicated shell pipeline, and then find a way to connect back to it from a gdb in a terminal window. So I've added an option to make Uppity listen on a TCP port in the normal way - but it's protected using that /proc/net/tcp trick I just added in the previous commit.
This commit is contained in:
parent
3b51644f2b
commit
443ad75a81
2
Recipe
2
Recipe
@ -397,7 +397,7 @@ testsc : [UT] testsc SSHCRYPTO marshal utils memory tree234 wildcard
|
|||||||
testzlib : [UT] testzlib sshzlib utils marshal memory
|
testzlib : [UT] testzlib sshzlib utils marshal memory
|
||||||
|
|
||||||
uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk
|
uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk
|
||||||
+ uxpty uxsftpserver ux_x11 uxagentsock
|
+ uxpty uxsftpserver ux_x11 uxagentsock procnet
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# On Windows, provide a means of removing local test binaries that we
|
# On Windows, provide a means of removing local test binaries that we
|
||||||
|
@ -41,6 +41,7 @@ struct server {
|
|||||||
int nhostkeys;
|
int nhostkeys;
|
||||||
RSAKey *hostkey1;
|
RSAKey *hostkey1;
|
||||||
AuthPolicy *authpolicy;
|
AuthPolicy *authpolicy;
|
||||||
|
LogPolicy *logpolicy;
|
||||||
const SftpServerVtable *sftpserver_vt;
|
const SftpServerVtable *sftpserver_vt;
|
||||||
|
|
||||||
Seat seat;
|
Seat seat;
|
||||||
@ -242,6 +243,7 @@ Plug *ssh_server_plug(
|
|||||||
srv->hostkeys = hostkeys;
|
srv->hostkeys = hostkeys;
|
||||||
srv->hostkey1 = hostkey1;
|
srv->hostkey1 = hostkey1;
|
||||||
srv->authpolicy = authpolicy;
|
srv->authpolicy = authpolicy;
|
||||||
|
srv->logpolicy = logpolicy;
|
||||||
srv->sftpserver_vt = sftpserver_vt;
|
srv->sftpserver_vt = sftpserver_vt;
|
||||||
|
|
||||||
srv->seat.vt = &server_seat_vt;
|
srv->seat.vt = &server_seat_vt;
|
||||||
@ -310,7 +312,7 @@ static void ssh_server_free_callback(void *vsrv)
|
|||||||
|
|
||||||
sfree(srv);
|
sfree(srv);
|
||||||
|
|
||||||
server_instance_terminated();
|
server_instance_terminated(srv->logpolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_connect_bpp(server *srv)
|
static void server_connect_bpp(server *srv)
|
||||||
|
@ -18,7 +18,7 @@ Plug *ssh_server_plug(
|
|||||||
const SftpServerVtable *sftpserver_vt);
|
const SftpServerVtable *sftpserver_vt);
|
||||||
void ssh_server_start(Plug *plug, Socket *socket);
|
void ssh_server_start(Plug *plug, Socket *socket);
|
||||||
|
|
||||||
void server_instance_terminated(void);
|
void server_instance_terminated(LogPolicy *logpolicy);
|
||||||
void platform_logevent(const char *msg);
|
void platform_logevent(const char *msg);
|
||||||
|
|
||||||
#define AUTHMETHODS(X) \
|
#define AUTHMETHODS(X) \
|
||||||
|
156
unix/uxserver.c
156
unix/uxserver.c
@ -112,19 +112,15 @@ char *platform_get_x_display(void) { return NULL; }
|
|||||||
|
|
||||||
static bool verbose;
|
static bool verbose;
|
||||||
|
|
||||||
static void log_to_stderr(const char *msg)
|
struct server_instance {
|
||||||
{
|
unsigned id;
|
||||||
/*
|
LogPolicy logpolicy;
|
||||||
* FIXME: in multi-connection proper-socket mode, prefix this with
|
};
|
||||||
* a connection id of some kind. We'll surely pass this in to
|
|
||||||
* sshserver.c by way of constructing a distinct LogPolicy per
|
|
||||||
* instance and making its containing structure contain the id -
|
|
||||||
* but we'll also have to arrange for those LogPolicy structs to
|
|
||||||
* be freed when the server instance terminates.
|
|
||||||
*
|
|
||||||
* For now, though, we only have one server instance, so no need.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
static void log_to_stderr(unsigned id, const char *msg)
|
||||||
|
{
|
||||||
|
if (id != (unsigned)-1)
|
||||||
|
fprintf(stderr, "#%u: ", id);
|
||||||
fputs(msg, stderr);
|
fputs(msg, stderr);
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
@ -132,13 +128,17 @@ static void log_to_stderr(const char *msg)
|
|||||||
|
|
||||||
static void server_eventlog(LogPolicy *lp, const char *event)
|
static void server_eventlog(LogPolicy *lp, const char *event)
|
||||||
{
|
{
|
||||||
|
struct server_instance *inst = container_of(
|
||||||
|
lp, struct server_instance, logpolicy);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
log_to_stderr(event);
|
log_to_stderr(inst->id, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_logging_error(LogPolicy *lp, const char *event)
|
static void server_logging_error(LogPolicy *lp, const char *event)
|
||||||
{
|
{
|
||||||
log_to_stderr(event); /* unconditional */
|
struct server_instance *inst = container_of(
|
||||||
|
lp, struct server_instance, logpolicy);
|
||||||
|
log_to_stderr(inst->id, event); /* unconditional */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int server_askappend(
|
static int server_askappend(
|
||||||
@ -153,7 +153,6 @@ static const LogPolicyVtable server_logpolicy_vt = {
|
|||||||
server_askappend,
|
server_askappend,
|
||||||
server_logging_error,
|
server_logging_error,
|
||||||
};
|
};
|
||||||
LogPolicy server_logpolicy[1] = {{ &server_logpolicy_vt }};
|
|
||||||
|
|
||||||
struct AuthPolicy_ssh1_pubkey {
|
struct AuthPolicy_ssh1_pubkey {
|
||||||
RSAKey key;
|
RSAKey key;
|
||||||
@ -324,11 +323,20 @@ static void show_version_and_exit(void)
|
|||||||
|
|
||||||
const bool buildinfo_gtk_relevant = false;
|
const bool buildinfo_gtk_relevant = false;
|
||||||
|
|
||||||
|
static bool listening = false;
|
||||||
static bool finished = false;
|
static bool finished = false;
|
||||||
void server_instance_terminated(void)
|
void server_instance_terminated(LogPolicy *lp)
|
||||||
{
|
{
|
||||||
/* FIXME: change policy here if we're running in a listening loop */
|
struct server_instance *inst = container_of(
|
||||||
finished = true;
|
lp, struct server_instance, logpolicy);
|
||||||
|
|
||||||
|
if (listening) {
|
||||||
|
log_to_stderr(inst->id, "connection terminated");
|
||||||
|
} else {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfree(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool longoptarg(const char *arg, const char *expected,
|
static bool longoptarg(const char *arg, const char *expected,
|
||||||
@ -368,6 +376,95 @@ static bool longoptnoarg(const char *arg, const char *expected)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct server_config {
|
||||||
|
Conf *conf;
|
||||||
|
const SshServerConfig *ssc;
|
||||||
|
|
||||||
|
ssh_key **hostkeys;
|
||||||
|
int nhostkeys;
|
||||||
|
|
||||||
|
RSAKey *hostkey1;
|
||||||
|
|
||||||
|
AuthPolicy *ap;
|
||||||
|
|
||||||
|
unsigned next_id;
|
||||||
|
|
||||||
|
Plug listening_plug;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Plug *server_conn_plug(
|
||||||
|
struct server_config *cfg, struct server_instance **inst_out)
|
||||||
|
{
|
||||||
|
struct server_instance *inst = snew(struct server_instance);
|
||||||
|
|
||||||
|
inst->id = cfg->next_id++;
|
||||||
|
inst->logpolicy.vt = &server_logpolicy_vt;
|
||||||
|
|
||||||
|
if (inst_out)
|
||||||
|
*inst_out = inst;
|
||||||
|
|
||||||
|
return ssh_server_plug(
|
||||||
|
cfg->conf, cfg->ssc, cfg->hostkeys, cfg->nhostkeys, cfg->hostkey1,
|
||||||
|
cfg->ap, &inst->logpolicy, &unix_live_sftpserver_vt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_log(Plug *plug, int type, SockAddr *addr, int port,
|
||||||
|
const char *error_msg, int error_code)
|
||||||
|
{
|
||||||
|
log_to_stderr((unsigned)-1, error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_closing(Plug *plug, const char *error_msg, int error_code,
|
||||||
|
bool calling_back)
|
||||||
|
{
|
||||||
|
log_to_stderr((unsigned)-1, error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int server_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||||
|
{
|
||||||
|
struct server_config *cfg = container_of(
|
||||||
|
p, struct server_config, listening_plug);
|
||||||
|
Socket *s;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
struct server_instance *inst;
|
||||||
|
|
||||||
|
unsigned old_next_id = cfg->next_id;
|
||||||
|
|
||||||
|
Plug *plug = server_conn_plug(cfg, &inst);
|
||||||
|
s = constructor(ctx, plug);
|
||||||
|
if ((err = sk_socket_error(s)) != NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
SocketPeerInfo *pi = sk_peer_info(s);
|
||||||
|
|
||||||
|
if (!sk_peer_trusted(s)) {
|
||||||
|
fprintf(stderr, "rejected connection from %s (untrustworthy peer)\n",
|
||||||
|
pi->log_text);
|
||||||
|
sk_free_peer_info(pi);
|
||||||
|
sk_close(s);
|
||||||
|
cfg->next_id = old_next_id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *msg = dupprintf("new connection from %s", pi->log_text);
|
||||||
|
log_to_stderr(inst->id, msg);
|
||||||
|
sfree(msg);
|
||||||
|
sk_free_peer_info(pi);
|
||||||
|
|
||||||
|
sk_set_frozen(s, false);
|
||||||
|
ssh_server_start(plug, s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PlugVtable server_plugvt = {
|
||||||
|
server_log,
|
||||||
|
server_closing,
|
||||||
|
NULL, /* recv */
|
||||||
|
NULL, /* send */
|
||||||
|
server_accepting
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int *fdlist;
|
int *fdlist;
|
||||||
@ -375,6 +472,7 @@ int main(int argc, char **argv)
|
|||||||
int i, fdstate;
|
int i, fdstate;
|
||||||
size_t fdsize;
|
size_t fdsize;
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
|
int listen_port = -1;
|
||||||
|
|
||||||
ssh_key **hostkeys = NULL;
|
ssh_key **hostkeys = NULL;
|
||||||
size_t nhostkeys = 0, hostkeysize = 0;
|
size_t nhostkeys = 0, hostkeysize = 0;
|
||||||
@ -414,6 +512,8 @@ int main(int argc, char **argv)
|
|||||||
show_version_and_exit();
|
show_version_and_exit();
|
||||||
} else if (longoptnoarg(arg, "--verbose") || !strcmp(arg, "-v")) {
|
} else if (longoptnoarg(arg, "--verbose") || !strcmp(arg, "-v")) {
|
||||||
verbose = true;
|
verbose = true;
|
||||||
|
} else if (longoptarg(arg, "--listen", &val, &argc, &argv)) {
|
||||||
|
listen_port = atoi(val);
|
||||||
} else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) {
|
} else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) {
|
||||||
Filename *keyfile;
|
Filename *keyfile;
|
||||||
int keytype;
|
int keytype;
|
||||||
@ -599,10 +699,22 @@ int main(int argc, char **argv)
|
|||||||
sk_init();
|
sk_init();
|
||||||
uxsel_init();
|
uxsel_init();
|
||||||
|
|
||||||
{
|
struct server_config scfg;
|
||||||
Plug *plug = ssh_server_plug(
|
scfg.conf = conf;
|
||||||
conf, &ssc, hostkeys, nhostkeys, hostkey1, &ap, server_logpolicy,
|
scfg.ssc = &ssc;
|
||||||
&unix_live_sftpserver_vt);
|
scfg.hostkeys = hostkeys;
|
||||||
|
scfg.nhostkeys = nhostkeys;
|
||||||
|
scfg.hostkey1 = hostkey1;
|
||||||
|
scfg.ap = ≈
|
||||||
|
scfg.next_id = 0;
|
||||||
|
|
||||||
|
if (listen_port >= 0) {
|
||||||
|
listening = true;
|
||||||
|
scfg.listening_plug.vt = &server_plugvt;
|
||||||
|
sk_newlistener(NULL, listen_port, &scfg.listening_plug,
|
||||||
|
true, ADDRTYPE_UNSPEC);
|
||||||
|
} else {
|
||||||
|
Plug *plug = server_conn_plug(&scfg, NULL);
|
||||||
ssh_server_start(plug, make_fd_socket(0, 1, -1, plug));
|
ssh_server_start(plug, make_fd_socket(0, 1, -1, plug));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user