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
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'])
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 = {
NULL /* write_eof */,
NULL /* flush */,
NULL /* set_frozen */,
- sk_error_socket_error
+ sk_error_socket_error,
+ sk_error_peer_info,
};
Error_Socket ret;
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;
*/
#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).
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;
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;
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);
}
}
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 = {
}
}
-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)
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);
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.
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;
}
*/
extern Backend serial_backend;
+/*
+ * uxpeer.c, wrapping getsockopt(SO_PEERCRED).
+ */
+int so_peercred(int fd, int *pid, int *uid, int *gid);
+
#endif
#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"
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 = {
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)
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;
--- /dev/null
+/*
+ * 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;
+}
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;
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)
{
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;
(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,
(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,
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);
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);
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);
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;
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;
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;
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;
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;
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;