Annotation of src/usr.bin/rusers/rusers.c, Revision 1.15
1.14 millert 1: /* $OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $ */
1.3 deraadt 2:
1.14 millert 3: /*
4: * Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com>
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. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
1.1 deraadt 29: /*-
30: * Copyright (c) 1993 John Brezak
31: * All rights reserved.
1.14 millert 32: *
1.1 deraadt 33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. The name of the author may not be used to endorse or promote products
42: * derived from this software without specific prior written permission.
1.14 millert 43: *
1.1 deraadt 44: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
45: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
48: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
49: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
50: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
52: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
53: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54: * POSSIBILITY OF SUCH DAMAGE.
55: */
56:
57: #ifndef lint
1.14 millert 58: static const char rcsid[] = "$OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $";
1.1 deraadt 59: #endif /* not lint */
60:
61: #include <sys/param.h>
1.14 millert 62: #include <sys/ioctl.h>
1.1 deraadt 63: #include <sys/socket.h>
1.14 millert 64: #include <rpc/rpc.h>
1.15 ! millert 65: #include <rpc/pmap_clnt.h>
! 66: #include <arpa/inet.h>
1.14 millert 67: #include <rpcsvc/rusers.h>
68: #include <rpcsvc/rnusers.h> /* Old protocol version */
69: #include <err.h>
1.1 deraadt 70: #include <netdb.h>
71: #include <stdio.h>
1.14 millert 72: #include <stdlib.h>
1.8 millert 73: #include <string.h>
1.14 millert 74: #include <termios.h>
75: #include <unistd.h>
1.1 deraadt 76:
1.11 pjanzen 77: /* Preferred formatting */
1.14 millert 78: #define HOST_WIDTH 17
1.1 deraadt 79: #define LINE_WIDTH 8
1.11 pjanzen 80: #define NAME_WIDTH 8
1.1 deraadt 81:
1.14 millert 82: int search_host(struct in_addr);
83: void remember_host(char **);
84: void fmt_idle(int, char *, size_t);
85: void print_longline(int, u_int, char *, char *, char *, char *, int);
86: void onehost(char *);
87: void allhosts(void);
88: bool_t rusers_reply(char *, struct sockaddr_in *);
89: bool_t rusers_reply_3(char *, struct sockaddr_in *);
90: __dead void usage(void);
91:
1.1 deraadt 92: int longopt;
93: int allopt;
1.14 millert 94: long termwidth;
95: extern char *__progname;
1.1 deraadt 96:
97: struct host_list {
98: struct host_list *next;
99: struct in_addr addr;
100: } *hosts;
101:
1.14 millert 102: int
103: main(int argc, char **argv)
104: {
105: struct winsize win;
106: char *cp, *ep;
107: int ch;
108:
109: while ((ch = getopt(argc, argv, "al")) != -1)
110: switch (ch) {
111: case 'a':
112: allopt++;
113: break;
114: case 'l':
115: longopt++;
116: break;
117: default:
118: usage();
119: /*NOTREACHED*/
120: }
121:
122: if (isatty(STDOUT_FILENO)) {
123: if ((cp = getenv("COLUMNS")) != NULL && *cp != '\0') {
124: termwidth = strtol(cp, &ep, 10);
125: if (*ep != '\0' || termwidth >= INT_MAX ||
126: termwidth < 0)
127: termwidth = 0;
128: }
129: if (termwidth == 0 &&
130: ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
131: win.ws_col > 0)
132: termwidth = win.ws_col;
133: else
134: termwidth = 80;
135: }
136: setlinebuf(stdout);
137: if (argc == optind)
138: allhosts();
139: else {
140: for (; optind < argc; optind++)
141: (void) onehost(argv[optind]);
142: }
143: exit(0);
144: }
1.11 pjanzen 145:
1.1 deraadt 146: int
147: search_host(struct in_addr addr)
148: {
149: struct host_list *hp;
150:
151: if (!hosts)
152: return(0);
153:
154: for (hp = hosts; hp != NULL; hp = hp->next) {
155: if (hp->addr.s_addr == addr.s_addr)
156: return(1);
157: }
158: return(0);
159: }
160:
161: void
1.14 millert 162: remember_host(char **ap)
1.1 deraadt 163: {
164: struct host_list *hp;
165:
1.14 millert 166: for (; *ap; ap++) {
167: if (!(hp = malloc(sizeof(struct host_list))))
168: err(1, NULL);
169: hp->addr.s_addr = *(in_addr_t *)*ap;
170: hp->next = hosts;
171: hosts = hp;
172: }
173: }
174:
175: void
176: fmt_idle(int idle, char *idle_time, size_t idle_time_len)
177: {
178: int days, hours, minutes, seconds;
179:
180: switch (idle) {
181: case 0:
182: *idle_time = '\0';
183: break;
184: case INT_MAX:
185: strlcpy(idle_time, "??", idle_time_len);
186: break;
187: default:
188: seconds = idle;
189: days = seconds / (60*60*24);
190: seconds %= (60*60*24);
191: hours = seconds / (60*60);
192: seconds %= (60*60);
193: minutes = seconds / 60;
194: seconds %= 60;
195: if (idle >= (24*60*60))
196: snprintf(idle_time, idle_time_len,
197: "%d days, %d:%02d:%02d",
198: days, hours, minutes, seconds);
199: else if (idle >= (60*60))
200: snprintf(idle_time, idle_time_len, "%2d:%02d:%02d",
201: hours, minutes, seconds);
202: else if (idle > 60)
203: snprintf(idle_time, idle_time_len, "%2d:%02d",
204: minutes, seconds);
205: else
206: snprintf(idle_time, idle_time_len, " :%02d", idle);
207: break;
208: }
209: }
210:
211: void
212: print_longline(int ut_time, u_int idle, char *host, char *user, char *line,
213: char *remhost, int remhostmax)
214: {
215: char date[32], idle_time[64];
216: char remote[RUSERS_MAXHOSTLEN + 1];
217: int len;
218:
219: strftime(date, sizeof(date), "%h %d %R", localtime((time_t *)&ut_time));
220: date[sizeof(date) - 1] = '\0';
221: fmt_idle(idle, idle_time, sizeof(idle_time));
222: len = termwidth -
223: (MAX(strlen(user), NAME_WIDTH) + 1 + HOST_WIDTH + 1 + LINE_WIDTH +
224: 1 + strlen(date) + 1 + MAX(8, strlen(idle_time)) + 1 + 2);
225: if (len > 0 && *remhost != '\0')
226: snprintf(remote, sizeof(remote), "(%.*s)",
227: MIN(len, remhostmax), remhost);
228: else
229: remote[0] = '\0';
230: len = HOST_WIDTH - MIN(HOST_WIDTH, strlen(host)) +
231: LINE_WIDTH - MIN(LINE_WIDTH, strlen(line));
232: printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n",
233: NAME_WIDTH, user, HOST_WIDTH, host, LINE_WIDTH, line,
234: len, "", date, idle_time, remote);
1.1 deraadt 235: }
236:
1.15 ! millert 237: bool_t
1.1 deraadt 238: rusers_reply(char *replyp, struct sockaddr_in *raddrp)
239: {
1.14 millert 240: char user[RNUSERS_MAXUSERLEN + 1];
1.13 millert 241: char utline[RNUSERS_MAXLINELEN + 1];
1.14 millert 242: utmpidlearr *up = (utmpidlearr *)replyp;
1.1 deraadt 243: struct hostent *hp;
1.14 millert 244: char *host, *taddrs[2];
245: int i;
1.1 deraadt 246:
247: if (search_host(raddrp->sin_addr))
248: return(0);
249:
250: if (!allopt && !up->uia_cnt)
251: return(0);
252:
1.15 ! millert 253: hp = gethostbyaddr((char *)&raddrp->sin_addr,
1.14 millert 254: sizeof(struct in_addr), AF_INET);
255: if (hp) {
1.1 deraadt 256: host = hp->h_name;
1.14 millert 257: remember_host(hp->h_addr_list);
258: } else {
1.1 deraadt 259: host = inet_ntoa(raddrp->sin_addr);
1.14 millert 260: taddrs[0] = (char *)&raddrp->sin_addr;
261: taddrs[1] = NULL;
262: remember_host(taddrs);
263: }
1.1 deraadt 264:
265: if (!longopt)
266: printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host);
267:
1.14 millert 268: for (i = 0; i < up->uia_cnt; i++) {
269: /* NOTE: strncpy() used below for non-terminated strings. */
270: strncpy(user, up->uia_arr[i]->ui_utmp.ut_name,
271: sizeof(user) - 1);
272: user[sizeof(user) - 1] = '\0';
273: if (longopt) {
274: strncpy(utline, up->uia_arr[i]->ui_utmp.ut_line,
275: sizeof(utline) - 1);
276: utline[sizeof(utline) - 1] = '\0';
277: print_longline(up->uia_arr[i]->ui_utmp.ut_time,
278: up->uia_arr[i]->ui_idle, host, user, utline,
279: up->uia_arr[i]->ui_utmp.ut_host, RNUSERS_MAXHOSTLEN);
280: } else {
281: fputs(user, stdout);
282: putchar(' ');
283: }
284: }
285: if (!longopt)
286: putchar('\n');
287:
288: return(0);
289: }
1.1 deraadt 290:
1.15 ! millert 291: bool_t
1.14 millert 292: rusers_reply_3(char *replyp, struct sockaddr_in *raddrp)
293: {
294: char user[RUSERS_MAXUSERLEN + 1];
295: char utline[RUSERS_MAXLINELEN + 1];
296: utmp_array *up3 = (utmp_array *)replyp;
297: struct hostent *hp;
298: char *host, *taddrs[2];
299: int i;
300:
301: if (search_host(raddrp->sin_addr))
302: return(0);
1.1 deraadt 303:
1.14 millert 304: if (!allopt && !up3->utmp_array_len)
305: return(0);
1.15 ! millert 306:
! 307: hp = gethostbyaddr((char *)&raddrp->sin_addr,
1.14 millert 308: sizeof(struct in_addr), AF_INET);
309: if (hp) {
310: host = hp->h_name;
311: remember_host(hp->h_addr_list);
312: } else {
313: host = inet_ntoa(raddrp->sin_addr);
314: taddrs[0] = (char *)&raddrp->sin_addr;
315: taddrs[1] = NULL;
316: remember_host(taddrs);
317: }
318:
319: if (!longopt)
320: printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host);
321:
322: for (i = 0; i < up3->utmp_array_len; i++) {
323: /* NOTE: strncpy() used below for non-terminated strings. */
324: strncpy(user, up3->utmp_array_val[i].ut_user,
325: sizeof(user) - 1);
326: user[sizeof(user) - 1] = '\0';
1.1 deraadt 327: if (longopt) {
1.14 millert 328: strncpy(utline, up3->utmp_array_val[i].ut_line,
1.13 millert 329: sizeof(utline) - 1);
1.11 pjanzen 330: utline[sizeof(utline) - 1] = '\0';
1.14 millert 331: print_longline(up3->utmp_array_val[i].ut_time,
332: up3->utmp_array_val[i].ut_idle, host, user, utline,
333: up3->utmp_array_val[i].ut_host, RUSERS_MAXHOSTLEN);
334: } else {
335: fputs(user, stdout);
336: putchar(' ');
337: }
1.1 deraadt 338: }
339: if (!longopt)
340: putchar('\n');
341:
342: return(0);
343: }
344:
345: void
346: onehost(char *host)
347: {
1.4 deraadt 348: utmpidlearr up;
1.14 millert 349: utmp_array up3;
1.1 deraadt 350: CLIENT *rusers_clnt;
351: struct sockaddr_in addr;
352: struct hostent *hp;
1.14 millert 353: struct timeval tv = { 25, 0 };
354: int error;
1.1 deraadt 355:
356: hp = gethostbyname(host);
1.11 pjanzen 357: if (hp == NULL)
358: errx(1, "unknown host \"%s\"", host);
1.1 deraadt 359:
1.14 millert 360: /* try version 3 first */
361: rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_3, "udp");
362: if (rusers_clnt == NULL) {
363: clnt_pcreateerror(__progname);
364: exit(1);
365: }
366:
367: memset(&up3, 0, sizeof(up3));
368: error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,
369: xdr_utmp_array, &up3, tv);
370: switch (error) {
371: case RPC_SUCCESS:
372: addr.sin_addr.s_addr = *(int *)hp->h_addr;
373: rusers_reply_3((char *)&up3, &addr);
374: clnt_destroy(rusers_clnt);
375: return;
376: case RPC_PROGVERSMISMATCH:
377: clnt_destroy(rusers_clnt);
378: break;
379: default:
380: clnt_perror(rusers_clnt, __progname);
381: clnt_destroy(rusers_clnt);
382: exit(1);
383: }
384:
385: /* fall back to version 2 */
1.1 deraadt 386: rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
387: if (rusers_clnt == NULL) {
1.11 pjanzen 388: clnt_pcreateerror(__progname);
1.1 deraadt 389: exit(1);
390: }
391:
1.14 millert 392: memset(&up, 0, sizeof(up));
393: error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,
394: xdr_utmpidlearr, &up, tv);
395: if (error != RPC_SUCCESS) {
1.11 pjanzen 396: clnt_perror(rusers_clnt, __progname);
1.12 deraadt 397: clnt_destroy(rusers_clnt);
1.1 deraadt 398: exit(1);
399: }
400: addr.sin_addr.s_addr = *(int *)hp->h_addr;
401: rusers_reply((char *)&up, &addr);
1.12 deraadt 402: clnt_destroy(rusers_clnt);
1.1 deraadt 403: }
404:
405: void
406: allhosts(void)
407: {
1.4 deraadt 408: utmpidlearr up;
1.14 millert 409: utmp_array up3;
1.15 ! millert 410: enum clnt_stat clnt_stat;
1.14 millert 411:
1.15 ! millert 412: puts("Sending broadcast for rusersd protocol version 3...");
! 413: memset(&up3, 0, sizeof(up3));
! 414: clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_3,
! 415: RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmp_array,
! 416: (char *)&up3, rusers_reply_3);
! 417: if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
! 418: errx(1, "%s", clnt_sperrno(clnt_stat));
1.14 millert 419:
1.15 ! millert 420: puts("Sending broadcast for rusersd protocol version 2...");
! 421: memset(&up, 0, sizeof(up));
! 422: clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE,
! 423: RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr,
! 424: (char *)&up, rusers_reply);
! 425: if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
! 426: errx(1, "%s", clnt_sperrno(clnt_stat));
1.1 deraadt 427: }
428:
1.14 millert 429: void
430: usage(void)
1.1 deraadt 431: {
432:
1.14 millert 433: fprintf(stderr, "usage: %s [-la] [hosts ...]\n", __progname);
434: exit(1);
1.1 deraadt 435: }