diff --git a/libexec/rpc.rusersd/rusers_proc.c b/libexec/rpc.rusersd/rusers_proc.c --- a/libexec/rpc.rusersd/rusers_proc.c +++ b/libexec/rpc.rusersd/rusers_proc.c @@ -52,6 +52,7 @@ #define _PATH_DEV "/dev" #endif +static rusers_utmp rusers_utmps[MAXUSERS]; static utmpidle utmp_idle[MAXUSERS]; static utmp old_utmp[MAXUSERS]; static struct utmpx utmp_list[MAXUSERS]; @@ -147,6 +148,42 @@ return(idle); } +static utmp_array * +do_names_3(void) +{ + static utmp_array ut; + struct utmpx *usr; + int nusers = 0; + + memset(&ut, 0, sizeof(ut)); + ut.utmp_array_val = &rusers_utmps[0]; + + setutxent(); + while ((usr = getutxent()) != NULL && nusers < MAXUSERS) { + if (usr->ut_type != USER_PROCESS) + continue; + + memcpy(&utmp_list[nusers], usr, sizeof(*usr)); + rusers_utmps[nusers].ut_time = usr->ut_tv.tv_sec; + rusers_utmps[nusers].ut_idle = + getidle(usr->ut_line, usr->ut_host); + rusers_utmps[nusers].ut_line = + utmp_list[nusers].ut_line; + rusers_utmps[nusers].ut_user = + utmp_list[nusers].ut_user; + rusers_utmps[nusers].ut_host = + utmp_list[nusers].ut_host; + rusers_utmps[nusers].ut_type = + utmp_list[nusers].ut_type; + + nusers++; + } + endutxent(); + + ut.utmp_array_len = nusers; + return(&ut); +} + static utmpidlearr * do_names_2(void) { @@ -220,6 +257,18 @@ return(&ut); } +utmp_array * +rusersproc_names_3_svc(void *argp __unused, struct svc_req *rqstp __unused) +{ + return (do_names_3()); +} + +utmp_array * +rusersproc_allnames_3_svc(void *argp __unused, struct svc_req *rqstp __unused) +{ + return (do_names_3()); +} + utmpidlearr * rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) { @@ -281,6 +330,10 @@ case RUSERSVERS_IDLE: local = (rusersproc_t)rusersproc_names_2_svc; break; + case RUSERSVERS_3: + local = (rusersproc_t)rusersproc_names_3_svc; + xdr_result = (xdrproc_t)xdr_utmp_array; + break; default: svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); goto leave; @@ -298,6 +351,9 @@ case RUSERSVERS_IDLE: local = (rusersproc_t)rusersproc_allnames_2_svc; break; + case RUSERSVERS_3: + local = (rusersproc_t)rusersproc_allnames_3_svc; + break; default: svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); goto leave; diff --git a/libexec/rpc.rusersd/rusersd.c b/libexec/rpc.rusersd/rusersd.c --- a/libexec/rpc.rusersd/rusersd.c +++ b/libexec/rpc.rusersd/rusersd.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "extern.h" @@ -43,6 +44,7 @@ static void cleanup(int sig __unused) { + (void) rpcb_unset(RUSERSPROG, RUSERSVERS_3, NULL); (void) rpcb_unset(RUSERSPROG, RUSERSVERS_IDLE, NULL); (void) rpcb_unset(RUSERSPROG, RUSERSVERS_ORIG, NULL); exit(0); @@ -52,9 +54,10 @@ main(int argc __unused, char *argv[] __unused) { SVCXPRT *transp = NULL; /* Keep compiler happy. */ - int ok; + struct netconfig *nconf; struct sockaddr_storage from; socklen_t fromlen; + void* handle; /* * See if inetd started us @@ -67,6 +70,7 @@ if (!from_inetd) { daemon(0, 0); + (void) rpcb_unset(RUSERSPROG, RUSERSVERS_3, NULL); (void) rpcb_unset(RUSERSPROG, RUSERSVERS_IDLE, NULL); (void) rpcb_unset(RUSERSPROG, RUSERSVERS_ORIG, NULL); @@ -78,29 +82,45 @@ openlog("rpc.rusersd", LOG_CONS|LOG_PID, LOG_DAEMON); if (from_inetd) { - transp = svc_tli_create(0, NULL, NULL, 0, 0); - if (transp == NULL) { - syslog(LOG_ERR, "cannot create udp service."); + if ((handle = setnetconfig()) == NULL) { + syslog(LOG_ERR, "setnetconfig failed."); + exit(1); + } + + while ((nconf = getnetconfig(handle)) != NULL) { + transp = svc_tli_create(0, nconf, NULL, 0, 0); + if (transp == NULL) { + syslog(LOG_ERR, "cannot create %s service.", nconf->nc_proto); + exit(1); + } + + if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service, NULL)) { + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_3, (inetd)"); + exit(1); + } + if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE, rusers_service, NULL)) { + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_IDLE, (inetd)"); + exit(1); + } + if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_ORIG, rusers_service, NULL)) { + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_ORIG, (inetd)"); + exit(1); + } + } + freenetconfigent(nconf); + } else { + if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")){ + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_3, netpath"); + exit(1); + } + if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE, "netpath")){ + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_IDLE, netpath"); + exit(1); + } + if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_ORIG, "netpath")){ + syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_ORIG, netpath"); exit(1); } - ok = svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE, - rusers_service, NULL); - } else - ok = svc_create(rusers_service, - RUSERSPROG, RUSERSVERS_IDLE, "udp"); - if (!ok) { - syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_IDLE, %s)", (!from_inetd)?"udp":"(inetd)"); - exit(1); - } - if (from_inetd) - ok = svc_reg(transp, RUSERSPROG, RUSERSVERS_ORIG, - rusers_service, NULL); - else - ok = svc_create(rusers_service, - RUSERSPROG, RUSERSVERS_ORIG, "udp"); - if (!ok) { - syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_ORIG, %s)", (!from_inetd)?"udp":"(inetd)"); - exit(1); } svc_run(); diff --git a/usr.bin/rusers/rusers.c b/usr.bin/rusers/rusers.c --- a/usr.bin/rusers/rusers.c +++ b/usr.bin/rusers/rusers.c @@ -60,11 +60,11 @@ static struct host_list { struct host_list *next; - struct in_addr addr; + struct netbuf addr; } *hosts; static int -search_host(struct in_addr addr) +search_host(struct netbuf addr) { struct host_list *hp; @@ -72,49 +72,153 @@ return (0); for (hp = hosts; hp != NULL; hp = hp->next) { - if (hp->addr.s_addr == addr.s_addr) + if (hp->addr.len == addr.len && + memcmp(hp->addr.buf, addr.buf, addr.len) == 0) return (1); } return (0); } static void -remember_host(struct in_addr addr) +remember_host(struct netbuf addr) { struct host_list *hp; if ((hp = (struct host_list *)malloc(sizeof(struct host_list))) == NULL) errx(1, "no memory"); - hp->addr.s_addr = addr.s_addr; + hp->addr.len = addr.len; + hp->addr.maxlen = addr.maxlen; + if ((hp->addr.buf = malloc(addr.maxlen)) == NULL) + errx(1, "no memory"); + memcpy(hp->addr.buf, addr.buf, addr.len); hp->next = hosts; hosts = hp; } static int -rusers_reply(void *replyp, struct sockaddr_in *raddrp) +rusers_reply_3(void *replyp, struct netbuf *raddrp, struct netconfig *_unused) { + struct sockaddr *sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; unsigned int x; int idle; char date[32], idle_time[64], remote[64]; - struct hostent *hp; - utmpidlearr *up, u; - char *host; + utmp_array *up; + char *host, host_buf[NI_MAXHOST]; int days, hours, minutes, seconds; - up = &u; - memcpy(up, replyp, sizeof(*up)); - if (search_host(raddrp->sin_addr)) + (void)_unused; + up = (utmp_array *)replyp; + if (search_host(*raddrp)) return (0); - if (!allopt && up->utmpidlearr_len == 0) + if (!allopt && up->utmp_array_len == 0) return (0); - hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, - sizeof(struct in_addr), AF_INET); - if (hp != NULL) - host = hp->h_name; - else - host = inet_ntoa(raddrp->sin_addr); + sa = (struct sockaddr *)raddrp->buf; + if (getnameinfo(sa, raddrp->len, host_buf, sizeof(host_buf), + NULL, 0, NI_NAMEREQD) == 0) { + host = host_buf; + } + else if (sa->sa_family == AF_INET) { + memcpy(&sin, sa, sa->sa_len); + inet_ntop(AF_INET, &sin.sin_addr, host_buf, sizeof(host_buf)); + } + else { + memcpy(&sin6, sa, sa->sa_len); + inet_ntop(AF_INET6, &sin6.sin6_addr, host_buf, sizeof(host_buf)); + } + host = host_buf; + + if (!longopt) + printf("%-*s ", HOST_WIDTH, host); + + for (x = 0; x < up->utmp_array_len; x++) { + time_t t = _int_to_time(up->utmp_array_val[x].ut_time); + strncpy(date, &(ctime(&t)[4]), sizeof(date) - 1); + + idle = up->utmp_array_val[x].ut_idle; + sprintf(idle_time, " :%02d", idle); + if (idle == MAX_INT) + strcpy(idle_time, "??"); + else if (idle == 0) + strcpy(idle_time, ""); + else { + seconds = idle; + days = seconds / (60 * 60 * 24); + seconds %= (60 * 60 * 24); + hours = seconds / (60 * 60); + seconds %= (60 * 60); + minutes = seconds / 60; + seconds %= 60; + if (idle > 60) + sprintf(idle_time, "%d:%02d", minutes, seconds); + if (idle >= (60 * 60)) + sprintf(idle_time, "%d:%02d:%02d", + hours, minutes, seconds); + if (idle >= (24 * 60 * 60)) + sprintf(idle_time, "%d days, %d:%02d:%02d", + days, hours, minutes, seconds); + } + + strncpy(remote, up->utmp_array_val[x].ut_host, + sizeof(remote) - 1); + if (strlen(remote) != 0) + sprintf(remote, "(%.16s)", + up->utmp_array_val[x].ut_host); + + if (longopt) + printf("%-8.8s %*s:%-*.*s %-12.12s %6s %.18s\n", + up->utmp_array_val[x].ut_user, + HOST_WIDTH, host, LINE_WIDTH, LINE_WIDTH, + up->utmp_array_val[x].ut_line, date, + idle_time, remote ); + else + printf("%s ", + up->utmp_array_val[x].ut_user); + } + if (!longopt) + putchar('\n'); + + remember_host(*raddrp); + return (0); +} + +static int +rusers_reply(void *replyp, struct netbuf *raddrp, struct netconfig *_unused) +{ + struct sockaddr *sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + unsigned int x; + int idle; + char date[32], idle_time[64], remote[64]; + utmpidlearr *up; + char *host, host_buf[NI_MAXHOST]; + int days, hours, minutes, seconds; + + (void)_unused; + up = (utmpidlearr *)replyp; + if (search_host(*raddrp)) + return (0); + + if (!allopt && up->utmpidlearr_len == 0) + return (0); + sa = (struct sockaddr *)raddrp->buf; + if (getnameinfo(sa, raddrp->len, host_buf, sizeof(host_buf), + NULL, 0, NI_NAMEREQD) == 0) { + host = host_buf; + } + else if (sa->sa_family == AF_INET) { + memcpy(&sin, sa, sa->sa_len); + inet_ntop(AF_INET, &sin.sin_addr, host_buf, sizeof(host_buf)); + } + else { + memcpy(&sin6, sa, sa->sa_len); + inet_ntop(AF_INET6, &sin6.sin6_addr, host_buf, sizeof(host_buf)); + } + host = host_buf; if (!longopt) printf("%-*s ", HOST_WIDTH, host); @@ -166,49 +270,83 @@ if (!longopt) putchar('\n'); - remember_host(raddrp->sin_addr); + remember_host(*raddrp); return (0); } static void onehost(char *host) { + utmp_array ua; utmpidlearr up; CLIENT *rusers_clnt; - struct sockaddr_in addr; - struct hostent *hp; + enum clnt_stat err; + struct netbuf addr; + struct addrinfo *res; struct timeval tv; - hp = gethostbyname(host); - if (hp == NULL) + if (getaddrinfo(host, NULL, &(struct addrinfo) { + .ai_family = AF_UNSPEC + }, &res) != 0){ errx(1, "unknown host \"%s\"", host); + } + addr.len = addr.maxlen = res->ai_addrlen; + addr.buf = malloc(addr.len); + if (addr.buf == NULL) + errx(1, "no memory"); + memcpy(addr.buf, res->ai_addr, addr.len); - rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); + rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_3, "netpath"); if (rusers_clnt == NULL) errx(1, "%s", clnt_spcreateerror("")); - - memset(&up, 0, sizeof(up)); + memset(&ua, 0, sizeof(ua)); tv.tv_sec = 15; /* XXX ?? */ tv.tv_usec = 0; - if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, - (xdrproc_t)xdr_utmpidlearr, &up, tv) != RPC_SUCCESS) + err = clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_utmp_array, &ua, tv); + if (err == RPC_PROGVERSMISMATCH) { + clnt_destroy(rusers_clnt); + memset(&up, 0, sizeof(up)); + rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "netpath"); + if (rusers_clnt == NULL) + errx(1, "%s", clnt_spcreateerror("")); + err = clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_utmpidlearr, &up, tv); + if (err != RPC_SUCCESS) + errx(1, "%s", clnt_sperror(rusers_clnt, "")); + rusers_reply(&up, &addr, NULL); + } + else if (err != RPC_SUCCESS) { errx(1, "%s", clnt_sperror(rusers_clnt, "")); - memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(addr.sin_addr.s_addr)); - rusers_reply(&up, &addr); + } + else { + rusers_reply_3(&ua, &addr, NULL); + } + + free(addr.buf); clnt_destroy(rusers_clnt); + freeaddrinfo(res); } static void allhosts(void) { utmpidlearr up; + utmp_array utmp_array_res; enum clnt_stat clnt_stat; memset(&up, 0, sizeof(up)); - clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, + memset(&utmp_array_res, 0, sizeof(utmp_array_res)); + clnt_stat = rpc_broadcast(RUSERSPROG, RUSERSVERS_3, + RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_utmp_array, (char *)&utmp_array_res, + (resultproc_t)rusers_reply_3, "netpath"); + if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) + errx(1, "%s", clnt_sperrno(clnt_stat)); + clnt_stat = rpc_broadcast(RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_utmpidlearr, (char *)&up, - (resultproc_t)rusers_reply); + (resultproc_t)rusers_reply, "netpath"); if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) errx(1, "%s", clnt_sperrno(clnt_stat)); }