summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/rusers/rusers.15
-rw-r--r--usr.bin/rusers/rusers.c651
2 files changed, 521 insertions, 135 deletions
diff --git a/usr.bin/rusers/rusers.1 b/usr.bin/rusers/rusers.1
index 640c1cb0a5a..b5e177b05c1 100644
--- a/usr.bin/rusers/rusers.1
+++ b/usr.bin/rusers/rusers.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: rusers.1,v 1.9 2000/11/09 17:52:36 aaron Exp $
+.\" $OpenBSD: rusers.1,v 1.10 2001/11/01 23:37:42 millert Exp $
.\"
.\" Copyright (c) 1983, 1990 The Regents of the University of California.
.\" All rights reserved.
@@ -54,8 +54,7 @@ the hostname with the names of the users currently logged
on is printed on each line.
The
.Nm
-command will wait for
-one minute to catch late responders.
+command will wait for 30 seconds to catch late responders.
.Pp
The options are as follows:
.Bl -tag -width Ds
diff --git a/usr.bin/rusers/rusers.c b/usr.bin/rusers/rusers.c
index 4458cf4ca07..2d17b529564 100644
--- a/usr.bin/rusers/rusers.c
+++ b/usr.bin/rusers/rusers.c
@@ -1,9 +1,35 @@
-/* $OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $ */
+/* $OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $ */
+/*
+ * Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
/*-
* Copyright (c) 1993 John Brezak
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -14,7 +40,7 @@
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -29,44 +55,103 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $";
+static const char rcsid[] = "$OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $";
#endif /* not lint */
-#include <sys/types.h>
#include <sys/param.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <netdb.h>
-#include <err.h>
-#include <stdio.h>
-#include <string.h>
#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_rmt.h>
+#include <rpcsvc/rusers.h>
+#include <rpcsvc/rnusers.h> /* Old protocol version */
#include <arpa/inet.h>
+#include <net/if.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
-/*
- * For now we only try version 2 of the protocol. The current
- * version is 3 (rusers.h), but only Solaris and NetBSD seem
- * to support it currently.
- */
-#include <rpcsvc/rnusers.h> /* Old version */
-
-#define MAX_INT 0x7fffffff
/* Preferred formatting */
-#define HOST_WIDTH 20
+#define HOST_WIDTH 17
#define LINE_WIDTH 8
#define NAME_WIDTH 8
-struct timeval timeout = { 25, 0 };
+int search_host(struct in_addr);
+void remember_host(char **);
+void fmt_idle(int, char *, size_t);
+void print_longline(int, u_int, char *, char *, char *, char *, int);
+void onehost(char *);
+void allhosts(void);
+void alarmclock(int);
+bool_t rusers_reply(char *, struct sockaddr_in *);
+bool_t rusers_reply_3(char *, struct sockaddr_in *);
+enum clnt_stat get_reply(int, u_long, u_long, struct rpc_msg *,
+ struct rmtcallres *, bool_t (*)());
+__dead void usage(void);
+
int longopt;
int allopt;
+long termwidth;
+struct itimerval timeout;
+extern char *__progname;
struct host_list {
struct host_list *next;
struct in_addr addr;
} *hosts;
-extern char *__progname;
+#define MAX_BROADCAST_SIZE 1400
+
+int
+main(int argc, char **argv)
+{
+ struct winsize win;
+ char *cp, *ep;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "al")) != -1)
+ switch (ch) {
+ case 'a':
+ allopt++;
+ break;
+ case 'l':
+ longopt++;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (isatty(STDOUT_FILENO)) {
+ if ((cp = getenv("COLUMNS")) != NULL && *cp != '\0') {
+ termwidth = strtol(cp, &ep, 10);
+ if (*ep != '\0' || termwidth >= INT_MAX ||
+ termwidth < 0)
+ termwidth = 0;
+ }
+ if (termwidth == 0 &&
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+ win.ws_col > 0)
+ termwidth = win.ws_col;
+ else
+ termwidth = 80;
+ }
+ setlinebuf(stdout);
+ if (argc == optind)
+ allhosts();
+ else {
+ for (; optind < argc; optind++)
+ (void) onehost(argv[optind]);
+ }
+ exit(0);
+}
int
search_host(struct in_addr addr)
@@ -84,28 +169,90 @@ search_host(struct in_addr addr)
}
void
-remember_host(struct in_addr addr)
+remember_host(char **ap)
{
struct host_list *hp;
- if (!(hp = (struct host_list *)malloc(sizeof(struct host_list))))
- err(1, NULL);
- hp->addr.s_addr = addr.s_addr;
- hp->next = hosts;
- hosts = hp;
+ for (; *ap; ap++) {
+ if (!(hp = malloc(sizeof(struct host_list))))
+ err(1, NULL);
+ hp->addr.s_addr = *(in_addr_t *)*ap;
+ hp->next = hosts;
+ hosts = hp;
+ }
+}
+
+void
+fmt_idle(int idle, char *idle_time, size_t idle_time_len)
+{
+ int days, hours, minutes, seconds;
+
+ switch (idle) {
+ case 0:
+ *idle_time = '\0';
+ break;
+ case INT_MAX:
+ strlcpy(idle_time, "??", idle_time_len);
+ break;
+ default:
+ 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 >= (24*60*60))
+ snprintf(idle_time, idle_time_len,
+ "%d days, %d:%02d:%02d",
+ days, hours, minutes, seconds);
+ else if (idle >= (60*60))
+ snprintf(idle_time, idle_time_len, "%2d:%02d:%02d",
+ hours, minutes, seconds);
+ else if (idle > 60)
+ snprintf(idle_time, idle_time_len, "%2d:%02d",
+ minutes, seconds);
+ else
+ snprintf(idle_time, idle_time_len, " :%02d", idle);
+ break;
+ }
+}
+
+void
+print_longline(int ut_time, u_int idle, char *host, char *user, char *line,
+ char *remhost, int remhostmax)
+{
+ char date[32], idle_time[64];
+ char remote[RUSERS_MAXHOSTLEN + 1];
+ int len;
+
+ strftime(date, sizeof(date), "%h %d %R", localtime((time_t *)&ut_time));
+ date[sizeof(date) - 1] = '\0';
+ fmt_idle(idle, idle_time, sizeof(idle_time));
+ len = termwidth -
+ (MAX(strlen(user), NAME_WIDTH) + 1 + HOST_WIDTH + 1 + LINE_WIDTH +
+ 1 + strlen(date) + 1 + MAX(8, strlen(idle_time)) + 1 + 2);
+ if (len > 0 && *remhost != '\0')
+ snprintf(remote, sizeof(remote), "(%.*s)",
+ MIN(len, remhostmax), remhost);
+ else
+ remote[0] = '\0';
+ len = HOST_WIDTH - MIN(HOST_WIDTH, strlen(host)) +
+ LINE_WIDTH - MIN(LINE_WIDTH, strlen(line));
+ printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n",
+ NAME_WIDTH, user, HOST_WIDTH, host, LINE_WIDTH, line,
+ len, "", date, idle_time, remote);
}
int
rusers_reply(char *replyp, struct sockaddr_in *raddrp)
{
- int x, idle, i;
- char date[32], idle_time[64], remote[RNUSERS_MAXHOSTLEN + 1];
- char local[HOST_WIDTH + LINE_WIDTH + 2];
+ char user[RNUSERS_MAXUSERLEN + 1];
char utline[RNUSERS_MAXLINELEN + 1];
- struct hostent *hp;
utmpidlearr *up = (utmpidlearr *)replyp;
- char *host, *tmp;
- int days, hours, minutes, seconds;
+ struct hostent *hp;
+ char *host, *taddrs[2];
+ int i;
if (search_host(raddrp->sin_addr))
return(0);
@@ -114,82 +261,94 @@ rusers_reply(char *replyp, struct sockaddr_in *raddrp)
return(0);
hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
- sizeof(struct in_addr), AF_INET);
- if (hp)
+ sizeof(struct in_addr), AF_INET);
+ if (hp) {
host = hp->h_name;
- else
+ remember_host(hp->h_addr_list);
+ } else {
host = inet_ntoa(raddrp->sin_addr);
+ taddrs[0] = (char *)&raddrp->sin_addr;
+ taddrs[1] = NULL;
+ remember_host(taddrs);
+ }
if (!longopt)
printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host);
- for (x = 0; x < up->uia_cnt; x++) {
- strlcpy(date,
- &(ctime((time_t *)&(up->uia_arr[x]->ui_utmp.ut_time))[4]),
- sizeof(date));
- /* ctime() adds a trailing \n. Trimming it is only
- * mandatory if the output formatting changes.
- */
- if ((tmp = strchr(date, '\n')) != NULL)
- *tmp = '\0';
-
- idle = up->uia_arr[x]->ui_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, "%2d:%02d",
- minutes, seconds);
- if (idle >= (60*60))
- sprintf(idle_time, "%2d:%02d:%02d",
- hours, minutes, seconds);
- if (idle >= (24*60*60))
- sprintf(idle_time, "%d days, %d:%02d:%02d",
- days, hours, minutes, seconds);
+ for (i = 0; i < up->uia_cnt; i++) {
+ /* NOTE: strncpy() used below for non-terminated strings. */
+ strncpy(user, up->uia_arr[i]->ui_utmp.ut_name,
+ sizeof(user) - 1);
+ user[sizeof(user) - 1] = '\0';
+ if (longopt) {
+ strncpy(utline, up->uia_arr[i]->ui_utmp.ut_line,
+ sizeof(utline) - 1);
+ utline[sizeof(utline) - 1] = '\0';
+ print_longline(up->uia_arr[i]->ui_utmp.ut_time,
+ up->uia_arr[i]->ui_idle, host, user, utline,
+ up->uia_arr[i]->ui_utmp.ut_host, RNUSERS_MAXHOSTLEN);
+ } else {
+ fputs(user, stdout);
+ putchar(' ');
}
+ }
+ if (!longopt)
+ putchar('\n');
+
+ return(0);
+}
- strncpy(remote, up->uia_arr[x]->ui_utmp.ut_host,
- sizeof(remote)-1);
- remote[sizeof(remote) - 1] = '\0';
- if (strlen(remote) != 0)
- snprintf(remote, sizeof(remote), "(%.16s)",
- up->uia_arr[x]->ui_utmp.ut_host);
+int
+rusers_reply_3(char *replyp, struct sockaddr_in *raddrp)
+{
+ char user[RUSERS_MAXUSERLEN + 1];
+ char utline[RUSERS_MAXLINELEN + 1];
+ utmp_array *up3 = (utmp_array *)replyp;
+ struct hostent *hp;
+ char *host, *taddrs[2];
+ int i;
+
+ if (search_host(raddrp->sin_addr))
+ return(0);
+
+ if (!allopt && !up3->utmp_array_len)
+ return(0);
+ hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (hp) {
+ host = hp->h_name;
+ remember_host(hp->h_addr_list);
+ } else {
+ host = inet_ntoa(raddrp->sin_addr);
+ taddrs[0] = (char *)&raddrp->sin_addr;
+ taddrs[1] = NULL;
+ remember_host(taddrs);
+ }
+
+ if (!longopt)
+ printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host);
+
+ for (i = 0; i < up3->utmp_array_len; i++) {
+ /* NOTE: strncpy() used below for non-terminated strings. */
+ strncpy(user, up3->utmp_array_val[i].ut_user,
+ sizeof(user) - 1);
+ user[sizeof(user) - 1] = '\0';
if (longopt) {
- strncpy(local, host, sizeof(local));
- strncpy(utline, up->uia_arr[x]->ui_utmp.ut_line,
+ strncpy(utline, up3->utmp_array_val[i].ut_line,
sizeof(utline) - 1);
utline[sizeof(utline) - 1] = '\0';
- i = sizeof(local) - strlen(utline) - 2;
- if (i < 0)
- i = 0;
- local[i] = '\0';
- strcat(local, ":");
- strlcat(local, utline, sizeof(local));
-
- printf("%-*.*s %-*.*s %-12.12s %8s %.18s\n",
- NAME_WIDTH, RNUSERS_MAXUSERLEN,
- up->uia_arr[x]->ui_utmp.ut_name,
- HOST_WIDTH+LINE_WIDTH+1, HOST_WIDTH+LINE_WIDTH+1,
- local, date, idle_time, remote);
- } else
- printf("%.*s ", RNUSERS_MAXUSERLEN,
- up->uia_arr[x]->ui_utmp.ut_name);
+ print_longline(up3->utmp_array_val[i].ut_time,
+ up3->utmp_array_val[i].ut_idle, host, user, utline,
+ up3->utmp_array_val[i].ut_host, RUSERS_MAXHOSTLEN);
+ } else {
+ fputs(user, stdout);
+ putchar(' ');
+ }
}
if (!longopt)
putchar('\n');
- remember_host(raddrp->sin_addr);
return(0);
}
@@ -197,23 +356,53 @@ void
onehost(char *host)
{
utmpidlearr up;
+ utmp_array up3;
CLIENT *rusers_clnt;
struct sockaddr_in addr;
struct hostent *hp;
+ struct timeval tv = { 25, 0 };
+ int error;
hp = gethostbyname(host);
if (hp == NULL)
errx(1, "unknown host \"%s\"", host);
+ /* try version 3 first */
+ rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_3, "udp");
+ if (rusers_clnt == NULL) {
+ clnt_pcreateerror(__progname);
+ exit(1);
+ }
+
+ memset(&up3, 0, sizeof(up3));
+ error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,
+ xdr_utmp_array, &up3, tv);
+ switch (error) {
+ case RPC_SUCCESS:
+ addr.sin_addr.s_addr = *(int *)hp->h_addr;
+ rusers_reply_3((char *)&up3, &addr);
+ clnt_destroy(rusers_clnt);
+ return;
+ case RPC_PROGVERSMISMATCH:
+ clnt_destroy(rusers_clnt);
+ break;
+ default:
+ clnt_perror(rusers_clnt, __progname);
+ clnt_destroy(rusers_clnt);
+ exit(1);
+ }
+
+ /* fall back to version 2 */
rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
if (rusers_clnt == NULL) {
clnt_pcreateerror(__progname);
exit(1);
}
- bzero((char *)&up, sizeof(up));
- if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,
- xdr_utmpidlearr, &up, timeout) != RPC_SUCCESS) {
+ memset(&up, 0, sizeof(up));
+ error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,
+ xdr_utmpidlearr, &up, tv);
+ if (error != RPC_SUCCESS) {
clnt_perror(rusers_clnt, __progname);
clnt_destroy(rusers_clnt);
exit(1);
@@ -223,52 +412,250 @@ onehost(char *host)
clnt_destroy(rusers_clnt);
}
+enum clnt_stat
+get_reply(int sock, u_long port, u_long xid, struct rpc_msg *msgp,
+ struct rmtcallres *resp, bool_t (*callback)())
+{
+ int inlen, fromlen;
+ struct sockaddr_in raddr;
+ char inbuf[UDPMSGSIZE];
+ XDR xdr;
+
+retry:
+ msgp->acpted_rply.ar_verf = _null_auth;
+ msgp->acpted_rply.ar_results.where = (caddr_t)resp;
+ msgp->acpted_rply.ar_results.proc = xdr_rmtcallres;
+
+ fromlen = sizeof(struct sockaddr);
+ inlen = recvfrom(sock, inbuf, sizeof(inbuf), 0,
+ (struct sockaddr *)&raddr, &fromlen);
+ if (inlen < 0) {
+ if (errno == EINTR)
+ goto retry;
+ return (RPC_CANTRECV);
+ }
+ if (inlen < sizeof(u_int32_t))
+ goto retry;
+
+ /*
+ * If the reply we got matches our request, decode the
+ * replay and pass it to the callback function.
+ */
+ xdrmem_create(&xdr, inbuf, (u_int)inlen, XDR_DECODE);
+ if (xdr_replymsg(&xdr, msgp)) {
+ if ((msgp->rm_xid == xid) &&
+ (msgp->rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (msgp->acpted_rply.ar_stat == SUCCESS)) {
+ raddr.sin_port = htons((u_short)port);
+ (void)(*callback)(resp->results_ptr, &raddr);
+ }
+ }
+ xdr.x_op = XDR_FREE;
+ msgp->acpted_rply.ar_results.proc = xdr_void;
+ (void)xdr_replymsg(&xdr, msgp);
+ (void)(*resp->xdr_results)(&xdr, resp->results_ptr);
+ xdr_destroy(&xdr);
+
+ return(RPC_SUCCESS);
+}
+
+enum clnt_stat
+rpc_setup(int *fdp, XDR *xdrs, struct rpc_msg *msg, struct rmtcallargs *args,
+ AUTH *unix_auth, char *buf)
+{
+ int on = 1;
+
+ if ((*fdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ return(RPC_CANTSEND);
+
+ if (setsockopt(*fdp, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
+ return(RPC_CANTSEND);
+
+ msg->rm_xid = arc4random();
+ msg->rm_direction = CALL;
+ msg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg->rm_call.cb_prog = PMAPPROG;
+ msg->rm_call.cb_vers = PMAPVERS;
+ msg->rm_call.cb_proc = PMAPPROC_CALLIT;
+ msg->rm_call.cb_cred = unix_auth->ah_cred;
+ msg->rm_call.cb_verf = unix_auth->ah_verf;
+
+ xdrmem_create(xdrs, buf, MAX_BROADCAST_SIZE, XDR_ENCODE);
+ if (!xdr_callmsg(xdrs, msg) || !xdr_rmtcall_args(xdrs, args))
+ return(RPC_CANTENCODEARGS);
+
+ return(RPC_SUCCESS);
+}
+
void
allhosts(void)
{
+ enum clnt_stat stat;
+ AUTH *unix_auth = authunix_create_default();
+ int outlen, outlen3;
+ int sock = -1;
+ int sock3 = -1;
+ int i, maxfd, rval;
+ u_long xid, xid3;
+ u_long port, port3;
+ fd_set *fds = NULL;
+ struct sockaddr_in *sin, baddr;
+ struct rmtcallargs args;
+ struct rmtcallres res, res3;
+ struct rpc_msg msg, msg3;
+ struct ifaddrs *ifa, *ifap = NULL;
+ char buf[MAX_BROADCAST_SIZE], buf3[MAX_BROADCAST_SIZE];
utmpidlearr up;
- enum clnt_stat clnt_stat;
-
- bzero((char *)&up, sizeof(up));
- clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE,
- RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr,
- (char *)&up, rusers_reply);
- if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
- errx(1, "%s", clnt_sperrno(clnt_stat));
+ utmp_array up3;
+ XDR xdr;
+
+ if (getifaddrs(&ifap) != 0) {
+ perror("Cannot get list of interface addresses");
+ stat = RPC_CANTSEND;
+ goto cleanup;
+ }
+
+ args.prog = RUSERSPROG;
+ args.vers = RUSERSVERS_IDLE;
+ args.proc = RUSERSPROC_NAMES;
+ args.xdr_args = xdr_void;
+ args.args_ptr = NULL;
+
+ stat = rpc_setup(&sock, &xdr, &msg, &args, unix_auth, buf);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ xid = msg.rm_xid;
+ outlen = (int)xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+
+ args.vers = RUSERSVERS_3;
+ stat = rpc_setup(&sock3, &xdr, &msg3, &args, unix_auth, buf3);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ xid3 = msg3.rm_xid;
+ outlen3 = (int)xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+
+ maxfd = sock3 + 1;
+ fds = (fd_set *)calloc(howmany(maxfd, NFDBITS), sizeof(fd_mask));
+ if (fds == NULL) {
+ stat = RPC_CANTSEND;
+ goto cleanup;
+ }
+
+ memset(&baddr, 0, sizeof(baddr));
+ baddr.sin_len = sizeof(struct sockaddr_in);
+ baddr.sin_family = AF_INET;
+ baddr.sin_port = htons(PMAPPORT);
+ baddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ memset(&res, 0, sizeof(res));
+ res.port_ptr = &port;
+ res.xdr_results = xdr_utmpidlearr;
+ res.results_ptr = (caddr_t)&up;
+
+ memset(&res3, 0, sizeof(res3));
+ res3.port_ptr = &port3;
+ res3.xdr_results = xdr_utmp_array;
+ res3.results_ptr = (caddr_t)&up3;
+
+ (void)signal(SIGALRM, alarmclock);
+
+ /*
+ * We do 6 runs through the loop. On even runs we send
+ * a version 3 broadcast. On odd ones we send a version 2
+ * broadcast. This should give version 3 replies enough
+ * of an 'edge' over the old version 2 ones in most cases.
+ * We select() waiting for replies for 5 seconds in between
+ * each broadcast.
+ */
+ for (i = 0; i < 6; i++) {
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET ||
+ !(ifa->ifa_flags & IFF_BROADCAST) ||
+ !(ifa->ifa_flags & IFF_UP) ||
+ ifa->ifa_broadaddr == NULL ||
+ ifa->ifa_broadaddr->sa_family != AF_INET)
+ continue;
+ sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+ baddr.sin_addr = sin->sin_addr;
+
+ /* use protocol 2 or 3 depending on i (odd or even) */
+ if (i & 1) {
+ if (sendto(sock, buf, outlen, 0,
+ (struct sockaddr *)&baddr,
+ sizeof(struct sockaddr)) != outlen) {
+ warn("unable to send broadcast packet");
+ stat = RPC_CANTSEND;
+ goto cleanup;
+ }
+ } else {
+ if (sendto(sock3, buf3, outlen3, 0,
+ (struct sockaddr *)&baddr,
+ sizeof(struct sockaddr)) != outlen3) {
+ warn("unable to send broadcast packet");
+ stat = RPC_CANTSEND;
+ goto cleanup;
+ }
+ }
+ }
+
+ /*
+ * We stay in the select loop for ~5 seconds
+ */
+ timerclear(&timeout.it_value);
+ timeout.it_value.tv_sec = 5;
+ timeout.it_value.tv_usec = 0;
+ while (timerisset(&timeout.it_value)) {
+ FD_SET(sock, fds);
+ FD_SET(sock3, fds);
+ setitimer(ITIMER_REAL, &timeout, NULL);
+ rval = select(maxfd, fds, NULL, NULL, NULL);
+ setitimer(ITIMER_REAL, NULL, &timeout);
+ if (rval == -1) {
+ if (!timerisset(&timeout.it_value))
+ break;
+ warn("select"); /* shouldn't happen */
+ stat = RPC_CANTRECV;
+ goto cleanup;
+ }
+ if (FD_ISSET(sock3, fds)) {
+ stat = get_reply(sock3, port3, xid3, &msg3,
+ &res3, rusers_reply_3);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ }
+ if (FD_ISSET(sock, fds)) {
+ stat = get_reply(sock, port, xid, &msg,
+ &res, rusers_reply);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ }
+ }
+ }
+cleanup:
+ if (ifap != NULL)
+ freeifaddrs(ifap);
+ if (fds != NULL)
+ free(fds);
+ if (sock >= 0)
+ (void)close(sock);
+ if (sock3 >= 0)
+ (void)close(sock3);
+ AUTH_DESTROY(unix_auth);
}
void
-usage(void)
+alarmclock(int signo)
{
- fprintf(stderr, "Usage: %s [-la] [hosts ...]\n", __progname);
- exit(1);
+
+ timerclear(&timeout.it_value);
}
-int
-main(int argc, char *argv[])
+void
+usage(void)
{
- int ch;
- extern int optind;
-
- while ((ch = getopt(argc, argv, "al")) != -1)
- switch (ch) {
- case 'a':
- allopt++;
- break;
- case 'l':
- longopt++;
- break;
- default:
- usage();
- /*NOTREACHED*/
- }
- setlinebuf(stdout);
- if (argc == optind)
- allhosts();
- else {
- for (; optind < argc; optind++)
- (void) onehost(argv[optind]);
- }
- exit(0);
+ fprintf(stderr, "usage: %s [-la] [hosts ...]\n", __progname);
+ exit(1);
}