diff options
author | 2001-11-06 02:22:25 +0000 | |
---|---|---|
committer | 2001-11-06 02:22:25 +0000 | |
commit | c27ff37c90ac42edc697658ffeb94bd76b06224e (patch) | |
tree | db46fcf56a1f441f55377980e80647fedce9c0ac | |
parent | - include shuffling (diff) | |
download | wireguard-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.c | 267 |
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 |