1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Log identifying information for the other end of connections.

When anyone connects to a PuTTY tool's listening socket - whether it's
a user of a local->remote port forwarding, a connection-sharing
downstream or a client of Pageant - we'd like to log as much
information as we can find out about where the connection came from.

To that end, I've implemented a function sk_peer_info() in the socket
abstraction, which returns a freeform text string as best it can (or
NULL, if it can't get anything at all) describing the thing at the
other end of the connection. For TCP connections, this is done using
getpeername() to get an IP address and port in the obvious way; for
Unix-domain sockets, we attempt SO_PEERCRED (conditionalised on some
moderately hairy autoconfery) to get the pid and owner of the peer. I
haven't implemented anything for Windows named pipes, but I will if I
hear of anything useful.

(cherry picked from commit c8f83979a3)

Conflicts:
	pageant.c

Cherry-picker's notes: the conflict was because the original commit
also added a use of the same feature in the centralised Pageant code,
which doesn't exist on this branch. Also I had to remove 'const' from
the type of the second parameter to wrap_send_port_open(), since this
branch hasn't had the same extensive const-fixing as master.
This commit is contained in:
Simon Tatham 2015-05-18 13:57:45 +01:00
parent 3ba1a7cf4b
commit 41f63b6e5d
16 changed files with 219 additions and 17 deletions

4
Recipe
View File

@ -230,8 +230,8 @@ SFTP = sftp int64 logging
MISC = timing callback misc version settings tree234 proxy conf
WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy
+ wintime winhsock errsock
UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy time
OSXMISC = MISC uxstore uxsel osxsel uxnet uxmisc uxproxy time
UXMISC = MISC uxstore uxsel uxnet uxpeer cmdline uxmisc uxproxy time
OSXMISC = MISC uxstore uxsel osxsel uxnet uxpeer uxmisc uxproxy time
# Character set library, for use in pterm.
CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc

View File

@ -132,6 +132,28 @@ AC_CHECK_FUNCS([getaddrinfo posix_openpt ptsname setresuid strsignal updwtmpx])
AC_CHECK_DECLS([CLOCK_MONOTONIC], [], [], [[#include <time.h>]])
AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE([HAVE_CLOCK_GETTIME],[],[Define if clock_gettime() is available])])
AC_CACHE_CHECK([for SO_PEERCRED and dependencies], [x_cv_linux_so_peercred], [
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#define _GNU_SOURCE
#include <features.h>
#include <sys/socket.h>
]],[[
struct ucred cr;
socklen_t crlen = sizeof(cr);
return getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cr, &crlen) +
cr.pid + cr.uid + cr.gid;
]]
)],
AS_VAR_SET(x_cv_linux_so_peercred, yes),
AS_VAR_SET(x_cv_linux_so_peercred, no)
)
])
AS_IF([test AS_VAR_GET(x_cv_linux_so_peercred) = yes],
[AC_DEFINE([HAVE_SO_PEERCRED], [1],
[Define if SO_PEERCRED works in the Linux fashion.])]
)
if test "x$GCC" = "xyes"; then
:
AC_SUBST(WARNINGOPTS, ['-Wall -Werror'])

View File

