diff --git a/ChangeLog b/ChangeLog index 2d5c6199..f4f3b77b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2012-07-21 Mats Erik Andersson + + r-commands: Partial IPv6 support. + Adapt host resolution to cope with IPv6, + in particular for libshishi related code. + + * libinetutils/kcmd.c (getport): New signature + `(int *, int)', adding address family parameter. + Update code to use `struct sockaddr_storage'. + New variable LEN. + (kcmd): New alternate code using getaddrinfo(), + instead of gethostbyname(). + [HAVE_DECL_GETADDRINFO]: New variables HINTS, AI, RES. + + * libinetutils/shishi_def.h : Changed + type of FROM to `struct sockaddr_storage'. + * src/rlogind.c [!SHISHI]: Likewise. + (rlogind_auth): New variables ADDRP, PORT. Adapt to new + type of `auth_data.from'. + [!KERBEROS]: Accept families AF_INET and AF_INET6. + (rlogind_mainloop): Adapt to new `auth_data.from'. + (do_rlogin): Likewise. + [WITH_IRUSEROK_AF || WITH_IRUSEROK]: New variable ADDRP. + (do_shishi_login): New type `struct sockaddr_storage' + for SOCK. + 2012-07-18 Mats Erik Andersson rlogin: Close libshishi handle. diff --git a/libinetutils/kcmd.c b/libinetutils/kcmd.c index c3f079e4..130b9e52 100644 --- a/libinetutils/kcmd.c +++ b/libinetutils/kcmd.c @@ -88,7 +88,7 @@ # define START_PORT 5120 /* arbitrary */ -int getport (int *); +int getport (int *, int); # if defined KERBEROS int @@ -120,7 +120,12 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, # else int lport = START_PORT; # endif +# ifdef HAVE_DECL_GETADDRINFO + struct addrinfo hints, *ai, *res; + char portstr[8]; +# else /* !HAVE_DECL_GETADDRINFO */ struct hostent *hp; +# endif int rc; char *host_save; int status; @@ -131,7 +136,29 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, pid = getpid (); - /* FIXME: Often the following rejects non-IPv4. +# ifdef HAVE_DECL_GETADDRINFO + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + snprintf (portstr, sizeof (portstr), "%hu", ntohs (rport)); + + rc = getaddrinfo (*ahost, portstr, &hints, &res); + if (rc) + { + fprintf (stderr, "kcmd: host %s: %s\n", *ahost, gai_strerror (rc)); + return (-1); + } + + ai = res; + + host_save = malloc (strlen (ai->ai_canonname) + 1); + if (host_save == NULL) + return (-1); + strcpy (host_save, ai->ai_canonname); + +# else /* !HAVE_DECL_GETADDRINFO */ + /* Often the following rejects non-IPv4. * This is dependent on system implementation. */ hp = gethostbyname (*ahost); if (hp == NULL) @@ -144,6 +171,8 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, if (host_save == NULL) return -1; strcpy (host_save, hp->h_name); +# endif /* !HAVE_DECL_GETADDRINFO */ + *ahost = host_save; # ifdef KERBEROS @@ -161,7 +190,11 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, # endif /* !HAVE_SIGACTION */ for (;;) { - s = getport (&lport); +# ifdef HAVE_DECL_GETADDRINFO + s = getport (&lport, ai->ai_family); +# else /* !HAVE_DECL_GETADDRINFO */ + s = getport (&lport, hp->h_addrtype); +# endif if (s < 0) { if (errno == EAGAIN) @@ -176,14 +209,19 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, return (-1); } fcntl (s, F_SETOWN, pid); + +# ifdef HAVE_DECL_GETADDRINFO + len = ai->ai_addrlen; + memcpy (&sin, ai->ai_addr, ai->ai_addrlen); +# else /* !HAVE_DECL_GETADDRINFO */ sin.ss_family = hp->h_addrtype; switch (hp->h_addrtype) { case AF_INET6: len = sizeof (struct sockaddr_in6); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN +# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.ss_len = len; -#endif +# endif memcpy (&((struct sockaddr_in6 *) &sin)->sin6_addr, hp->h_addr, hp->h_length); ((struct sockaddr_in6 *) &sin)->sin6_port = rport; @@ -191,13 +229,14 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, case AF_INET: default: len = sizeof (struct sockaddr_in); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN +# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.ss_len = len; -#endif +# endif memcpy (&((struct sockaddr_in *) &sin)->sin_addr, hp->h_addr, hp->h_length); ((struct sockaddr_in *) &sin)->sin_port = rport; } +# endif /* !HAVE_DECL_GETADDRINFO */ if (connect (s, (struct sockaddr *) &sin, len) >= 0) break; @@ -217,11 +256,28 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, continue; } # if ! defined ultrix || defined sun +# ifdef HAVE_DECL_GETADDRINFO + if (ai->ai_next) +# else /* !HAVE_DECL_GETADDRINFO */ if (hp->h_addr_list[1] != NULL) +# endif { int oerrno = errno; char addrstr[INET6_ADDRSTRLEN]; +# ifdef HAVE_DECL_GETADDRINFO + getnameinfo (ai->ai_addr, ai->ai_addrlen, + addrstr, sizeof (addrstr), NULL, 0, + NI_NUMERICHOST); + fprintf (stderr, "kcmd: connect to address %s: ", addrstr); + errno = oerrno; + perror (NULL); + ai = ai->ai_next; + getnameinfo (ai->ai_addr, ai->ai_addrlen, + addrstr, sizeof (addrstr), NULL, 0, + NI_NUMERICHOST); + fprintf (stderr, "Trying %s...\n", addrstr); +# else /* !HAVE_DECL_GETADDRINFO */ fprintf (stderr, "kcmd: connect to address %s: ", inet_ntop (hp->h_addrtype, hp->h_addr_list[0], addrstr, sizeof (addrstr))); @@ -231,11 +287,20 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, fprintf (stderr, "Trying %s...\n", inet_ntop (hp->h_addrtype, hp->h_addr_list[0], addrstr, sizeof (addrstr))); +# endif /* !HAVE_DECL_GETADDRINFO */ continue; } # endif /* !(defined(ultrix) || defined(sun)) */ +# ifdef HAVE_DECL_GETADDRINFO + if (errno != ECONNREFUSED) + perror (res->ai_canonname); + + if (res) + freeaddrinfo (res); +# else /* !HAVE_DECL_GETADDRINFO */ if (errno != ECONNREFUSED) perror (hp->h_name); +# endif # if HAVE_SIGACTION sigprocmask (SIG_SETMASK, &osigs, NULL); @@ -245,6 +310,11 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, return (-1); } +# ifdef HAVE_DECL_GETADDRINFO + if (res) + freeaddrinfo (res); +#endif + lport--; if (fd2p == 0) { @@ -256,7 +326,7 @@ kcmd (Shishi ** h, int *sock, char **ahost, unsigned short rport, char *locuser, char num[8]; int port, s2, s3; - s2 = getport (&lport); + s2 = getport (&lport, sin.ss_family); len = sizeof (from); if (s2 < 0) @@ -403,23 +473,38 @@ bad: } int -getport (int *alport) +getport (int *alport, int af) { - struct sockaddr_in sin; + struct sockaddr_storage sin; + socklen_t len; int s; - sin.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = sizeof (sin); -#endif - sin.sin_addr.s_addr = INADDR_ANY; - s = socket (sin.sin_family, SOCK_STREAM, 0); + memset (&sin, 0, sizeof (sin)); + sin.ss_family = af; + len = (af == AF_INET6) ? sizeof (struct sockaddr_in6) + : sizeof (struct sockaddr_in); +# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin.ss_len = len; +# endif + + s = socket (sin.ss_family, SOCK_STREAM, 0); if (s < 0) return (-1); for (;;) { - sin.sin_port = htons ((unsigned short) * alport); - if (bind (s, (struct sockaddr *) &sin, sizeof (sin)) >= 0) + switch (af) + { + case AF_INET6: + ((struct sockaddr_in6 *) &sin)->sin6_port = + htons ((unsigned short) * alport); + break; + case AF_INET: + default: + ((struct sockaddr_in *) &sin)->sin_port = + htons ((unsigned short) * alport); + } + + if (bind (s, (struct sockaddr *) &sin, len) >= 0) return (s); if (errno != EADDRINUSE) { diff --git a/libinetutils/shishi_def.h b/libinetutils/shishi_def.h index 71ef2d77..bd8b9d61 100644 --- a/libinetutils/shishi_def.h +++ b/libinetutils/shishi_def.h @@ -36,7 +36,7 @@ typedef struct shishi_iv shishi_ivector; struct auth_data { - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; char *hostaddr; char *hostname; diff --git a/src/rlogind.c b/src/rlogind.c index f463f44e..4340dcf0 100644 --- a/src/rlogind.c +++ b/src/rlogind.c @@ -144,7 +144,7 @@ extern int __check_rhosts_file; #ifndef SHISHI struct auth_data { - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; char *hostaddr; char *hostname; @@ -442,6 +442,7 @@ main (int argc, char *argv[]) return 0; } +/* FIXME: Migrate to IPv6 supported listener. */ void rlogin_daemon (int maxchildren, int port) @@ -546,7 +547,7 @@ rlogin_daemon (int maxchildren, int port) int rlogind_auth (int fd, struct auth_data *ap) { -#if defined HAVE_DECL_GETNAMEINFO || defined HAVE_DECL_GETADDRINFO +#if defined HAVE_DECL_GETNAMEINFO && defined HAVE_DECL_GETADDRINFO int rc; char hoststr[NI_MAXHOST]; #else @@ -554,11 +555,25 @@ rlogind_auth (int fd, struct auth_data *ap) #endif char *hostname; int authenticated = 0; + void * addrp; + int port; #ifdef SHISHI int len, c; #endif + switch (ap->from.ss_family) + { + case AF_INET6: + addrp = (void *) &((struct sockaddr_in6 *) &ap->from)->sin6_addr; + port = ntohs (((struct sockaddr_in6 *) &ap->from)->sin6_port); + break; + case AF_INET: + default: + addrp = (void *) &((struct sockaddr_in *) &ap->from)->sin_addr; + port = ntohs (((struct sockaddr_in *) &ap->from)->sin_port); + } + confirmed = 0; /* Check the remote host name */ @@ -568,8 +583,17 @@ rlogind_auth (int fd, struct auth_data *ap) if (!rc) hostname = hoststr; #else /* !HAVE_DECL_GETNAMEINFO */ - hp = gethostbyaddr ((char *) &ap->from.sin_addr, sizeof (struct in_addr), - ap->from.sin_family); + switch (ap->from.ss_family) + { + case AF_INET6: + hp = gethostbyaddr (addrp, sizeof (struct in6_addr), + ap->from.ss_family); + break; + case AF_INET: + default: + hp = gethostbyaddr (addrp, sizeof (struct in_addr), + ap->from.ss_family); + } if (hp) hostname = hp->h_name; #endif /* !HAVE_DECL_GETNAMEINFO */ @@ -591,7 +615,7 @@ rlogind_auth (int fd, struct auth_data *ap) char astr[INET6_ADDRSTRLEN]; memset (&hints, 0, sizeof (hints)); - hints.ai_family = ap->from.sin_family; + hints.ai_family = ap->from.ss_family; hints.ai_socktype = SOCK_STREAM; rc = getaddrinfo (ap->hostname, NULL, &hints, &res); @@ -615,8 +639,7 @@ rlogind_auth (int fd, struct auth_data *ap) { if (hp->h_addr_list[0] == NULL) break; - match = memcmp (hp->h_addr_list[0], &ap->from.sin_addr, - sizeof (ap->from.sin_addr)) == 0; + match = memcmp (hp->h_addr_list[0], addrp, hp->h_length) == 0; } #endif /* !HAVE_DECL_GETADDRINFO */ if (!match) @@ -638,15 +661,17 @@ rlogind_auth (int fd, struct auth_data *ap) else fatal (fd, err_msg, 0); write (fd, &c, 1); - confirmed = 1; /* we sent the null! */ + confirmed = 1; /* We have sent the null! */ } else #endif { - int port = ntohs (ap->from.sin_port); - - if (ap->from.sin_family != AF_INET || - port >= IPPORT_RESERVED || port < IPPORT_RESERVED / 2) + if ((ap->from.ss_family != AF_INET +#ifndef KERBEROS + && ap->from.ss_family != AF_INET6 +#endif + ) + || port >= IPPORT_RESERVED || port < IPPORT_RESERVED / 2) { syslog (LOG_NOTICE, "Connection from %s on illegal port %d", ap->hostaddr, port); @@ -818,7 +843,10 @@ rlogind_mainloop (int infd, int outfd) fatal (outfd, "Can't get peer name of remote host", 1); } - reply = inet_ntop (auth_data.from.sin_family, &auth_data.from.sin_addr, + reply = inet_ntop (auth_data.from.ss_family, + (auth_data.from.ss_family == AF_INET6) + ? (void *) &((struct sockaddr_in6 *) &auth_data.from)->sin6_addr + : (void *) &((struct sockaddr_in *) &auth_data.from)->sin_addr, addrstr, sizeof (addrstr)); if (reply == NULL) { @@ -828,7 +856,9 @@ rlogind_mainloop (int infd, int outfd) auth_data.hostaddr = xstrdup (addrstr); syslog (LOG_INFO, "Connect from %s:%d", auth_data.hostaddr, - ntohs (auth_data.from.sin_port)); + (auth_data.from.ss_family == AF_INET6) + ? ntohs (((struct sockaddr_in6 *) &auth_data.from)->sin6_port) + : ntohs (((struct sockaddr_in *) &auth_data.from)->sin_port)); true = 1; if (keepalive @@ -923,6 +953,19 @@ do_rlogin (int infd, struct auth_data *ap) { struct passwd *pwd; int rc; +#if defined WITH_IRUSEROK_AF || defined WITH_IRUSEROK + void *addrp; + + switch (ap->from.ss_family) + { + case AF_INET6: + addrp = (void *) &((struct sockaddr_in6 *) &ap->from)->sin6_addr; + break; + case AF_INET: + default: + addrp = (void *) &((struct sockaddr_in *) &ap->from)->sin_addr; + } +#endif /* WITH_IRUSEROK_AF || WITH_IRUSEROK */ getstr (infd, &ap->rusername, NULL); getstr (infd, &ap->lusername, NULL); @@ -946,10 +989,10 @@ do_rlogin (int infd, struct auth_data *ap) rc = iruserok_sa ((struct sockaddr *) &ap->from, ap->fromlen, 0, ap->rusername, ap->lusername); # elif defined WITH_IRUSEROK_AF - rc = iruserok_af (&ap->from.sin_addr, 0, ap->rusername, ap->lusername, - ap->from.sin_family); + rc = iruserok_af (addrp, 0, ap->rusername, ap->lusername, + ap->from.ss_family); # else /* WITH_IRUSEROK */ - rc = iruserok (ap->from.sin_addr.s_addr, 0, ap->rusername, ap->lusername); + rc = iruserok (addrp, 0, ap->rusername, ap->lusername); # endif /* WITH_IRUSEROK_SA || WITH_IRUSEROK_AF || WITH_IRUSEROK */ if (rc) syslog (LOG_ERR | LOG_AUTH, @@ -958,7 +1001,7 @@ do_rlogin (int infd, struct auth_data *ap) #elif defined WITH_RUSEROK_AF || defined WITH_RUSEROK # ifdef WITH_RUSEROK_AF rc = ruserok_af (ap->hostaddr, 0, ap->rusername, ap->lusername, - ap->from.sin_family); + ap->from.ss_family); # else /* WITH_RUSEROK */ rc = ruserok (ap->hostaddr, 0, ap->rusername, ap->lusername); # endif /* WITH_RUSEROK_AF || WITH_RUSEROK */ @@ -1187,7 +1230,7 @@ do_shishi_login (int infd, struct auth_data *ad, const char **err_msg) char *compcksum; size_t compcksumlen, cksumlen = 30; char cksumdata[100]; - struct sockaddr_in sock; + struct sockaddr_storage sock; socklen_t socklen = sizeof (sock); # ifdef ENCRYPTION @@ -1296,8 +1339,11 @@ do_shishi_login (int infd, struct auth_data *ad, const char **err_msg) fatal (infd, "Can't get sockname", 1); } - snprintf (cksumdata, 100, "%u:%s%s", ntohs (sock.sin_port), ad->term + 5, - ad->lusername); + snprintf (cksumdata, 100, "%u:%s%s", + (sock.ss_family == AF_INET6) + ? ntohs (((struct sockaddr_in6 *) &sock)->sin6_port) + : ntohs (((struct sockaddr_in *) &sock)->sin_port), + ad->term + 5, ad->lusername); rc = shishi_checksum (ad->h, ad->enckey, 0, cksumtype, cksumdata, strlen (cksumdata), &compcksum, &compcksumlen); if (rc != SHISHI_OK