1 |
|
|
/* $OpenBSD: rusers.c,v 1.40 2017/01/21 11:32:04 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2001, 2003 Todd C. Miller <Todd.Miller@courtesan.com> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
* Sponsored in part by the Defense Advanced Research Projects |
18 |
|
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
19 |
|
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
20 |
|
|
*/ |
21 |
|
|
/*- |
22 |
|
|
* Copyright (c) 1993 John Brezak |
23 |
|
|
* All rights reserved. |
24 |
|
|
* |
25 |
|
|
* Redistribution and use in source and binary forms, with or without |
26 |
|
|
* modification, are permitted provided that the following conditions |
27 |
|
|
* are met: |
28 |
|
|
* 1. Redistributions of source code must retain the above copyright |
29 |
|
|
* notice, this list of conditions and the following disclaimer. |
30 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
31 |
|
|
* notice, this list of conditions and the following disclaimer in the |
32 |
|
|
* documentation and/or other materials provided with the distribution. |
33 |
|
|
* 3. The name of the author may not be used to endorse or promote products |
34 |
|
|
* derived from this software without specific prior written permission. |
35 |
|
|
* |
36 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR |
37 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
38 |
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
39 |
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
40 |
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
41 |
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
42 |
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
43 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
44 |
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
45 |
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
46 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
47 |
|
|
*/ |
48 |
|
|
|
49 |
|
|
#include <sys/ioctl.h> |
50 |
|
|
#include <sys/socket.h> |
51 |
|
|
#include <sys/signal.h> |
52 |
|
|
#include <rpc/rpc.h> |
53 |
|
|
#include <rpc/pmap_prot.h> |
54 |
|
|
#include <rpc/pmap_rmt.h> |
55 |
|
|
#include <rpcsvc/rusers.h> |
56 |
|
|
#include <rpcsvc/rnusers.h> /* Old protocol version */ |
57 |
|
|
#include <arpa/inet.h> |
58 |
|
|
#include <net/if.h> |
59 |
|
|
#include <err.h> |
60 |
|
|
#include <errno.h> |
61 |
|
|
#include <ifaddrs.h> |
62 |
|
|
#include <netdb.h> |
63 |
|
|
#include <stdio.h> |
64 |
|
|
#include <stdlib.h> |
65 |
|
|
#include <string.h> |
66 |
|
|
#include <termios.h> |
67 |
|
|
#include <unistd.h> |
68 |
|
|
#include <limits.h> |
69 |
|
|
#include <poll.h> |
70 |
|
|
|
71 |
|
|
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) |
72 |
|
|
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) |
73 |
|
|
|
74 |
|
|
/* Preferred formatting */ |
75 |
|
|
#define HOST_WIDTH 17 |
76 |
|
|
#define LINE_WIDTH 8 |
77 |
|
|
#define NAME_WIDTH 8 |
78 |
|
|
|
79 |
|
|
#define MAX_BROADCAST_SIZE 1400 |
80 |
|
|
|
81 |
|
|
struct host_info { |
82 |
|
|
u_int count; |
83 |
|
|
u_int idle; |
84 |
|
|
char *host; |
85 |
|
|
rusers_utmp *users; |
86 |
|
|
} *hostinfo; |
87 |
|
|
|
88 |
|
|
void print_entry(struct host_info *, int); |
89 |
|
|
void fmt_idle(int, char *, size_t); |
90 |
|
|
void onehost(char *); |
91 |
|
|
void allhosts(void); |
92 |
|
|
void sorthosts(void); |
93 |
|
|
void expandhosts(void); |
94 |
|
|
void alarmclock(int); |
95 |
|
|
char *estrndup(const char *, size_t); |
96 |
|
|
struct host_info *add_host(char *); |
97 |
|
|
int hcompare(const void *, const void *); |
98 |
|
|
int icompare(const void *, const void *); |
99 |
|
|
int ucompare(const void *, const void *); |
100 |
|
|
bool_t rusers_reply(char *, struct sockaddr_in *); |
101 |
|
|
bool_t rusers_reply_3(char *, struct sockaddr_in *); |
102 |
|
|
enum clnt_stat get_reply(int, in_port_t, u_long, struct rpc_msg *, |
103 |
|
|
struct rmtcallres *, bool_t (*)(char *, struct sockaddr_in *)); |
104 |
|
|
enum clnt_stat rpc_setup(int *, XDR *, struct rpc_msg *, |
105 |
|
|
struct rmtcallargs *, AUTH *, char *); |
106 |
|
|
__dead void usage(void); |
107 |
|
|
|
108 |
|
|
int aflag, hflag, iflag, lflag, uflag; |
109 |
|
|
u_int nentries, maxentries; |
110 |
|
|
long termwidth; |
111 |
|
|
extern char *__progname; |
112 |
|
|
|
113 |
|
|
int |
114 |
|
|
main(int argc, char **argv) |
115 |
|
|
{ |
116 |
|
|
struct winsize win; |
117 |
|
|
char *cp; |
118 |
|
|
int ch; |
119 |
|
|
|
120 |
|
|
while ((ch = getopt(argc, argv, "ahilu")) != -1) |
121 |
|
|
switch (ch) { |
122 |
|
|
case 'a': |
123 |
|
|
aflag = 1; |
124 |
|
|
break; |
125 |
|
|
case 'h': |
126 |
|
|
hflag = 1; |
127 |
|
|
break; |
128 |
|
|
case 'i': |
129 |
|
|
iflag = 1; |
130 |
|
|
break; |
131 |
|
|
case 'l': |
132 |
|
|
lflag = 1; |
133 |
|
|
break; |
134 |
|
|
case 'u': |
135 |
|
|
uflag = 1; |
136 |
|
|
break; |
137 |
|
|
default: |
138 |
|
|
usage(); |
139 |
|
|
/*NOTREACHED*/ |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
if (hflag + iflag + uflag > 1) |
143 |
|
|
usage(); |
144 |
|
|
|
145 |
|
|
termwidth = 0; |
146 |
|
|
if ((cp = getenv("COLUMNS")) != NULL) |
147 |
|
|
termwidth = strtonum(cp, 1, LONG_MAX, NULL); |
148 |
|
|
if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && |
149 |
|
|
win.ws_col > 0) |
150 |
|
|
termwidth = win.ws_col; |
151 |
|
|
if (termwidth == 0) |
152 |
|
|
termwidth = 80; |
153 |
|
|
|
154 |
|
|
setvbuf(stdout, NULL, _IOLBF, 0); |
155 |
|
|
|
156 |
|
|
if (argc == optind) { |
157 |
|
|
if (hflag || iflag || uflag) { |
158 |
|
|
puts("Collecting responses..."); |
159 |
|
|
allhosts(); |
160 |
|
|
sorthosts(); |
161 |
|
|
} else |
162 |
|
|
allhosts(); |
163 |
|
|
} else { |
164 |
|
|
aflag = 1; |
165 |
|
|
for (; optind < argc; optind++) |
166 |
|
|
(void) onehost(argv[optind]); |
167 |
|
|
if (hflag || iflag || uflag) |
168 |
|
|
sorthosts(); |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
exit(0); |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
struct host_info * |
175 |
|
|
add_host(char *host) |
176 |
|
|
{ |
177 |
|
|
int i; |
178 |
|
|
|
179 |
|
|
for (i = 0; i < nentries; i++) { |
180 |
|
|
/* Existing entry. */ |
181 |
|
|
if (strcmp(host, hostinfo[i].host) == 0) |
182 |
|
|
return(NULL); |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
/* New entry, allocate space if needed and store. */ |
186 |
|
|
if (nentries == maxentries) { |
187 |
|
|
maxentries += 128; |
188 |
|
|
hostinfo = reallocarray(hostinfo, maxentries, |
189 |
|
|
sizeof(*hostinfo)); |
190 |
|
|
if (hostinfo == NULL) |
191 |
|
|
err(1, NULL); |
192 |
|
|
} |
193 |
|
|
if ((hostinfo[nentries].host = strdup(host)) == NULL) |
194 |
|
|
err(1, NULL); |
195 |
|
|
return(&hostinfo[nentries++]); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
void |
199 |
|
|
fmt_idle(int idle, char *idle_time, size_t idle_time_len) |
200 |
|
|
{ |
201 |
|
|
int days, hours, minutes, seconds; |
202 |
|
|
|
203 |
|
|
switch (idle) { |
204 |
|
|
case 0: |
205 |
|
|
*idle_time = '\0'; |
206 |
|
|
break; |
207 |
|
|
case INT_MAX: |
208 |
|
|
strlcpy(idle_time, "??", idle_time_len); |
209 |
|
|
break; |
210 |
|
|
default: |
211 |
|
|
seconds = idle; |
212 |
|
|
days = seconds / (60*60*24); |
213 |
|
|
seconds %= (60*60*24); |
214 |
|
|
hours = seconds / (60*60); |
215 |
|
|
seconds %= (60*60); |
216 |
|
|
minutes = seconds / 60; |
217 |
|
|
seconds %= 60; |
218 |
|
|
if (idle >= (24*60*60)) |
219 |
|
|
snprintf(idle_time, idle_time_len, |
220 |
|
|
"%d day%s, %d:%02d:%02d", days, |
221 |
|
|
days > 1 ? "s" : "", hours, minutes, seconds); |
222 |
|
|
else if (idle >= (60*60)) |
223 |
|
|
snprintf(idle_time, idle_time_len, "%2d:%02d:%02d", |
224 |
|
|
hours, minutes, seconds); |
225 |
|
|
else if (idle > 60) |
226 |
|
|
snprintf(idle_time, idle_time_len, "%2d:%02d", |
227 |
|
|
minutes, seconds); |
228 |
|
|
else |
229 |
|
|
snprintf(idle_time, idle_time_len, " :%02d", idle); |
230 |
|
|
break; |
231 |
|
|
} |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
bool_t |
235 |
|
|
rusers_reply(char *replyp, struct sockaddr_in *raddrp) |
236 |
|
|
{ |
237 |
|
|
utmpidlearr *up = (utmpidlearr *)replyp; |
238 |
|
|
struct host_info *entry; |
239 |
|
|
struct hostent *hp; |
240 |
|
|
rusers_utmp *ut; |
241 |
|
|
char *host; |
242 |
|
|
int i; |
243 |
|
|
|
244 |
|
|
if (!aflag && up->uia_cnt == 0) |
245 |
|
|
return(0); |
246 |
|
|
|
247 |
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
248 |
|
|
sizeof(struct in_addr), AF_INET); |
249 |
|
|
if (hp) |
250 |
|
|
host = hp->h_name; |
251 |
|
|
else |
252 |
|
|
host = inet_ntoa(raddrp->sin_addr); |
253 |
|
|
if ((entry = add_host(host)) == NULL) |
254 |
|
|
return(0); |
255 |
|
|
|
256 |
|
|
if (up->uia_cnt == 0) |
257 |
|
|
ut = NULL; |
258 |
|
|
else if ((ut = calloc(up->uia_cnt, sizeof(*ut))) == NULL) |
259 |
|
|
err(1, NULL); |
260 |
|
|
entry->users = ut; |
261 |
|
|
entry->count = up->uia_cnt; |
262 |
|
|
entry->idle = UINT_MAX; |
263 |
|
|
for (i = 0; i < up->uia_cnt; i++, ut++) { |
264 |
|
|
ut->ut_user = estrndup(up->uia_arr[i]->ui_utmp.ut_name, |
265 |
|
|
RNUSERS_MAXUSERLEN); |
266 |
|
|
ut->ut_line = estrndup(up->uia_arr[i]->ui_utmp.ut_line, |
267 |
|
|
RNUSERS_MAXLINELEN); |
268 |
|
|
ut->ut_host = estrndup(up->uia_arr[i]->ui_utmp.ut_host, |
269 |
|
|
RNUSERS_MAXHOSTLEN); |
270 |
|
|
ut->ut_time = up->uia_arr[i]->ui_utmp.ut_time; |
271 |
|
|
ut->ut_idle = up->uia_arr[i]->ui_idle; |
272 |
|
|
if (ut->ut_idle < entry->idle) |
273 |
|
|
entry->idle = ut->ut_idle; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
if (!hflag && !iflag && !uflag) { |
277 |
|
|
print_entry(entry, lflag && entry->count); |
278 |
|
|
for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { |
279 |
|
|
free(ut->ut_user); |
280 |
|
|
free(ut->ut_line); |
281 |
|
|
free(ut->ut_host); |
282 |
|
|
} |
283 |
|
|
free(entry->users); |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
return(0); |
287 |
|
|
} |
288 |
|
|
|
289 |
|
|
bool_t |
290 |
|
|
rusers_reply_3(char *replyp, struct sockaddr_in *raddrp) |
291 |
|
|
{ |
292 |
|
|
utmp_array *up3 = (utmp_array *)replyp; |
293 |
|
|
struct host_info *entry; |
294 |
|
|
struct hostent *hp; |
295 |
|
|
rusers_utmp *ut; |
296 |
|
|
char *host; |
297 |
|
|
int i; |
298 |
|
|
|
299 |
|
|
if (!aflag && up3->utmp_array_len == 0) |
300 |
|
|
return(0); |
301 |
|
|
|
302 |
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr, |
303 |
|
|
sizeof(struct in_addr), AF_INET); |
304 |
|
|
if (hp) |
305 |
|
|
host = hp->h_name; |
306 |
|
|
else |
307 |
|
|
host = inet_ntoa(raddrp->sin_addr); |
308 |
|
|
if ((entry = add_host(host)) == NULL) |
309 |
|
|
return(0); |
310 |
|
|
|
311 |
|
|
if (up3->utmp_array_len == 0) |
312 |
|
|
ut = NULL; |
313 |
|
|
else if ((ut = calloc(up3->utmp_array_len, sizeof(*ut))) == NULL) |
314 |
|
|
err(1, NULL); |
315 |
|
|
entry->users = ut; |
316 |
|
|
entry->count = up3->utmp_array_len; |
317 |
|
|
entry->idle = UINT_MAX; |
318 |
|
|
for (i = 0; i < up3->utmp_array_len; i++, ut++) { |
319 |
|
|
ut->ut_user = estrndup(up3->utmp_array_val[i].ut_user, |
320 |
|
|
RUSERS_MAXUSERLEN); |
321 |
|
|
ut->ut_line = estrndup(up3->utmp_array_val[i].ut_line, |
322 |
|
|
RUSERS_MAXLINELEN); |
323 |
|
|
ut->ut_host = estrndup(up3->utmp_array_val[i].ut_host, |
324 |
|
|
RUSERS_MAXHOSTLEN); |
325 |
|
|
ut->ut_time = up3->utmp_array_val[i].ut_time; |
326 |
|
|
ut->ut_idle = up3->utmp_array_val[i].ut_idle; |
327 |
|
|
if (ut->ut_idle < entry->idle) |
328 |
|
|
entry->idle = ut->ut_idle; |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
if (!hflag && !iflag && !uflag) { |
332 |
|
|
print_entry(entry, lflag && entry->count); |
333 |
|
|
for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { |
334 |
|
|
free(ut->ut_user); |
335 |
|
|
free(ut->ut_line); |
336 |
|
|
free(ut->ut_host); |
337 |
|
|
} |
338 |
|
|
free(entry->users); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
return(0); |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
void |
345 |
|
|
onehost(char *host) |
346 |
|
|
{ |
347 |
|
|
utmpidlearr up; |
348 |
|
|
utmp_array up3; |
349 |
|
|
CLIENT *rusers_clnt; |
350 |
|
|
struct sockaddr_in sin; |
351 |
|
|
struct hostent *hp; |
352 |
|
|
struct timeval tv = { 25, 0 }; |
353 |
|
|
int error; |
354 |
|
|
|
355 |
|
|
memset(&sin, 0, sizeof sin); |
356 |
|
|
|
357 |
|
|
hp = gethostbyname(host); |
358 |
|
|
if (hp == NULL) |
359 |
|
|
errx(1, "unknown host \"%s\"", host); |
360 |
|
|
|
361 |
|
|
/* Try version 3 first. */ |
362 |
|
|
rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_3, "udp"); |
363 |
|
|
if (rusers_clnt == NULL) { |
364 |
|
|
clnt_pcreateerror(__progname); |
365 |
|
|
exit(1); |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
memset(&up3, 0, sizeof(up3)); |
369 |
|
|
error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, |
370 |
|
|
xdr_utmp_array, &up3, tv); |
371 |
|
|
switch (error) { |
372 |
|
|
case RPC_SUCCESS: |
373 |
|
|
sin.sin_addr.s_addr = *(int *)hp->h_addr; |
374 |
|
|
rusers_reply_3((char *)&up3, &sin); |
375 |
|
|
clnt_destroy(rusers_clnt); |
376 |
|
|
return; |
377 |
|
|
case RPC_PROGVERSMISMATCH: |
378 |
|
|
clnt_destroy(rusers_clnt); |
379 |
|
|
break; |
380 |
|
|
default: |
381 |
|
|
clnt_perror(rusers_clnt, __progname); |
382 |
|
|
clnt_destroy(rusers_clnt); |
383 |
|
|
exit(1); |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
/* Fall back to version 2. */ |
387 |
|
|
rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); |
388 |
|
|
if (rusers_clnt == NULL) { |
389 |
|
|
clnt_pcreateerror(__progname); |
390 |
|
|
exit(1); |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
memset(&up, 0, sizeof(up)); |
394 |
|
|
error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, |
395 |
|
|
xdr_utmpidlearr, &up, tv); |
396 |
|
|
if (error != RPC_SUCCESS) { |
397 |
|
|
clnt_perror(rusers_clnt, __progname); |
398 |
|
|
clnt_destroy(rusers_clnt); |
399 |
|
|
exit(1); |
400 |
|
|
} |
401 |
|
|
sin.sin_addr.s_addr = *(int *)hp->h_addr; |
402 |
|
|
rusers_reply((char *)&up, &sin); |
403 |
|
|
clnt_destroy(rusers_clnt); |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
enum clnt_stat |
407 |
|
|
get_reply(int sock, in_port_t port, u_long xid, struct rpc_msg *msgp, |
408 |
|
|
struct rmtcallres *resp, bool_t (*callback)(char *, struct sockaddr_in *)) |
409 |
|
|
{ |
410 |
|
|
ssize_t inlen; |
411 |
|
|
socklen_t fromlen; |
412 |
|
|
struct sockaddr_in raddr; |
413 |
|
|
char inbuf[UDPMSGSIZE]; |
414 |
|
|
XDR xdr; |
415 |
|
|
|
416 |
|
|
retry: |
417 |
|
|
msgp->acpted_rply.ar_verf = _null_auth; |
418 |
|
|
msgp->acpted_rply.ar_results.where = (caddr_t)resp; |
419 |
|
|
msgp->acpted_rply.ar_results.proc = xdr_rmtcallres; |
420 |
|
|
|
421 |
|
|
fromlen = sizeof(raddr); |
422 |
|
|
inlen = recvfrom(sock, inbuf, sizeof(inbuf), 0, |
423 |
|
|
(struct sockaddr *)&raddr, &fromlen); |
424 |
|
|
if (inlen < 0) { |
425 |
|
|
if (errno == EINTR) |
426 |
|
|
goto retry; |
427 |
|
|
return (RPC_CANTRECV); |
428 |
|
|
} |
429 |
|
|
if (inlen < sizeof(u_int32_t)) |
430 |
|
|
goto retry; |
431 |
|
|
|
432 |
|
|
/* |
433 |
|
|
* If the reply we got matches our request, decode the |
434 |
|
|
* replay and pass it to the callback function. |
435 |
|
|
*/ |
436 |
|
|
xdrmem_create(&xdr, inbuf, (u_int)inlen, XDR_DECODE); |
437 |
|
|
if (xdr_replymsg(&xdr, msgp)) { |
438 |
|
|
if ((msgp->rm_xid == xid) && |
439 |
|
|
(msgp->rm_reply.rp_stat == MSG_ACCEPTED) && |
440 |
|
|
(msgp->acpted_rply.ar_stat == SUCCESS)) { |
441 |
|
|
raddr.sin_port = htons(port); |
442 |
|
|
(void)(*callback)(resp->results_ptr, &raddr); |
443 |
|
|
} |
444 |
|
|
} |
445 |
|
|
xdr.x_op = XDR_FREE; |
446 |
|
|
msgp->acpted_rply.ar_results.proc = xdr_void; |
447 |
|
|
(void)xdr_replymsg(&xdr, msgp); |
448 |
|
|
(void)(*resp->xdr_results)(&xdr, resp->results_ptr); |
449 |
|
|
xdr_destroy(&xdr); |
450 |
|
|
|
451 |
|
|
return(RPC_SUCCESS); |
452 |
|
|
} |
453 |
|
|
|
454 |
|
|
enum clnt_stat |
455 |
|
|
rpc_setup(int *fdp, XDR *xdr, struct rpc_msg *msg, struct rmtcallargs *args, |
456 |
|
|
AUTH *unix_auth, char *buf) |
457 |
|
|
{ |
458 |
|
|
int on = 1; |
459 |
|
|
|
460 |
|
|
if ((*fdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
461 |
|
|
return(RPC_CANTSEND); |
462 |
|
|
|
463 |
|
|
if (setsockopt(*fdp, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) |
464 |
|
|
return(RPC_CANTSEND); |
465 |
|
|
|
466 |
|
|
msg->rm_xid = arc4random(); |
467 |
|
|
msg->rm_direction = CALL; |
468 |
|
|
msg->rm_call.cb_rpcvers = RPC_MSG_VERSION; |
469 |
|
|
msg->rm_call.cb_prog = PMAPPROG; |
470 |
|
|
msg->rm_call.cb_vers = PMAPVERS; |
471 |
|
|
msg->rm_call.cb_proc = PMAPPROC_CALLIT; |
472 |
|
|
msg->rm_call.cb_cred = unix_auth->ah_cred; |
473 |
|
|
msg->rm_call.cb_verf = unix_auth->ah_verf; |
474 |
|
|
|
475 |
|
|
xdrmem_create(xdr, buf, MAX_BROADCAST_SIZE, XDR_ENCODE); |
476 |
|
|
if (!xdr_callmsg(xdr, msg) || !xdr_rmtcall_args(xdr, args)) |
477 |
|
|
return(RPC_CANTENCODEARGS); |
478 |
|
|
|
479 |
|
|
return(RPC_SUCCESS); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
void |
483 |
|
|
allhosts(void) |
484 |
|
|
{ |
485 |
|
|
enum clnt_stat stat; |
486 |
|
|
struct itimerval timeout; |
487 |
|
|
AUTH *unix_auth; |
488 |
|
|
size_t outlen[2]; |
489 |
|
|
int sock[2] = { -1, -1 }; |
490 |
|
|
int i, rval; |
491 |
|
|
u_long xid[2], port[2]; |
492 |
|
|
struct pollfd pfd[2]; |
493 |
|
|
struct sockaddr_in *sin, baddr; |
494 |
|
|
struct rmtcallargs args; |
495 |
|
|
struct rmtcallres res[2]; |
496 |
|
|
struct rpc_msg msg[2]; |
497 |
|
|
struct ifaddrs *ifa, *ifap = NULL; |
498 |
|
|
char buf[2][MAX_BROADCAST_SIZE]; |
499 |
|
|
utmpidlearr up; |
500 |
|
|
utmp_array up3; |
501 |
|
|
XDR xdr; |
502 |
|
|
|
503 |
|
|
if ((unix_auth = authunix_create_default()) == NULL) |
504 |
|
|
err(1, "can't create auth handle"); |
505 |
|
|
|
506 |
|
|
if (getifaddrs(&ifap) != 0) |
507 |
|
|
err(1, "can't get list of interface addresses"); |
508 |
|
|
|
509 |
|
|
memset(&up, 0, sizeof(up)); |
510 |
|
|
memset(&up3, 0, sizeof(up3)); |
511 |
|
|
memset(&baddr, 0, sizeof(baddr)); |
512 |
|
|
memset(&res, 0, sizeof(res)); |
513 |
|
|
memset(&msg, 0, sizeof(msg)); |
514 |
|
|
memset(&timeout, 0, sizeof(timeout)); |
515 |
|
|
|
516 |
|
|
args.prog = RUSERSPROG; |
517 |
|
|
args.vers = RUSERSVERS_IDLE; |
518 |
|
|
args.proc = RUSERSPROC_NAMES; |
519 |
|
|
args.xdr_args = xdr_void; |
520 |
|
|
args.args_ptr = NULL; |
521 |
|
|
|
522 |
|
|
stat = rpc_setup(&sock[0], &xdr, &msg[0], &args, unix_auth, buf[0]); |
523 |
|
|
if (stat != RPC_SUCCESS) |
524 |
|
|
goto cleanup; |
525 |
|
|
xid[0] = msg[0].rm_xid; |
526 |
|
|
outlen[0] = xdr_getpos(&xdr); |
527 |
|
|
xdr_destroy(&xdr); |
528 |
|
|
|
529 |
|
|
args.vers = RUSERSVERS_3; |
530 |
|
|
stat = rpc_setup(&sock[1], &xdr, &msg[1], &args, unix_auth, buf[1]); |
531 |
|
|
if (stat != RPC_SUCCESS) |
532 |
|
|
goto cleanup; |
533 |
|
|
xid[1] = msg[1].rm_xid; |
534 |
|
|
outlen[1] = xdr_getpos(&xdr); |
535 |
|
|
xdr_destroy(&xdr); |
536 |
|
|
|
537 |
|
|
baddr.sin_family = AF_INET; |
538 |
|
|
baddr.sin_port = htons(PMAPPORT); |
539 |
|
|
baddr.sin_addr.s_addr = htonl(INADDR_ANY); |
540 |
|
|
|
541 |
|
|
res[0].port_ptr = &port[0]; |
542 |
|
|
res[0].xdr_results = xdr_utmpidlearr; |
543 |
|
|
res[0].results_ptr = (caddr_t)&up; |
544 |
|
|
|
545 |
|
|
res[1].port_ptr = &port[1]; |
546 |
|
|
res[1].xdr_results = xdr_utmp_array; |
547 |
|
|
res[1].results_ptr = (caddr_t)&up3; |
548 |
|
|
|
549 |
|
|
(void)signal(SIGALRM, alarmclock); |
550 |
|
|
|
551 |
|
|
/* |
552 |
|
|
* We do 6 runs through the loop. On even runs we send |
553 |
|
|
* a version 3 broadcast. On odd ones we send a version 2 |
554 |
|
|
* broadcast. This should give version 3 replies enough |
555 |
|
|
* of an 'edge' over the old version 2 ones in most cases. |
556 |
|
|
* We poll() waiting for replies for 5 seconds in between |
557 |
|
|
* each broadcast. |
558 |
|
|
*/ |
559 |
|
|
for (i = 0; i < 6; i++) { |
560 |
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
561 |
|
|
if (ifa->ifa_addr->sa_family != AF_INET || |
562 |
|
|
!(ifa->ifa_flags & IFF_BROADCAST) || |
563 |
|
|
!(ifa->ifa_flags & IFF_UP) || |
564 |
|
|
ifa->ifa_broadaddr == NULL || |
565 |
|
|
ifa->ifa_broadaddr->sa_family != AF_INET) |
566 |
|
|
continue; |
567 |
|
|
sin = (struct sockaddr_in *)ifa->ifa_broadaddr; |
568 |
|
|
baddr.sin_addr = sin->sin_addr; |
569 |
|
|
|
570 |
|
|
/* use protocol 2 or 3 depending on i (odd or even) */ |
571 |
|
|
if (i & 1) { |
572 |
|
|
if (sendto(sock[0], buf[0], outlen[0], 0, |
573 |
|
|
(struct sockaddr *)&baddr, |
574 |
|
|
sizeof(baddr)) != outlen[0]) |
575 |
|
|
err(1, "can't send broadcast packet"); |
576 |
|
|
} else { |
577 |
|
|
if (sendto(sock[1], buf[1], outlen[1], 0, |
578 |
|
|
(struct sockaddr *)&baddr, |
579 |
|
|
sizeof(baddr)) != outlen[1]) |
580 |
|
|
err(1, "can't send broadcast packet"); |
581 |
|
|
} |
582 |
|
|
} |
583 |
|
|
|
584 |
|
|
/* |
585 |
|
|
* We stay in the poll loop for ~5 seconds |
586 |
|
|
*/ |
587 |
|
|
timeout.it_value.tv_sec = 5; |
588 |
|
|
timeout.it_value.tv_usec = 0; |
589 |
|
|
while (timerisset(&timeout.it_value)) { |
590 |
|
|
pfd[0].fd = sock[0]; |
591 |
|
|
pfd[0].events = POLLIN; |
592 |
|
|
pfd[1].fd = sock[1]; |
593 |
|
|
pfd[1].events = POLLIN; |
594 |
|
|
setitimer(ITIMER_REAL, &timeout, NULL); |
595 |
|
|
rval = poll(pfd, 2, 0); |
596 |
|
|
setitimer(ITIMER_REAL, NULL, &timeout); |
597 |
|
|
if (rval == -1) { |
598 |
|
|
if (errno == EINTR) |
599 |
|
|
break; |
600 |
|
|
err(1, "poll"); /* shouldn't happen */ |
601 |
|
|
} |
602 |
|
|
if (pfd[1].revents & POLLIN) { |
603 |
|
|
stat = get_reply(sock[1], (in_port_t)port[1], |
604 |
|
|
xid[1], &msg[1], &res[1], rusers_reply_3); |
605 |
|
|
if (stat != RPC_SUCCESS) |
606 |
|
|
goto cleanup; |
607 |
|
|
} |
608 |
|
|
if (pfd[0].revents & POLLIN) { |
609 |
|
|
stat = get_reply(sock[0], (in_port_t)port[0], |
610 |
|
|
xid[0], &msg[0], &res[0], rusers_reply); |
611 |
|
|
if (stat != RPC_SUCCESS) |
612 |
|
|
goto cleanup; |
613 |
|
|
} |
614 |
|
|
} |
615 |
|
|
} |
616 |
|
|
cleanup: |
617 |
|
|
if (ifap != NULL) |
618 |
|
|
freeifaddrs(ifap); |
619 |
|
|
if (sock[0] >= 0) |
620 |
|
|
(void)close(sock[0]); |
621 |
|
|
if (sock[1] >= 0) |
622 |
|
|
(void)close(sock[1]); |
623 |
|
|
AUTH_DESTROY(unix_auth); |
624 |
|
|
if (stat != RPC_SUCCESS) { |
625 |
|
|
clnt_perrno(stat); |
626 |
|
|
exit(1); |
627 |
|
|
} |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
void |
631 |
|
|
print_entry(struct host_info *entry, int longfmt) |
632 |
|
|
{ |
633 |
|
|
char date[32], idle_time[64]; |
634 |
|
|
char remote[RUSERS_MAXHOSTLEN + 3]; |
635 |
|
|
struct rusers_utmp *ut; |
636 |
|
|
int i, len; |
637 |
|
|
|
638 |
|
|
if (!longfmt) |
639 |
|
|
printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, entry->host); |
640 |
|
|
|
641 |
|
|
for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { |
642 |
|
|
if (longfmt) { |
643 |
|
|
time_t tim = ut->ut_time; |
644 |
|
|
strftime(date, sizeof(date), "%h %d %R", |
645 |
|
|
localtime(&tim)); |
646 |
|
|
date[sizeof(date) - 1] = '\0'; |
647 |
|
|
fmt_idle(ut->ut_idle, idle_time, sizeof(idle_time)); |
648 |
|
|
len = termwidth - |
649 |
|
|
(MAXIMUM(strlen(ut->ut_user), NAME_WIDTH) + 1 + |
650 |
|
|
HOST_WIDTH + 1 + LINE_WIDTH + 1 + strlen(date) + |
651 |
|
|
1 + MAXIMUM(8, strlen(idle_time)) + 1 + 2); |
652 |
|
|
if (len > 0 && ut->ut_host[0] != '\0') |
653 |
|
|
snprintf(remote, sizeof(remote), "(%.*s)", |
654 |
|
|
MINIMUM(len, RUSERS_MAXHOSTLEN), ut->ut_host); |
655 |
|
|
else |
656 |
|
|
remote[0] = '\0'; |
657 |
|
|
len = HOST_WIDTH - MINIMUM(HOST_WIDTH, strlen(entry->host)) + |
658 |
|
|
LINE_WIDTH - MINIMUM(LINE_WIDTH, strlen(ut->ut_line)); |
659 |
|
|
printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n", |
660 |
|
|
NAME_WIDTH, ut->ut_user, HOST_WIDTH, entry->host, |
661 |
|
|
LINE_WIDTH, ut->ut_line, len, "", date, |
662 |
|
|
idle_time, remote); |
663 |
|
|
} else { |
664 |
|
|
fputs(ut->ut_user, stdout); |
665 |
|
|
putchar(' '); |
666 |
|
|
} |
667 |
|
|
} |
668 |
|
|
if (!longfmt) |
669 |
|
|
putchar('\n'); |
670 |
|
|
} |
671 |
|
|
|
672 |
|
|
void |
673 |
|
|
expandhosts(void) |
674 |
|
|
{ |
675 |
|
|
struct host_info *new_hostinfo, *entry; |
676 |
|
|
u_int count; |
677 |
|
|
int i, j; |
678 |
|
|
|
679 |
|
|
for (i = 0, count = 0; i < nentries; i++) |
680 |
|
|
count += hostinfo[i].count; |
681 |
|
|
|
682 |
|
|
new_hostinfo = calloc(sizeof(*entry), count); |
683 |
|
|
if (new_hostinfo == NULL) |
684 |
|
|
err(1, NULL); |
685 |
|
|
for (i = 0, entry = new_hostinfo; i < nentries; i++) { |
686 |
|
|
for (j = 0; j < hostinfo[i].count; j++) { |
687 |
|
|
memcpy(entry, &hostinfo[i], sizeof(*entry)); |
688 |
|
|
entry->users = &hostinfo[i].users[j]; |
689 |
|
|
entry->idle = entry->users->ut_idle; |
690 |
|
|
entry->count = 1; |
691 |
|
|
entry++; |
692 |
|
|
} |
693 |
|
|
} |
694 |
|
|
free(hostinfo); |
695 |
|
|
hostinfo = new_hostinfo; |
696 |
|
|
nentries = maxentries = count; |
697 |
|
|
} |
698 |
|
|
|
699 |
|
|
void |
700 |
|
|
sorthosts(void) |
701 |
|
|
{ |
702 |
|
|
int i; |
703 |
|
|
int (*compar)(const void *, const void *); |
704 |
|
|
|
705 |
|
|
if (iflag && lflag) |
706 |
|
|
expandhosts(); |
707 |
|
|
|
708 |
|
|
if (hflag) |
709 |
|
|
compar = hcompare; |
710 |
|
|
else if (iflag) |
711 |
|
|
compar = icompare; |
712 |
|
|
else |
713 |
|
|
compar = ucompare; |
714 |
|
|
qsort(hostinfo, nentries, sizeof(*hostinfo), compar); |
715 |
|
|
|
716 |
|
|
for (i = 0; i < nentries; i++) |
717 |
|
|
print_entry(&hostinfo[i], lflag && hostinfo[i].count); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
int |
721 |
|
|
hcompare(const void *aa, const void *bb) |
722 |
|
|
{ |
723 |
|
|
const struct host_info *a = (struct host_info *)aa; |
724 |
|
|
const struct host_info *b = (struct host_info *)bb; |
725 |
|
|
int rval; |
726 |
|
|
|
727 |
|
|
if ((rval = strcasecmp(a->host, b->host)) != 0) |
728 |
|
|
return(rval); |
729 |
|
|
|
730 |
|
|
if (a->idle < b->idle) |
731 |
|
|
return(-1); |
732 |
|
|
else if (a->idle > b->idle) |
733 |
|
|
return(1); |
734 |
|
|
|
735 |
|
|
if (a->count > b->count) |
736 |
|
|
return(-1); |
737 |
|
|
else if (a->count < b->count) |
738 |
|
|
return(1); |
739 |
|
|
|
740 |
|
|
return(0); |
741 |
|
|
} |
742 |
|
|
|
743 |
|
|
int |
744 |
|
|
icompare(const void *aa, const void *bb) |
745 |
|
|
{ |
746 |
|
|
const struct host_info *a = (struct host_info *)aa; |
747 |
|
|
const struct host_info *b = (struct host_info *)bb; |
748 |
|
|
|
749 |
|
|
if (a->idle < b->idle) |
750 |
|
|
return(-1); |
751 |
|
|
else if (a->idle > b->idle) |
752 |
|
|
return(1); |
753 |
|
|
|
754 |
|
|
if (a->count > b->count) |
755 |
|
|
return(-1); |
756 |
|
|
else if (a->count < b->count) |
757 |
|
|
return(1); |
758 |
|
|
|
759 |
|
|
return(strcasecmp(a->host, b->host)); |
760 |
|
|
} |
761 |
|
|
|
762 |
|
|
int |
763 |
|
|
ucompare(const void *aa, const void *bb) |
764 |
|
|
{ |
765 |
|
|
const struct host_info *a = (struct host_info *)aa; |
766 |
|
|
const struct host_info *b = (struct host_info *)bb; |
767 |
|
|
|
768 |
|
|
if (a->count > b->count) |
769 |
|
|
return(-1); |
770 |
|
|
else if (a->count < b->count) |
771 |
|
|
return(1); |
772 |
|
|
|
773 |
|
|
if (a->idle < b->idle) |
774 |
|
|
return(-1); |
775 |
|
|
else if (a->idle > b->idle) |
776 |
|
|
return(1); |
777 |
|
|
|
778 |
|
|
return(strcasecmp(a->host, b->host)); |
779 |
|
|
} |
780 |
|
|
|
781 |
|
|
void |
782 |
|
|
alarmclock(int signo) |
783 |
|
|
{ |
784 |
|
|
|
785 |
|
|
; /* just interrupt */ |
786 |
|
|
} |
787 |
|
|
|
788 |
|
|
char * |
789 |
|
|
estrndup(const char *src, size_t len) |
790 |
|
|
{ |
791 |
|
|
char *dst, *end; |
792 |
|
|
|
793 |
|
|
if ((end = memchr(src, '\0', len)) != NULL) |
794 |
|
|
len = end - src; |
795 |
|
|
|
796 |
|
|
if ((dst = malloc(len + 1)) == NULL) |
797 |
|
|
err(1, NULL); |
798 |
|
|
memcpy(dst, src, len); |
799 |
|
|
dst[len] = '\0'; |
800 |
|
|
|
801 |
|
|
return(dst); |
802 |
|
|
} |
803 |
|
|
|
804 |
|
|
void |
805 |
|
|
usage(void) |
806 |
|
|
{ |
807 |
|
|
|
808 |
|
|
fprintf(stderr, "usage: %s [-al] [-h | -i | -u] [hosts ...]\n", |
809 |
|
|
__progname); |
810 |
|
|
exit(1); |
811 |
|
|
} |