@ -43,6 +43,11 @@ static const char *sk_error_socket_error(Socket s)
return ps->error;
}
static char *sk_error_peer_info(Socket s)
{
return NULL;
}
Socket new_error_socket(const char *errmsg, Plug plug)
{
static const struct socket_function_table socket_fn_table = {
@ -53,7 +58,8 @@ Socket new_error_socket(const char *errmsg, Plug plug)
NULL /* write_eof */,
NULL /* flush */,
NULL /* set_frozen */,
sk_error_socket_error
sk_error_socket_error,
sk_error_peer_info,
};
Error_Socket ret;

View File

@ -38,6 +38,7 @@ struct socket_function_table {
void (*set_frozen) (Socket s, int is_frozen);
/* ignored by tcp, but vital for ssl */
const char *(*socket_error) (Socket s);
char *(*peer_info) (Socket s);
};
typedef union { void *p; int i; } accept_ctx_t;
@ -181,6 +182,13 @@ const char *sk_addr_error(SockAddr addr);
*/
#define sk_set_frozen(s, is_frozen) (((*s)->set_frozen) (s, is_frozen))
/*
* Return a (dynamically allocated) string giving some information
* about the other end of the socket, suitable for putting in log
* files. May be NULL if nothing is available at all.
*/
#define sk_peer_info(s) (((*s)->peer_info) (s))
/*
* Simple wrapper on getservbyname(), needed by ssh.c. Returns the
* port number, in host byte order (suitable for printf and so on).

View File

@ -157,6 +157,21 @@ static int pfl_closing(Plug plug, const char *error_msg, int error_code,
return 1;
}
static void wrap_send_port_open(void *channel, char *hostname, int port,
Socket s)
{
char *peerinfo, *description;
peerinfo = sk_peer_info(s);
if (peerinfo) {
description = dupprintf("forwarding from %s", peerinfo);
sfree(peerinfo);
} else {
description = dupstr("forwarding");
}
ssh_send_port_open(channel, hostname, port, description);
sfree(description);
}
static int pfd_receive(Plug plug, int urgent, char *data, int len)
{
struct PortForwarding *pf = (struct PortForwarding *) plug;
@ -371,7 +386,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
return 1;
} else {
/* asks to forward to the specified host/port for this */
ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");
wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s);
}
pf->dynamic = 0;
@ -510,7 +525,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
return 1;
} else {
/* asks to forward to the specified host/port for this */
ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");
wrap_send_port_open(pf->c, pf->hostname, pf->port, s);
}
}

View File

@ -388,7 +388,8 @@ Socket new_connection(SockAddr addr, char *hostname,
sk_proxy_write_eof,
sk_proxy_flush,
sk_proxy_set_frozen,
sk_proxy_socket_error
sk_proxy_socket_error,
NULL, /* peer_info */
};
static const struct plug_function_table plug_fn_table = {

9
ssh.c
View File

@ -7608,9 +7608,14 @@ static void ssh_check_termination(Ssh ssh)
}
}
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id)
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,
const char *peerinfo)
{
logeventf(ssh, "Connection sharing downstream #%u connected", id);
if (peerinfo)
logeventf(ssh, "Connection sharing downstream #%u connected from %s",
id, peerinfo);
else
logeventf(ssh, "Connection sharing downstream #%u connected", id);
}
void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id)

3
ssh.h
View File

@ -44,7 +44,8 @@ void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth);
void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type,
const void *pkt, int pktlen,
const char *additional_log_text);
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id);
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,
const char *peerinfo);
void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id);
void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...);
int ssh_agent_forwarding_permitted(Ssh ssh);

View File

@ -1924,6 +1924,7 @@ static int share_listen_accepting(Plug plug,
struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)plug;
struct ssh_sharing_connstate *cs;
const char *err;
char *peerinfo;
/*
* A new downstream has connected to us.
@ -1966,7 +1967,9 @@ static int share_listen_accepting(Plug plug,
cs->forwardings = newtree234(share_forwarding_cmp);
cs->globreq_head = cs->globreq_tail = NULL;
ssh_sharing_downstream_connected(sharestate->ssh, cs->id);
peerinfo = sk_peer_info(cs->sock);
ssh_sharing_downstream_connected(sharestate->ssh, cs->id, peerinfo);
sfree(peerinfo);
return 0;
}

View File

@ -184,4 +184,9 @@ void *sk_getxdmdata(void *sock, int *lenp);
*/
extern Backend serial_backend;
/*
* uxpeer.c, wrapping getsockopt(SO_PEERCRED).
*/
int so_peercred(int fd, int *pid, int *uid, int *gid);
#endif

View File

