summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormillert <millert@openbsd.org>2001-11-06 02:22:25 +0000
committermillert <millert@openbsd.org>2001-11-06 02:22:25 +0000
commitc27ff37c90ac42edc697658ffeb94bd76b06224e (patch)
treedb46fcf56a1f441f55377980e80647fedce9c0ac
parent - include shuffling (diff)
downloadwireguard-openbsd-c27ff37c90ac42edc697658ffeb94bd76b06224e.tar.xz
wireguard-openbsd-c27ff37c90ac42edc697658ffeb94bd76b06224e.zip
Restore asyncronous RPC code now that I found the uninitialized variable
that was causing problem.
-rw-r--r--usr.bin/rusers/rusers.c267
1 files changed, 243 insertions, 24 deletions
diff --git a/usr.bin/rusers/rusers.c b/usr.bin/rusers/rusers.c
index 12378be36d6..3f0b422f9ea 100644
--- a/usr.bin/rusers/rusers.c
+++ b/usr.bin/rusers/rusers.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rusers.c,v 1.15 2001/11/02 17:16:22 millert Exp $ */
+/* $OpenBSD: rusers.c,v 1.16 2001/11/06 02:22:25 millert Exp $ */
/*
* Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -55,18 +55,22 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: rusers.c,v 1.15 2001/11/02 17:16:22 millert Exp $";
+static const char rcsid[] = "$OpenBSD: rusers.c,v 1.16 2001/11/06 02:22:25 millert Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
-#include <arpa/inet.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>
@@ -85,8 +89,11 @@ 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, in_port_t, u_long, struct rpc_msg *,
+ struct rmtcallres *, bool_t (*)());
__dead void usage(void);
int longopt;
@@ -99,6 +106,8 @@ struct host_list {
struct in_addr addr;
} *hosts;
+#define MAX_BROADCAST_SIZE 1400
+
int
main(int argc, char **argv)
{
@@ -303,7 +312,7 @@ rusers_reply_3(char *replyp, struct sockaddr_in *raddrp)
if (!allopt && !up3->utmp_array_len)
return(0);
-
+
hp = gethostbyaddr((char *)&raddrp->sin_addr,
sizeof(struct in_addr), AF_INET);
if (hp) {
@@ -348,7 +357,7 @@ onehost(char *host)
utmpidlearr up;
utmp_array up3;
CLIENT *rusers_clnt;
- struct sockaddr_in addr;
+ struct sockaddr_in sin;
struct hostent *hp;
struct timeval tv = { 25, 0 };
int error;
@@ -369,8 +378,8 @@ onehost(char *host)
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);
+ sin.sin_addr.s_addr = *(int *)hp->h_addr;
+ rusers_reply_3((char *)&up3, &sin);
clnt_destroy(rusers_clnt);
return;
case RPC_PROGVERSMISMATCH:
@@ -397,33 +406,243 @@ onehost(char *host)
clnt_destroy(rusers_clnt);
exit(1);
}
- addr.sin_addr.s_addr = *(int *)hp->h_addr;
- rusers_reply((char *)&up, &addr);
+ sin.sin_addr.s_addr = *(int *)hp->h_addr;
+ rusers_reply((char *)&up, &sin);
clnt_destroy(rusers_clnt);
}
+enum clnt_stat
+get_reply(int sock, in_port_t port, u_long xid, struct rpc_msg *msgp,
+ struct rmtcallres *resp, bool_t (*callback)())
+{
+ ssize_t inlen;
+ socklen_t 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(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 *xdr, 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(xdr, buf, MAX_BROADCAST_SIZE, XDR_ENCODE);
+ if (!xdr_callmsg(xdr, msg) || !xdr_rmtcall_args(xdr, args))
+ return(RPC_CANTENCODEARGS);
+
+ return(RPC_SUCCESS);
+}
+
void
allhosts(void)
{
+ enum clnt_stat stat;
+ struct itimerval timeout;
+ AUTH *unix_auth = authunix_create_default();
+ size_t outlen[2];
+ int sock[2] = { -1, -1 };
+ int i, maxfd, rval;
+ u_long xid[2], port[2];
+ fd_set *fds = NULL;
+ struct sockaddr_in *sin, baddr;
+ struct rmtcallargs args;
+ struct rmtcallres res[2];
+ struct rpc_msg msg[2];
+ struct ifaddrs *ifa, *ifap = NULL;
+ char buf[2][MAX_BROADCAST_SIZE];
utmpidlearr up;
utmp_array up3;
- enum clnt_stat clnt_stat;
+ XDR xdr;
- puts("Sending broadcast for rusersd protocol version 3...");
- memset(&up3, 0, sizeof(up3));
- clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_3,
- RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmp_array,
- (char *)&up3, rusers_reply_3);
- if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
- errx(1, "%s", clnt_sperrno(clnt_stat));
+ if (getifaddrs(&ifap) != 0)
+ err(1, "can't get list of interface addresses");
- puts("Sending broadcast for rusersd protocol version 2...");
memset(&up, 0, 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));
+ memset(&up3, 0, sizeof(up3));
+ memset(&baddr, 0, sizeof(baddr));
+ memset(&res, 0, sizeof(res));
+ memset(&msg, 0, sizeof(msg));
+
+ args.prog = RUSERSPROG;
+ args.vers = RUSERSVERS_IDLE;
+ args.proc = RUSERSPROC_NAMES;
+ args.xdr_args = xdr_void;
+ args.args_ptr = NULL;
+
+ stat = rpc_setup(&sock[0], &xdr, &msg[0], &args, unix_auth, buf[0]);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ xid[0] = msg[0].rm_xid;
+ outlen[0] = xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+
+ args.vers = RUSERSVERS_3;
+ stat = rpc_setup(&sock[1], &xdr, &msg[1], &args, unix_auth, buf[1]);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ xid[1] = msg[1].rm_xid;
+ outlen[1] = xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+
+ maxfd = MAX(sock[0], sock[1]) + 1;
+ fds = (fd_set *)calloc(howmany(maxfd, NFDBITS), sizeof(fd_mask));
+ if (fds == NULL)
+ err(1, NULL);
+
+ 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);
+
+ res[0].port_ptr = &port[0];
+ res[0].xdr_results = xdr_utmpidlearr;
+ res[0].results_ptr = (caddr_t)&up;
+
+ res[1].port_ptr = &port[1];
+ res[1].xdr_results = xdr_utmp_array;
+ res[1].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[0], buf[0], outlen[0], 0,
+ (struct sockaddr *)&baddr,
+ sizeof(struct sockaddr)) != outlen[0])
+ err(1, "can't send broadcast packet");
+ } else {
+ if (sendto(sock[1], buf[1], outlen[1], 0,
+ (struct sockaddr *)&baddr,
+ sizeof(struct sockaddr)) != outlen[1])
+ err(1, "can't send broadcast packet");
+ }
+ }
+
+ /*
+ * 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;
+ for (;;) {
+ FD_SET(sock[0], fds);
+ FD_SET(sock[1], fds);
+ setitimer(ITIMER_REAL, &timeout, NULL);
+ rval = select(maxfd, fds, NULL, NULL, NULL);
+ setitimer(ITIMER_REAL, NULL, &timeout);
+ if (rval == -1) {
+ if (errno == EINTR)
+ break;
+ err(1, "select"); /* shouldn't happen */
+ }
+ if (FD_ISSET(sock[1], fds)) {
+ stat = get_reply(sock[1], (in_port_t)port[1],
+ xid[1], &msg[1], &res[1], rusers_reply_3);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ }
+ if (FD_ISSET(sock[0], fds)) {
+ stat = get_reply(sock[0], (in_port_t)port[0],
+ xid[0], &msg[0], &res[0], rusers_reply);
+ if (stat != RPC_SUCCESS)
+ goto cleanup;
+ }
+ }
+ }
+cleanup:
+ if (ifap != NULL)
+ freeifaddrs(ifap);
+ if (fds != NULL)
+ free(fds);
+ if (sock[0] >= 0)
+ (void)close(sock[0]);
+ if (sock[1] >= 0)
+ (void)close(sock[1]);
+ AUTH_DESTROY(unix_auth);
+ if (stat != RPC_SUCCESS) {
+ clnt_perrno(stat);
+ exit(1);
+ }
+}
+
+void
+alarmclock(int signo)
+{
+
+ ; /* just interupt */
}
void