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