@ -16,6 +16,8 @@
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/un.h>
#include <pwd.h>
#include <grp.h>
#define DEFINE_PLUG_METHOD_MACROS
#include "putty.h"
@ -485,6 +487,7 @@ static int sk_tcp_write(Socket s, const char *data, int len);
static int sk_tcp_write_oob(Socket s, const char *data, int len);
static void sk_tcp_write_eof(Socket s);
static void sk_tcp_set_frozen(Socket s, int is_frozen);
static char *sk_tcp_peer_info(Socket s);
static const char *sk_tcp_socket_error(Socket s);
static struct socket_function_table tcp_fn_table = {
@ -495,7 +498,8 @@ static struct socket_function_table tcp_fn_table = {
sk_tcp_write_eof,
sk_tcp_flush,
sk_tcp_set_frozen,
sk_tcp_socket_error
sk_tcp_socket_error,
sk_tcp_peer_info,
};
static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
@ -1419,6 +1423,51 @@ static void sk_tcp_set_frozen(Socket sock, int is_frozen)
uxsel_tell(s);
}
static char *sk_tcp_peer_info(Socket sock)
{
Actual_Socket s = (Actual_Socket) sock;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
char buf[INET6_ADDRSTRLEN];
if (getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
return NULL;
if (addr.ss_family == AF_INET) {
return dupprintf
("%s:%d",
inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr),
(int)ntohs(((struct sockaddr_in *)&addr)->sin_port));
#ifndef NO_IPV6
} else if (addr.ss_family == AF_INET6) {
return dupprintf
("[%s]:%d",
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
buf, sizeof(buf)),
(int)ntohs(((struct sockaddr_in6 *)&addr)->sin6_port));
#endif
} else if (addr.ss_family == AF_UNIX) {
/*
* For Unix sockets, the source address is unlikely to be
* helpful. Instead, we try SO_PEERCRED and try to get the
* source pid.
*/
int pid, uid, gid;
if (so_peercred(s->s, &pid, &uid, &gid)) {
char uidbuf[64], gidbuf[64];
sprintf(uidbuf, "%d", uid);
sprintf(gidbuf, "%d", gid);
struct passwd *pw = getpwuid(uid);
struct group *gr = getgrgid(gid);
return dupprintf("pid %d (%s:%s)", pid,
pw ? pw->pw_name : uidbuf,
gr ? gr->gr_name : gidbuf);
}
return NULL;
} else {
return NULL;
}
}
static void uxsel_tell(Actual_Socket s)
{
int rwx = 0;

32
unix/uxpeer.c Normal file
View File

@ -0,0 +1,32 @@
/*
* Unix: wrapper for getsockopt(SO_PEERCRED), conditionalised on
* appropriate autoconfery.
*/
#ifdef HAVE_CONFIG_H
# include "uxconfig.h" /* leading space prevents mkfiles.pl trying to follow */
#endif
#ifdef HAVE_SO_PEERCRED
#define _GNU_SOURCE
#include <features.h>
#endif
#include <sys/socket.h>
#include "putty.h"
int so_peercred(int fd, int *pid, int *uid, int *gid)
{
#ifdef HAVE_SO_PEERCRED
struct ucred cr;
socklen_t crlen = sizeof(cr);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crlen) == 0) {
*pid = cr.pid;
*uid = cr.uid;
*gid = cr.gid;
return TRUE;
}
#endif
return FALSE;
}

View File

@ -245,7 +245,8 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
sk_localproxy_write_eof,
sk_localproxy_flush,
sk_localproxy_set_frozen,
sk_localproxy_socket_error
sk_localproxy_socket_error,
NULL, /* peer_info */
};
Local_Proxy_Socket ret;

View File

@ -234,6 +234,11 @@ static const char *sk_handle_socket_error(Socket s)
return ps->error;
}
static char *sk_handle_peer_info(Socket s)
{
return NULL;
}
Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, Plug plug,
int overlapped)
{
@ -245,7 +250,8 @@ Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, Plug plug,
sk_handle_write_eof,
sk_handle_flush,
sk_handle_set_frozen,
sk_handle_socket_error
sk_handle_socket_error,
sk_handle_peer_info,
};
Handle_Socket ret;

View File

