--- usr/src/lib/libc/net/rcmd.c 2012-07-14 19:44:54.000000000 +1000 +++ usr/src/lib/libc/net/rcmd.c 2012-07-14 19:42:47.000000000 +1000 @@ -330,6 +330,14 @@ rresvport_af(alport, family) int *alport, family; { + return rresvport_af_addr(alport, family, NULL); +} + +int +rresvport_af_addr(alport, family, addr) + int *alport, family; + void *addr; +{ int s; struct sockaddr_storage ss; u_short *sport; @@ -340,13 +348,19 @@ case AF_INET: ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in); sport = &((struct sockaddr_in *)&ss)->sin_port; - ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY; + if (addr != NULL) + ((struct sockaddr_in *)&ss)->sin_addr = ((struct sockaddr_in *)addr)->sin_addr; + else + ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY; break; #ifdef INET6 case AF_INET6: ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6); sport = &((struct sockaddr_in6 *)&ss)->sin6_port; - ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any; + if (addr != NULL) + ((struct sockaddr_in6 *)&ss)->sin6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr; + else + ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any; break; #endif default: --- usr/src/include/unistd.h 2012-01-03 14:23:59.000000000 +1100 +++ usr/src/include/unistd.h 2012-07-14 19:42:25.000000000 +1000 @@ -546,6 +546,7 @@ pid_t rfork_thread(int, void *, int (*)(void *), void *); int rresvport(int *); int rresvport_af(int *, int); +int rresvport_af_addr(int *, int, void *); int ruserok(const char *, int, const char *, const char *); #if __BSD_VISIBLE #ifndef _SELECT_DECLARED --- usr/src/lib/libc/net/Symbol.map 2012-01-03 14:26:01.000000000 +1100 +++ usr/src/lib/libc/net/Symbol.map 2012-07-14 20:15:17.000000000 +1000 @@ -99,6 +99,7 @@ rcmd_af; rresvport; rresvport_af; + rresvport_af_addr; ruserok; iruserok; iruserok_sa; --- usr/src/libexec/rshd/rshd.c 2012-01-03 14:26:11.000000000 +1100 +++ usr/src/libexec/rshd/rshd.c 2012-07-14 20:22:58.000000000 +1000 @@ -110,7 +110,7 @@ int sent_null; int no_delay; -void doit(struct sockaddr *); +void doit(struct sockaddr *, struct sockaddr *); static void rshd_errx(int, const char *, ...) __printf0like(2, 3); void getstr(char *, int, const char *); int local_domain(char *); @@ -128,8 +128,10 @@ extern int __check_rhosts_file; struct linger linger; socklen_t fromlen; + socklen_t locallen; int ch, on = 1; struct sockaddr_storage from; + struct sockaddr_storage local; openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); @@ -165,6 +167,10 @@ syslog(LOG_ERR, "getpeername: %m"); exit(1); } + if (getsockname(0, (struct sockaddr *)&local, &locallen) < 0) { + syslog(LOG_ERR, "getsockname: %m"); + exit(1); + } if (keepalive && setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) @@ -177,7 +183,7 @@ if (no_delay && setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); - doit((struct sockaddr *)&from); + doit((struct sockaddr *)&from, (struct sockaddr *)&local); /* NOTREACHED */ return(0); } @@ -185,7 +191,7 @@ extern char **environ; void -doit(struct sockaddr *fromp) +doit(struct sockaddr *fromp, struct sockaddr *localp) { extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ struct passwd *pwd; @@ -278,7 +284,7 @@ (void) alarm(0); if (port != 0) { int lport = IPPORT_RESERVED - 1; - s = rresvport_af(&lport, af); + s = rresvport_af_addr(&lport, af, localp); if (s < 0) { syslog(LOG_ERR, "can't get stderr port: %m"); exit(1);