Miquel van Smoorenburg <miquels@cistron.nl> supplied this note and patch: [...] However, in IPv6 mode, sshd doesn't write the utmp 'ut_addr' field. This patch fixes that; for 4-in-6 connections, the IPv4 address is written to ut_addr, for IPv6 connections, the IPv6 address is written to ut_addr_v6. This basically is a security fix, though a minor one; Linux doesn't have the ut_addr / ut_addr_v6 field just to leave them empty ! The next sysvinit (2.85) will include a 'last' that knows how to read ut_addr_v6 from the wtmp file (I'm the maintainer). diff -ruN t/openssh-3.5p1/loginrec.c openssh-3.5p1/loginrec.c --- t/openssh-3.5p1/loginrec.c 2002-09-26 02:38:49.000000000 +0200 +++ openssh-3.5p1/loginrec.c 2002-11-05 13:14:33.000000000 +0100 @@ -609,6 +609,9 @@ construct_utmp(struct logininfo *li, struct utmp *ut) { +# ifdef HAVE_ADDR_V6_IN_UTMP + struct sockaddr_in6 *sa6; +# endif memset(ut, '\0', sizeof(*ut)); /* First fill out fields used for both logins and logouts */ @@ -661,6 +664,19 @@ if (li->hostaddr.sa.sa_family == AF_INET) ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; # endif +# ifdef HAVE_ADDR_V6_IN_UTMP + /* this is just a 128-bit IPv6 address */ + if (li->hostaddr.sa.sa_family == AF_INET6) { + sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); + memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); + if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { + ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; + ut->ut_addr_v6[1] = 0; + ut->ut_addr_v6[2] = 0; + ut->ut_addr_v6[3] = 0; + } + } +# endif } #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ @@ -689,6 +705,9 @@ void construct_utmpx(struct logininfo *li, struct utmpx *utx) { +# ifdef HAVE_ADDR_V6_IN_UTMP + struct sockaddr_in6 *sa6; +# endif memset(utx, '\0', sizeof(*utx)); # ifdef HAVE_ID_IN_UTMPX line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); @@ -725,6 +744,19 @@ if (li->hostaddr.sa.sa_family == AF_INET) utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; # endif +# ifdef HAVE_ADDR_V6_IN_UTMP + /* this is just a 128-bit IPv6 address */ + if (li->hostaddr.sa.sa_family == AF_INET6) { + sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); + memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); + if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { + ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; + ut->ut_addr_v6[1] = 0; + ut->ut_addr_v6[2] = 0; + ut->ut_addr_v6[3] = 0; + } + } +# endif # ifdef HAVE_SYSLEN_IN_UTMPX /* ut_syslen is the length of the utx_host string */ utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host)); diff -ruN t/openssh-3.5p1/session.c openssh-3.5p1/session.c --- t/openssh-3.5p1/session.c 2002-09-26 02:38:50.000000000 +0200 +++ openssh-3.5p1/session.c 2002-11-05 13:11:30.000000000 +0100 @@ -730,8 +730,8 @@ * the address be 0.0.0.0. */ memset(&from, 0, sizeof(from)); + fromlen = sizeof(from); if (packet_connection_is_on_socket()) { - fromlen = sizeof(from); if (getpeername(packet_get_connection_in(), (struct sockaddr *) & from, &fromlen) < 0) { debug("getpeername: %.100s", strerror(errno)); diff -ruN t/openssh-3.5p1/sshlogin.c openssh-3.5p1/sshlogin.c --- t/openssh-3.5p1/sshlogin.c 2002-09-04 08:45:11.000000000 +0200 +++ openssh-3.5p1/sshlogin.c 2002-11-05 13:12:25.000000000 +0100 @@ -70,7 +70,7 @@ struct logininfo *li; li = login_alloc_entry(pid, user, host, ttyname); - login_set_addr(li, addr, sizeof(struct sockaddr)); + login_set_addr(li, addr, addrlen); login_login(li); login_free_entry(li); }
FYI: patches are best attached to a bug, rather than copied into comments. Applied - thanks.
Noted for the future. Thanks.
Mass change of RESOLVED bugs to CLOSED