version 1.15, 2001/11/02 17:16:22 |
version 1.16, 2001/11/06 02:22:25 |
|
|
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <rpc/rpc.h> |
#include <rpc/rpc.h> |
#include <rpc/pmap_clnt.h> |
#include <rpc/pmap_prot.h> |
#include <arpa/inet.h> |
#include <rpc/pmap_rmt.h> |
#include <rpcsvc/rusers.h> |
#include <rpcsvc/rusers.h> |
#include <rpcsvc/rnusers.h> /* Old protocol version */ |
#include <rpcsvc/rnusers.h> /* Old protocol version */ |
|
#include <arpa/inet.h> |
|
#include <net/if.h> |
#include <err.h> |
#include <err.h> |
|
#include <errno.h> |
|
#include <ifaddrs.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
void print_longline(int, u_int, char *, char *, char *, char *, int); |
void print_longline(int, u_int, char *, char *, char *, char *, int); |
void onehost(char *); |
void onehost(char *); |
void allhosts(void); |
void allhosts(void); |
|
void alarmclock(int); |
bool_t rusers_reply(char *, struct sockaddr_in *); |
bool_t rusers_reply(char *, struct sockaddr_in *); |
bool_t rusers_reply_3(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); |
__dead void usage(void); |
|
|
int longopt; |
int longopt; |
|
|
struct in_addr addr; |
struct in_addr addr; |
} *hosts; |
} *hosts; |
|
|
|
#define MAX_BROADCAST_SIZE 1400 |
|
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
|
|
|
|
if (!allopt && !up3->utmp_array_len) |
if (!allopt && !up3->utmp_array_len) |
return(0); |
return(0); |
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
sizeof(struct in_addr), AF_INET); |
sizeof(struct in_addr), AF_INET); |
if (hp) { |
if (hp) { |
|
|
utmpidlearr up; |
utmpidlearr up; |
utmp_array up3; |
utmp_array up3; |
CLIENT *rusers_clnt; |
CLIENT *rusers_clnt; |
struct sockaddr_in addr; |
struct sockaddr_in sin; |
struct hostent *hp; |
struct hostent *hp; |
struct timeval tv = { 25, 0 }; |
struct timeval tv = { 25, 0 }; |
int error; |
int error; |
|
|
xdr_utmp_array, &up3, tv); |
xdr_utmp_array, &up3, tv); |
switch (error) { |
switch (error) { |
case RPC_SUCCESS: |
case RPC_SUCCESS: |
addr.sin_addr.s_addr = *(int *)hp->h_addr; |
sin.sin_addr.s_addr = *(int *)hp->h_addr; |
rusers_reply_3((char *)&up3, &addr); |
rusers_reply_3((char *)&up3, &sin); |
clnt_destroy(rusers_clnt); |
clnt_destroy(rusers_clnt); |
return; |
return; |
case RPC_PROGVERSMISMATCH: |
case RPC_PROGVERSMISMATCH: |
|
|
clnt_destroy(rusers_clnt); |
clnt_destroy(rusers_clnt); |
exit(1); |
exit(1); |
} |
} |
addr.sin_addr.s_addr = *(int *)hp->h_addr; |
sin.sin_addr.s_addr = *(int *)hp->h_addr; |
rusers_reply((char *)&up, &addr); |
rusers_reply((char *)&up, &sin); |
clnt_destroy(rusers_clnt); |
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 |
void |
allhosts(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; |
utmpidlearr up; |
utmp_array up3; |
utmp_array up3; |
enum clnt_stat clnt_stat; |
XDR xdr; |
|
|
puts("Sending broadcast for rusersd protocol version 3..."); |
if (getifaddrs(&ifap) != 0) |
memset(&up3, 0, sizeof(up3)); |
err(1, "can't get list of interface addresses"); |
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)); |
|
|
|
puts("Sending broadcast for rusersd protocol version 2..."); |
|
memset(&up, 0, sizeof(up)); |
memset(&up, 0, sizeof(up)); |
clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, |
memset(&up3, 0, sizeof(up3)); |
RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, |
memset(&baddr, 0, sizeof(baddr)); |
(char *)&up, rusers_reply); |
memset(&res, 0, sizeof(res)); |
if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) |
memset(&msg, 0, sizeof(msg)); |
errx(1, "%s", clnt_sperrno(clnt_stat)); |
|
|
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 |
void |