File: | src/usr.bin/rusers/rusers.c |
Warning: | line 604, column 12 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: rusers.c,v 1.43 2020/12/29 19:52:16 benno Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2001, 2003 Todd C. Miller <millert@openbsd.org> | |||
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(*__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)) (((a) < (b)) ? (a) : (b)) | |||
72 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
73 | ||||
74 | /* Preferred formatting */ | |||
75 | #define HOST_WIDTH17 17 | |||
76 | #define LINE_WIDTH8 8 | |||
77 | #define NAME_WIDTH8 8 | |||
78 | ||||
79 | #define MAX_BROADCAST_SIZE1400 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_tint32_t rusers_reply(char *, struct sockaddr_in *); | |||
101 | bool_tint32_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_tint32_t (*)(char *, struct sockaddr_in *)); | |||
104 | enum clnt_stat rpc_setup(int *, XDR *, struct rpc_msg *, | |||
105 | struct rmtcallargs *, AUTH *, char *); | |||
106 | __dead__attribute__((__noreturn__)) 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((void *)0)) | |||
147 | termwidth = strtonum(cp, 1, LONG_MAX0x7fffffffffffffffL, NULL((void *)0)); | |||
148 | if (termwidth == 0 && ioctl(STDOUT_FILENO1, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff ) << 16) | ((('t')) << 8) | ((104))), &win) == 0 && | |||
149 | win.ws_col > 0) | |||
150 | termwidth = win.ws_col; | |||
151 | if (termwidth
| |||
152 | termwidth = 80; | |||
153 | ||||
154 | setvbuf(stdout(&__sF[1]), NULL((void *)0), _IOLBF1, 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((void *)0)); | |||
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((void *)0)) | |||
191 | err(1, NULL((void *)0)); | |||
192 | } | |||
193 | if ((hostinfo[nentries].host = strdup(host)) == NULL((void *)0)) | |||
194 | err(1, NULL((void *)0)); | |||
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_MAX0x7fffffff: | |||
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_tint32_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_INET2); | |||
249 | if (hp) | |||
250 | host = hp->h_name; | |||
251 | else | |||
252 | host = inet_ntoa(raddrp->sin_addr); | |||
253 | if ((entry = add_host(host)) == NULL((void *)0)) | |||
254 | return(0); | |||
255 | ||||
256 | if (up->uia_cnt == 0) | |||
257 | ut = NULL((void *)0); | |||
258 | else if ((ut = calloc(up->uia_cnt, sizeof(*ut))) == NULL((void *)0)) | |||
259 | err(1, NULL((void *)0)); | |||
260 | entry->users = ut; | |||
261 | entry->count = up->uia_cnt; | |||
262 | entry->idle = UINT_MAX0xffffffffU; | |||
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_MAXUSERLEN8); | |||
266 | ut->ut_line = estrndup(up->uia_arr[i]->ui_utmp.ut_line, | |||
267 | RNUSERS_MAXLINELEN8); | |||
268 | ut->ut_host = estrndup(up->uia_arr[i]->ui_utmp.ut_host, | |||
269 | RNUSERS_MAXHOSTLEN16); | |||
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_tint32_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_INET2); | |||
304 | if (hp) | |||
305 | host = hp->h_name; | |||
306 | else | |||
307 | host = inet_ntoa(raddrp->sin_addr); | |||
308 | if ((entry = add_host(host)) == NULL((void *)0)) | |||
309 | return(0); | |||
310 | ||||
311 | if (up3->utmp_array_len == 0) | |||
312 | ut = NULL((void *)0); | |||
313 | else if ((ut = calloc(up3->utmp_array_len, sizeof(*ut))) == NULL((void *)0)) | |||
314 | err(1, NULL((void *)0)); | |||
315 | entry->users = ut; | |||
316 | entry->count = up3->utmp_array_len; | |||
317 | entry->idle = UINT_MAX0xffffffffU; | |||
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_MAXUSERLEN32); | |||
321 | ut->ut_line = estrndup(up3->utmp_array_val[i].ut_line, | |||
322 | RUSERS_MAXLINELEN32); | |||
323 | ut->ut_host = estrndup(up3->utmp_array_val[i].ut_host, | |||
324 | RUSERS_MAXHOSTLEN257); | |||
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((void *)0)) | |||
359 | errx(1, "unknown host \"%s\"", host); | |||
360 | ||||
361 | /* Try version 3 first. */ | |||
362 | rusers_clnt = clnt_create(host, RUSERSPROG((u_long)100002), RUSERSVERS_3((u_long)3), "udp"); | |||
363 | if (rusers_clnt == NULL((void *)0)) { | |||
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,((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmp_array, (caddr_t )&up3, tv)) | |||
370 | xdr_utmp_array, &up3, tv)((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmp_array, (caddr_t )&up3, tv)); | |||
371 | switch (error) { | |||
372 | case RPC_SUCCESS: | |||
373 | sin.sin_addr.s_addr = *(int *)hp->h_addrh_addr_list[0]; | |||
374 | rusers_reply_3((char *)&up3, &sin); | |||
375 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
376 | return; | |||
377 | case RPC_PROGVERSMISMATCH: | |||
378 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
379 | break; | |||
380 | default: | |||
381 | clnt_perror(rusers_clnt, __progname); | |||
382 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
383 | exit(1); | |||
384 | } | |||
385 | ||||
386 | /* Fall back to version 2. */ | |||
387 | rusers_clnt = clnt_create(host, RUSERSPROG((u_long)100002), RUSERSVERS_IDLE2, "udp"); | |||
388 | if (rusers_clnt == NULL((void *)0)) { | |||
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,((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmpidlearr, (caddr_t )&up, tv)) | |||
395 | xdr_utmpidlearr, &up, tv)((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmpidlearr, (caddr_t )&up, tv)); | |||
396 | if (error != RPC_SUCCESS) { | |||
397 | clnt_perror(rusers_clnt, __progname); | |||
398 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
399 | exit(1); | |||
400 | } | |||
401 | sin.sin_addr.s_addr = *(int *)hp->h_addrh_addr_list[0]; | |||
402 | rusers_reply((char *)&up, &sin); | |||
403 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_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_tint32_t (*callback)(char *, struct sockaddr_in *)) | |||
409 | { | |||
410 | ssize_t inlen; | |||
411 | socklen_t fromlen; | |||
412 | struct sockaddr_in raddr; | |||
413 | char inbuf[UDPMSGSIZE8800]; | |||
414 | XDR xdr; | |||
415 | ||||
416 | retry: | |||
417 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
418 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = (caddr_t)resp; | |||
419 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.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 == -1) { | |||
425 | if (errno(*__errno()) == EINTR4) | |||
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_replyru.RM_rmb.rp_stat == MSG_ACCEPTED) && | |||
440 | (msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_stat == SUCCESS)) { | |||
441 | raddr.sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t )(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U ) >> 8) : __swap16md(port)); | |||
442 | (void)(*callback)(resp->results_ptr, &raddr); | |||
443 | } | |||
444 | } | |||
445 | xdr.x_op = XDR_FREE; | |||
446 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
447 | (void)xdr_replymsg(&xdr, msgp); | |||
448 | (void)(*resp->xdr_results)(&xdr, resp->results_ptr); | |||
449 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_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_INET2, SOCK_DGRAM2, IPPROTO_UDP17)) == -1) | |||
461 | return(RPC_CANTSEND); | |||
462 | ||||
463 | if (setsockopt(*fdp, SOL_SOCKET0xffff, SO_BROADCAST0x0020, &on, sizeof(on)) == -1) | |||
464 | return(RPC_CANTSEND); | |||
465 | ||||
466 | msg->rm_xid = arc4random(); | |||
467 | msg->rm_direction = CALL; | |||
468 | msg->rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
469 | msg->rm_callru.RM_cmb.cb_prog = PMAPPROG((unsigned long)100000); | |||
470 | msg->rm_callru.RM_cmb.cb_vers = PMAPVERS((unsigned long)2); | |||
471 | msg->rm_callru.RM_cmb.cb_proc = PMAPPROC_CALLIT((unsigned long)5); | |||
472 | msg->rm_callru.RM_cmb.cb_cred = unix_auth->ah_cred; | |||
473 | msg->rm_callru.RM_cmb.cb_verf = unix_auth->ah_verf; | |||
474 | ||||
475 | xdrmem_create(xdr, buf, MAX_BROADCAST_SIZE1400, 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((void *)0); | |||
498 | char buf[2][MAX_BROADCAST_SIZE1400]; | |||
499 | utmpidlearr up; | |||
500 | utmp_array up3; | |||
501 | XDR xdr; | |||
502 | ||||
503 | if ((unix_auth = authunix_create_default()) == NULL((void *)0)) | |||
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((u_long)100002); | |||
517 | args.vers = RUSERSVERS_IDLE2; | |||
518 | args.proc = RUSERSPROC_NAMES((u_long)2); | |||
519 | args.xdr_args = xdr_void; | |||
520 | args.args_ptr = NULL((void *)0); | |||
521 | ||||
522 | stat = rpc_setup(&sock[0], &xdr, &msg[0], &args, unix_auth, buf[0]); | |||
523 | if (stat
| |||
524 | goto cleanup; | |||
525 | xid[0] = msg[0].rm_xid; | |||
526 | outlen[0] = xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
527 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
528 | ||||
529 | args.vers = RUSERSVERS_3((u_long)3); | |||
530 | stat = rpc_setup(&sock[1], &xdr, &msg[1], &args, unix_auth, buf[1]); | |||
531 | if (stat
| |||
532 | goto cleanup; | |||
533 | xid[1] = msg[1].rm_xid; | |||
534 | outlen[1] = xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
535 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
536 | ||||
537 | baddr.sin_family = AF_INET2; | |||
538 | baddr.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t )(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8 | ((__uint16_t)(((unsigned short)111)) & 0xff00U) >> 8) : __swap16md(((unsigned short)111))); | |||
539 | baddr.sin_addr.s_addr = htonl(INADDR_ANY)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x00000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x00000000)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x00000000 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x00000000)))); | |||
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(SIGALRM14, 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 == NULL((void *)0) || | |||
562 | ifa->ifa_addr->sa_family != AF_INET2 || | |||
563 | !(ifa->ifa_flags & IFF_BROADCAST0x2) || | |||
564 | !(ifa->ifa_flags & IFF_UP0x1) || | |||
565 | ifa->ifa_broadaddrifa_dstaddr == NULL((void *)0) || | |||
566 | ifa->ifa_broadaddrifa_dstaddr->sa_family != AF_INET2) | |||
567 | continue; | |||
568 | sin = (struct sockaddr_in *)ifa->ifa_broadaddrifa_dstaddr; | |||
569 | baddr.sin_addr = sin->sin_addr; | |||
570 | ||||
571 | /* use protocol 2 or 3 depending on i (odd or even) */ | |||
572 | if (i & 1) { | |||
573 | if (sendto(sock[0], buf[0], outlen[0], 0, | |||
574 | (struct sockaddr *)&baddr, | |||
575 | sizeof(baddr)) != outlen[0]) | |||
576 | err(1, "can't send broadcast packet"); | |||
577 | } else { | |||
578 | if (sendto(sock[1], buf[1], outlen[1], 0, | |||
579 | (struct sockaddr *)&baddr, | |||
580 | sizeof(baddr)) != outlen[1]) | |||
581 | err(1, "can't send broadcast packet"); | |||
582 | } | |||
583 | } | |||
584 | ||||
585 | /* | |||
586 | * We stay in the poll loop for ~5 seconds | |||
587 | */ | |||
588 | timeout.it_value.tv_sec = 5; | |||
589 | timeout.it_value.tv_usec = 0; | |||
590 | while (timerisset(&timeout.it_value)((&timeout.it_value)->tv_sec || (&timeout.it_value )->tv_usec)) { | |||
591 | pfd[0].fd = sock[0]; | |||
592 | pfd[0].events = POLLIN0x0001; | |||
593 | pfd[1].fd = sock[1]; | |||
594 | pfd[1].events = POLLIN0x0001; | |||
595 | setitimer(ITIMER_REAL0, &timeout, NULL((void *)0)); | |||
596 | rval = poll(pfd, 2, 0); | |||
597 | setitimer(ITIMER_REAL0, NULL((void *)0), &timeout); | |||
598 | if (rval == -1) { | |||
599 | if (errno(*__errno()) == EINTR4) | |||
600 | break; | |||
601 | err(1, "poll"); /* shouldn't happen */ | |||
602 | } | |||
603 | if (pfd[1].revents & POLLIN0x0001) { | |||
604 | stat = get_reply(sock[1], (in_port_t)port[1], | |||
| ||||
605 | xid[1], &msg[1], &res[1], rusers_reply_3); | |||
606 | if (stat != RPC_SUCCESS) | |||
607 | goto cleanup; | |||
608 | } | |||
609 | if (pfd[0].revents & POLLIN0x0001) { | |||
610 | stat = get_reply(sock[0], (in_port_t)port[0], | |||
611 | xid[0], &msg[0], &res[0], rusers_reply); | |||
612 | if (stat != RPC_SUCCESS) | |||
613 | goto cleanup; | |||
614 | } | |||
615 | } | |||
616 | } | |||
617 | cleanup: | |||
618 | if (ifap != NULL((void *)0)) | |||
619 | freeifaddrs(ifap); | |||
620 | if (sock[0] >= 0) | |||
621 | (void)close(sock[0]); | |||
622 | if (sock[1] >= 0) | |||
623 | (void)close(sock[1]); | |||
624 | AUTH_DESTROY(unix_auth)((*((unix_auth)->ah_ops->ah_destroy))(unix_auth)); | |||
625 | if (stat != RPC_SUCCESS) { | |||
626 | clnt_perrno(stat); | |||
627 | exit(1); | |||
628 | } | |||
629 | } | |||
630 | ||||
631 | void | |||
632 | print_entry(struct host_info *entry, int longfmt) | |||
633 | { | |||
634 | char date[32], idle_time[64]; | |||
635 | char remote[RUSERS_MAXHOSTLEN257 + 3]; | |||
636 | struct rusers_utmp *ut; | |||
637 | int i, len; | |||
638 | ||||
639 | if (!longfmt) | |||
640 | printf("%-*.*s ", HOST_WIDTH17, HOST_WIDTH17, entry->host); | |||
641 | ||||
642 | for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { | |||
643 | if (longfmt) { | |||
644 | time_t tim = ut->ut_time; | |||
645 | strftime(date, sizeof(date), "%h %d %R", | |||
646 | localtime(&tim)); | |||
647 | date[sizeof(date) - 1] = '\0'; | |||
648 | fmt_idle(ut->ut_idle, idle_time, sizeof(idle_time)); | |||
649 | len = termwidth - | |||
650 | (MAXIMUM(strlen(ut->ut_user), NAME_WIDTH)(((strlen(ut->ut_user)) > (8)) ? (strlen(ut->ut_user )) : (8)) + 1 + | |||
651 | HOST_WIDTH17 + 1 + LINE_WIDTH8 + 1 + strlen(date) + | |||
652 | 1 + MAXIMUM(8, strlen(idle_time))(((8) > (strlen(idle_time))) ? (8) : (strlen(idle_time))) + 1 + 2); | |||
653 | if (len > 0 && ut->ut_host[0] != '\0') | |||
654 | snprintf(remote, sizeof(remote), "(%.*s)", | |||
655 | MINIMUM(len, RUSERS_MAXHOSTLEN)(((len) < (257)) ? (len) : (257)), ut->ut_host); | |||
656 | else | |||
657 | remote[0] = '\0'; | |||
658 | len = HOST_WIDTH17 - MINIMUM(HOST_WIDTH, strlen(entry->host))(((17) < (strlen(entry->host))) ? (17) : (strlen(entry-> host))) + | |||
659 | LINE_WIDTH8 - MINIMUM(LINE_WIDTH, strlen(ut->ut_line))(((8) < (strlen(ut->ut_line))) ? (8) : (strlen(ut->ut_line ))); | |||
660 | printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n", | |||
661 | NAME_WIDTH8, ut->ut_user, HOST_WIDTH17, entry->host, | |||
662 | LINE_WIDTH8, ut->ut_line, len, "", date, | |||
663 | idle_time, remote); | |||
664 | } else { | |||
665 | fputs(ut->ut_user, stdout(&__sF[1])); | |||
666 | putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', ( &__sF[1]))); | |||
667 | } | |||
668 | } | |||
669 | if (!longfmt) | |||
670 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
671 | } | |||
672 | ||||
673 | void | |||
674 | expandhosts(void) | |||
675 | { | |||
676 | struct host_info *new_hostinfo, *entry; | |||
677 | u_int count; | |||
678 | int i, j; | |||
679 | ||||
680 | for (i = 0, count = 0; i < nentries; i++) | |||
681 | count += hostinfo[i].count; | |||
682 | ||||
683 | new_hostinfo = calloc(sizeof(*entry), count); | |||
684 | if (new_hostinfo == NULL((void *)0)) | |||
685 | err(1, NULL((void *)0)); | |||
686 | for (i = 0, entry = new_hostinfo; i < nentries; i++) { | |||
687 | for (j = 0; j < hostinfo[i].count; j++) { | |||
688 | memcpy(entry, &hostinfo[i], sizeof(*entry)); | |||
689 | entry->users = &hostinfo[i].users[j]; | |||
690 | entry->idle = entry->users->ut_idle; | |||
691 | entry->count = 1; | |||
692 | entry++; | |||
693 | } | |||
694 | } | |||
695 | free(hostinfo); | |||
696 | hostinfo = new_hostinfo; | |||
697 | nentries = maxentries = count; | |||
698 | } | |||
699 | ||||
700 | void | |||
701 | sorthosts(void) | |||
702 | { | |||
703 | int i; | |||
704 | int (*compar)(const void *, const void *); | |||
705 | ||||
706 | if (iflag && lflag) | |||
707 | expandhosts(); | |||
708 | ||||
709 | if (hflag) | |||
710 | compar = hcompare; | |||
711 | else if (iflag) | |||
712 | compar = icompare; | |||
713 | else | |||
714 | compar = ucompare; | |||
715 | qsort(hostinfo, nentries, sizeof(*hostinfo), compar); | |||
716 | ||||
717 | for (i = 0; i < nentries; i++) | |||
718 | print_entry(&hostinfo[i], lflag && hostinfo[i].count); | |||
719 | } | |||
720 | ||||
721 | int | |||
722 | hcompare(const void *aa, const void *bb) | |||
723 | { | |||
724 | const struct host_info *a = (struct host_info *)aa; | |||
725 | const struct host_info *b = (struct host_info *)bb; | |||
726 | int rval; | |||
727 | ||||
728 | if ((rval = strcasecmp(a->host, b->host)) != 0) | |||
729 | return(rval); | |||
730 | ||||
731 | if (a->idle < b->idle) | |||
732 | return(-1); | |||
733 | else if (a->idle > b->idle) | |||
734 | return(1); | |||
735 | ||||
736 | if (a->count > b->count) | |||
737 | return(-1); | |||
738 | else if (a->count < b->count) | |||
739 | return(1); | |||
740 | ||||
741 | return(0); | |||
742 | } | |||
743 | ||||
744 | int | |||
745 | icompare(const void *aa, const void *bb) | |||
746 | { | |||
747 | const struct host_info *a = (struct host_info *)aa; | |||
748 | const struct host_info *b = (struct host_info *)bb; | |||
749 | ||||
750 | if (a->idle < b->idle) | |||
751 | return(-1); | |||
752 | else if (a->idle > b->idle) | |||
753 | return(1); | |||
754 | ||||
755 | if (a->count > b->count) | |||
756 | return(-1); | |||
757 | else if (a->count < b->count) | |||
758 | return(1); | |||
759 | ||||
760 | return(strcasecmp(a->host, b->host)); | |||
761 | } | |||
762 | ||||
763 | int | |||
764 | ucompare(const void *aa, const void *bb) | |||
765 | { | |||
766 | const struct host_info *a = (struct host_info *)aa; | |||
767 | const struct host_info *b = (struct host_info *)bb; | |||
768 | ||||
769 | if (a->count > b->count) | |||
770 | return(-1); | |||
771 | else if (a->count < b->count) | |||
772 | return(1); | |||
773 | ||||
774 | if (a->idle < b->idle) | |||
775 | return(-1); | |||
776 | else if (a->idle > b->idle) | |||
777 | return(1); | |||
778 | ||||
779 | return(strcasecmp(a->host, b->host)); | |||
780 | } | |||
781 | ||||
782 | void | |||
783 | alarmclock(int signo) | |||
784 | { | |||
785 | ||||
786 | ; /* just interrupt */ | |||
787 | } | |||
788 | ||||
789 | char * | |||
790 | estrndup(const char *src, size_t len) | |||
791 | { | |||
792 | char *dst, *end; | |||
793 | ||||
794 | if ((end = memchr(src, '\0', len)) != NULL((void *)0)) | |||
795 | len = end - src; | |||
796 | ||||
797 | if ((dst = malloc(len + 1)) == NULL((void *)0)) | |||
798 | err(1, NULL((void *)0)); | |||
799 | memcpy(dst, src, len); | |||
800 | dst[len] = '\0'; | |||
801 | ||||
802 | return(dst); | |||
803 | } | |||
804 | ||||
805 | void | |||
806 | usage(void) | |||
807 | { | |||
808 | ||||
809 | fprintf(stderr(&__sF[2]), "usage: %s [-al] [-h | -i | -u] [hosts ...]\n", | |||
810 | __progname); | |||
811 | exit(1); | |||
812 | } |