@ -160,6 +160,8 @@ DECL_WINDOWS_FUNCTION(static, struct servent FAR *, getservbyname,
(const char FAR *, const char FAR *));
DECL_WINDOWS_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));
DECL_WINDOWS_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));
DECL_WINDOWS_FUNCTION(static, const char FAR *, inet_ntop,
(int, void FAR *, char *, size_t));
DECL_WINDOWS_FUNCTION(static, int, connect,
(SOCKET, const struct sockaddr FAR *, int));
DECL_WINDOWS_FUNCTION(static, int, bind,
@ -174,6 +176,8 @@ DECL_WINDOWS_FUNCTION(static, int, ioctlsocket,
(SOCKET, long, u_long FAR *));
DECL_WINDOWS_FUNCTION(static, SOCKET, accept,
(SOCKET, struct sockaddr FAR *, int FAR *));
DECL_WINDOWS_FUNCTION(static, int, getpeername,
(SOCKET, struct sockaddr FAR *, int FAR *));
DECL_WINDOWS_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
DECL_WINDOWS_FUNCTION(static, int, WSAIoctl,
(SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
@ -288,6 +292,7 @@ void sk_init(void)
GET_WINDOWS_FUNCTION(winsock_module, getservbyname);
GET_WINDOWS_FUNCTION(winsock_module, inet_addr);
GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa);
GET_WINDOWS_FUNCTION(winsock_module, inet_ntop);
GET_WINDOWS_FUNCTION(winsock_module, connect);
GET_WINDOWS_FUNCTION(winsock_module, bind);
GET_WINDOWS_FUNCTION(winsock_module, setsockopt);
@ -297,6 +302,7 @@ void sk_init(void)
GET_WINDOWS_FUNCTION(winsock_module, shutdown);
GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket);
GET_WINDOWS_FUNCTION(winsock_module, accept);
GET_WINDOWS_FUNCTION(winsock_module, getpeername);
GET_WINDOWS_FUNCTION(winsock_module, recv);
GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl);
@ -861,6 +867,7 @@ static int sk_tcp_write_oob(Socket s, const char *data, int len);
static void sk_tcp_write_eof(Socket s);
static void sk_tcp_set_frozen(Socket s, int is_frozen);
static const char *sk_tcp_socket_error(Socket s);
static char *sk_tcp_peer_info(Socket s);
extern char *do_select(SOCKET skt, int startup);
@ -874,7 +881,8 @@ static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
sk_tcp_write_eof,
sk_tcp_flush,
sk_tcp_set_frozen,
sk_tcp_socket_error
sk_tcp_socket_error,
sk_tcp_peer_info,
};
DWORD err;
@ -1122,7 +1130,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
sk_tcp_write_eof,
sk_tcp_flush,
sk_tcp_set_frozen,
sk_tcp_socket_error
sk_tcp_socket_error,
sk_tcp_peer_info,
};
Actual_Socket ret;
@ -1173,7 +1182,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
sk_tcp_write_eof,
sk_tcp_flush,
sk_tcp_set_frozen,
sk_tcp_socket_error
sk_tcp_socket_error,
sk_tcp_peer_info,
};
SOCKET s;
@ -1744,6 +1754,38 @@ static const char *sk_tcp_socket_error(Socket sock)
return s->error;
}
static char *sk_tcp_peer_info(Socket sock)
{
Actual_Socket s = (Actual_Socket) sock;
#ifdef NO_IPV6
struct sockaddr_in addr;
#else
struct sockaddr_storage addr;
#endif
int addrlen = sizeof(addr);
char buf[INET6_ADDRSTRLEN];
if (p_getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
return NULL;
if (((struct sockaddr *)&addr)->sa_family == AF_INET) {
return dupprintf
("%s:%d",
p_inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr),
(int)p_ntohs(((struct sockaddr_in *)&addr)->sin_port));
#ifndef NO_IPV6
} else if (((struct sockaddr *)&addr)->sa_family == AF_INET6) {
return dupprintf
("[%s]:%d",
p_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
buf, sizeof(buf)),
(int)p_ntohs(((struct sockaddr_in6 *)&addr)->sin6_port));
#endif
} else {
return NULL;
}
}
static void sk_tcp_set_frozen(Socket sock, int is_frozen)
{
Actual_Socket s = (Actual_Socket) sock;

View File

@ -71,6 +71,11 @@ static const char *sk_namedpipeserver_socket_error(Socket s)
return ps->error;
}
static char *sk_namedpipeserver_peer_info(Socket s)
{
return NULL;
}
static int create_named_pipe(Named_Pipe_Server_Socket ps, int first_instance)
{
SECURITY_ATTRIBUTES sa;
@ -211,7 +216,8 @@ Socket new_named_pipe_listener(const char *pipename, Plug plug)
NULL /* write_eof */,
NULL /* flush */,
NULL /* set_frozen */,
sk_namedpipeserver_socket_error
sk_namedpipeserver_socket_error,
sk_namedpipeserver_peer_info,
};
Named_Pipe_Server_Socket ret;