=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/rusers/rusers.c,v retrieving revision 1.13 retrieving revision 1.14 diff -c -r1.13 -r1.14 *** src/usr.bin/rusers/rusers.c 2001/10/11 03:06:32 1.13 --- src/usr.bin/rusers/rusers.c 2001/11/01 23:37:42 1.14 *************** *** 1,9 **** ! /* $OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $ */ /*- * 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: --- 1,35 ---- ! /* $OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $ */ + /* + * Copyright (c) 2001 Todd C. Miller + * 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,20 **** * 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 --- 40,46 ---- * 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,74 **** */ #ifndef lint ! static const char rcsid[] = "$OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $"; #endif /* not lint */ - #include #include #include - #include - #include - #include - #include #include ! #include #include #include - /* - * 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 /* Old version */ - - #define MAX_INT 0x7fffffff /* Preferred formatting */ ! #define HOST_WIDTH 20 #define LINE_WIDTH 8 #define NAME_WIDTH 8 ! struct timeval timeout = { 25, 0 }; int longopt; int allopt; struct host_list { struct host_list *next; struct in_addr addr; } *hosts; ! extern char *__progname; int search_host(struct in_addr addr) { struct host_list *hp; --- 55,159 ---- */ #ifndef lint ! static const char rcsid[] = "$OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $"; #endif /* not lint */ #include + #include #include #include ! #include ! #include ! #include ! #include /* Old protocol version */ #include + #include + #include + #include + #include + #include + #include #include + #include + #include + #include /* Preferred formatting */ ! #define HOST_WIDTH 17 #define LINE_WIDTH 8 #define NAME_WIDTH 8 ! 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; ! #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) { struct host_list *hp; *************** *** 84,111 **** } void ! remember_host(struct in_addr addr) { 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; } 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 utline[RNUSERS_MAXLINELEN + 1]; - struct hostent *hp; utmpidlearr *up = (utmpidlearr *)replyp; ! char *host, *tmp; ! int days, hours, minutes, seconds; if (search_host(raddrp->sin_addr)) return(0); --- 169,258 ---- } void ! remember_host(char **ap) { struct host_list *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) { ! char user[RNUSERS_MAXUSERLEN + 1]; char utline[RNUSERS_MAXLINELEN + 1]; utmpidlearr *up = (utmpidlearr *)replyp; ! struct hostent *hp; ! char *host, *taddrs[2]; ! int i; if (search_host(raddrp->sin_addr)) return(0); *************** *** 114,195 **** return(0); hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, ! sizeof(struct in_addr), AF_INET); ! if (hp) host = hp->h_name; ! else host = inet_ntoa(raddrp->sin_addr); 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); } ! 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); if (longopt) { ! strncpy(local, host, sizeof(local)); ! strncpy(utline, up->uia_arr[x]->ui_utmp.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); } if (!longopt) putchar('\n'); - remember_host(raddrp->sin_addr); return(0); } --- 261,354 ---- 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 < 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); + } ! 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(utline, up3->utmp_array_val[i].ut_line, sizeof(utline) - 1); utline[sizeof(utline) - 1] = '\0'; ! 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'); return(0); } *************** *** 197,219 **** onehost(char *host) { utmpidlearr up; CLIENT *rusers_clnt; struct sockaddr_in addr; struct hostent *hp; hp = gethostbyname(host); if (hp == NULL) errx(1, "unknown host \"%s\"", host); 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) { clnt_perror(rusers_clnt, __progname); clnt_destroy(rusers_clnt); exit(1); --- 356,408 ---- 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); } ! 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,274 **** clnt_destroy(rusers_clnt); } void allhosts(void) { 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)); } void ! usage(void) { ! fprintf(stderr, "Usage: %s [-la] [hosts ...]\n", __progname); ! exit(1); } ! int ! main(int argc, char *argv[]) { - 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); } --- 412,661 ---- 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; ! 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 ! alarmclock(int signo) { ! ! timerclear(&timeout.it_value); } ! void ! usage(void) { ! fprintf(stderr, "usage: %s [-la] [hosts ...]\n", __progname); ! exit(1); }