1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1993, John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 43 #include <rpc/rpc.h> 44 #include <rpc/pmap_clnt.h> 45 #include <rpcsvc/rnusers.h> 46 47 #include <arpa/inet.h> 48 49 #include <err.h> 50 #include <netdb.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <timeconv.h> 55 #include <unistd.h> 56 57 #define MAX_INT 0x7fffffff 58 #define HOST_WIDTH 20 59 #define LINE_WIDTH 15 60 61 static int longopt; 62 static int allopt; 63 64 static struct host_list { 65 struct host_list *next; 66 struct in_addr addr; 67 } *hosts; 68 69 static int 70 search_host(struct in_addr addr) 71 { 72 struct host_list *hp; 73 74 if (hosts == NULL) 75 return (0); 76 77 for (hp = hosts; hp != NULL; hp = hp->next) { 78 if (hp->addr.s_addr == addr.s_addr) 79 return (1); 80 } 81 return (0); 82 } 83 84 static void 85 remember_host(struct in_addr addr) 86 { 87 struct host_list *hp; 88 89 if ((hp = (struct host_list *)malloc(sizeof(struct host_list))) == NULL) 90 errx(1, "no memory"); 91 hp->addr.s_addr = addr.s_addr; 92 hp->next = hosts; 93 hosts = hp; 94 } 95 96 static int 97 rusers_reply(void *replyp, struct sockaddr_in *raddrp) 98 { 99 unsigned int x; 100 int idle; 101 char date[32], idle_time[64], remote[64]; 102 struct hostent *hp; 103 utmpidlearr *up, u; 104 char *host; 105 int days, hours, minutes, seconds; 106 107 up = &u; 108 memcpy(up, replyp, sizeof(*up)); 109 if (search_host(raddrp->sin_addr)) 110 return (0); 111 112 if (!allopt && up->utmpidlearr_len == 0) 113 return (0); 114 115 hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, 116 sizeof(struct in_addr), AF_INET); 117 if (hp != NULL) 118 host = hp->h_name; 119 else 120 host = inet_ntoa(raddrp->sin_addr); 121 122 if (!longopt) 123 printf("%-*s ", HOST_WIDTH, host); 124 125 for (x = 0; x < up->utmpidlearr_len; x++) { 126 time_t t = _int_to_time(up->utmpidlearr_val[x].ui_utmp.ut_time); 127 strncpy(date, &(ctime(&t)[4]), sizeof(date) - 1); 128 129 idle = up->utmpidlearr_val[x].ui_idle; 130 sprintf(idle_time, " :%02d", idle); 131 if (idle == MAX_INT) 132 strcpy(idle_time, "??"); 133 else if (idle == 0) 134 strcpy(idle_time, ""); 135 else { 136 seconds = idle; 137 days = seconds / (60 * 60 * 24); 138 seconds %= (60 * 60 * 24); 139 hours = seconds / (60 * 60); 140 seconds %= (60 * 60); 141 minutes = seconds / 60; 142 seconds %= 60; 143 if (idle > 60) 144 sprintf(idle_time, "%d:%02d", minutes, seconds); 145 if (idle >= (60 * 60)) 146 sprintf(idle_time, "%d:%02d:%02d", 147 hours, minutes, seconds); 148 if (idle >= (24 * 60 * 60)) 149 sprintf(idle_time, "%d days, %d:%02d:%02d", 150 days, hours, minutes, seconds); 151 } 152 153 strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, 154 sizeof(remote) - 1); 155 if (strlen(remote) != 0) 156 sprintf(remote, "(%.16s)", 157 up->utmpidlearr_val[x].ui_utmp.ut_host); 158 159 if (longopt) 160 printf("%-8.8s %*s:%-*.*s %-12.12s %6s %.18s\n", 161 up->utmpidlearr_val[x].ui_utmp.ut_name, 162 HOST_WIDTH, host, LINE_WIDTH, LINE_WIDTH, 163 up->utmpidlearr_val[x].ui_utmp.ut_line, date, 164 idle_time, remote ); 165 else 166 printf("%s ", 167 up->utmpidlearr_val[x].ui_utmp.ut_name); 168 } 169 if (!longopt) 170 putchar('\n'); 171 172 remember_host(raddrp->sin_addr); 173 return (0); 174 } 175 176 static void 177 onehost(char *host) 178 { 179 utmpidlearr up; 180 CLIENT *rusers_clnt; 181 struct sockaddr_in addr; 182 struct hostent *hp; 183 struct timeval tv; 184 185 hp = gethostbyname(host); 186 if (hp == NULL) 187 errx(1, "unknown host \"%s\"", host); 188 189 rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); 190 if (rusers_clnt == NULL) 191 errx(1, "%s", clnt_spcreateerror("")); 192 193 memset(&up, 0, sizeof(up)); 194 tv.tv_sec = 15; /* XXX ?? */ 195 tv.tv_usec = 0; 196 if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, 197 (xdrproc_t)xdr_utmpidlearr, &up, tv) != RPC_SUCCESS) 198 errx(1, "%s", clnt_sperror(rusers_clnt, "")); 199 memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(addr.sin_addr.s_addr)); 200 rusers_reply(&up, &addr); 201 clnt_destroy(rusers_clnt); 202 } 203 204 static void 205 allhosts(void) 206 { 207 utmpidlearr up; 208 enum clnt_stat clnt_stat; 209 210 memset(&up, 0, sizeof(up)); 211 clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, 212 RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, 213 (xdrproc_t)xdr_utmpidlearr, (char *)&up, 214 (resultproc_t)rusers_reply); 215 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) 216 errx(1, "%s", clnt_sperrno(clnt_stat)); 217 } 218 219 static void 220 usage(void) 221 { 222 223 fprintf(stderr, "usage: rusers [-al] [host ...]\n"); 224 exit(1); 225 } 226 227 int 228 main(int argc, char *argv[]) 229 { 230 int ch; 231 232 while ((ch = getopt(argc, argv, "al")) != -1) 233 switch (ch) { 234 case 'a': 235 allopt++; 236 break; 237 case 'l': 238 longopt++; 239 break; 240 default: 241 usage(); 242 /* NOTREACHED */ 243 } 244 245 setlinebuf(stdout); 246 if (argc == optind) 247 allhosts(); 248 else { 249 for (; optind < argc; optind++) 250 (void)onehost(argv[optind]); 251 } 252 exit(0); 253 } 254