version 1.14, 2001/11/01 23:37:42 |
version 1.15, 2001/11/02 17:16:22 |
|
|
#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_prot.h> |
#include <rpc/pmap_clnt.h> |
#include <rpc/pmap_rmt.h> |
#include <arpa/inet.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, u_long, u_long, struct rpc_msg *, |
|
struct rmtcallres *, bool_t (*)()); |
|
__dead void usage(void); |
__dead void usage(void); |
|
|
int longopt; |
int longopt; |
int allopt; |
int allopt; |
long termwidth; |
long termwidth; |
struct itimerval timeout; |
|
extern char *__progname; |
extern char *__progname; |
|
|
struct host_list { |
struct host_list { |
|
|
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) |
{ |
{ |
|
|
len, "", date, idle_time, remote); |
len, "", date, idle_time, remote); |
} |
} |
|
|
int |
bool_t |
rusers_reply(char *replyp, struct sockaddr_in *raddrp) |
rusers_reply(char *replyp, struct sockaddr_in *raddrp) |
{ |
{ |
char user[RNUSERS_MAXUSERLEN + 1]; |
char user[RNUSERS_MAXUSERLEN + 1]; |
|
|
if (!allopt && !up->uia_cnt) |
if (!allopt && !up->uia_cnt) |
return(0); |
return(0); |
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, |
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
sizeof(struct in_addr), AF_INET); |
sizeof(struct in_addr), AF_INET); |
if (hp) { |
if (hp) { |
host = hp->h_name; |
host = hp->h_name; |
|
|
return(0); |
return(0); |
} |
} |
|
|
int |
bool_t |
rusers_reply_3(char *replyp, struct sockaddr_in *raddrp) |
rusers_reply_3(char *replyp, struct sockaddr_in *raddrp) |
{ |
{ |
char user[RUSERS_MAXUSERLEN + 1]; |
char user[RUSERS_MAXUSERLEN + 1]; |
|
|
|
|
if (!allopt && !up3->utmp_array_len) |
if (!allopt && !up3->utmp_array_len) |
return(0); |
return(0); |
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, |
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
sizeof(struct in_addr), AF_INET); |
sizeof(struct in_addr), AF_INET); |
if (hp) { |
if (hp) { |
host = hp->h_name; |
host = hp->h_name; |
|
|
clnt_destroy(rusers_clnt); |
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 |
void |
allhosts(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; |
utmpidlearr up; |
utmp_array up3; |
utmp_array up3; |
XDR xdr; |
enum clnt_stat clnt_stat; |
|
|
if (getifaddrs(&ifap) != 0) { |
puts("Sending broadcast for rusersd protocol version 3..."); |
perror("Cannot get list of interface addresses"); |
memset(&up3, 0, sizeof(up3)); |
stat = RPC_CANTSEND; |
clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_3, |
goto cleanup; |
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)); |
|
|
args.prog = RUSERSPROG; |
puts("Sending broadcast for rusersd protocol version 2..."); |
args.vers = RUSERSVERS_IDLE; |
memset(&up, 0, sizeof(up)); |
args.proc = RUSERSPROC_NAMES; |
clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, |
args.xdr_args = xdr_void; |
RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, |
args.args_ptr = NULL; |
(char *)&up, rusers_reply); |
|
if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) |
stat = rpc_setup(&sock, &xdr, &msg, &args, unix_auth, buf); |
errx(1, "%s", clnt_sperrno(clnt_stat)); |
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 |
|
alarmclock(int signo) |
|
{ |
|
|
|
timerclear(&timeout.it_value); |
|
} |
} |
|
|
void |
void |