1 /*	$OpenBSD: rusers_proc.c,v 1.21 2004/11/04 20:09:18 deraadt Exp $	*/
2 
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. 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 BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <paths.h>
36 #include <utmp.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <rpc/rpc.h>
43 #include <rpcsvc/rusers.h>	/* New version */
44 #include <rpcsvc/rnusers.h>	/* Old version */
45 
46 __RCSID("$MirOS: src/libexec/rpc.rusersd/rusers_proc.c,v 1.2 2006/09/21 02:10:54 tg Exp $");
47 
48 extern int utmp_fd;
49 
50 typedef char ut_line_t[UT_LINESIZE+1];
51 typedef char ut_name_t[UT_NAMESIZE+1];
52 typedef char ut_host_t[UT_HOSTSIZE+1];
53 
54 struct rusers_utmp utmps[MAXUSERS];
55 struct utmpidle *utmp_idlep[MAXUSERS];
56 struct utmpidle utmp_idle[MAXUSERS];
57 struct ru_utmp *ru_utmpp[MAXUSERS];
58 struct ru_utmp ru_utmp[MAXUSERS];
59 ut_line_t line[MAXUSERS];
60 ut_name_t name[MAXUSERS];
61 ut_host_t host[MAXUSERS];
62 
63 int *rusers_num_svc(void *, struct svc_req *);
64 struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *);
65 struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *);
66 struct utmparr *rusersproc_names_1_svc(void *, struct svc_req *);
67 struct utmparr *rusersproc_allnames_1_svc(void *, struct svc_req *);
68 void rusers_service(struct svc_req *, SVCXPRT *);
69 
70 extern int from_inetd;
71 
72 FILE *ufp;
73 
74 static long
getidle(char * tty)75 getidle(char *tty)
76 {
77 	char devname[PATH_MAX];
78 	struct stat st;
79 	long idle;
80 	time_t now;
81 
82 	idle = 0;
83 	if (*tty == 'X') {
84 		long kbd_idle, mouse_idle;
85 #if !defined(__i386__)
86 		kbd_idle = getidle("kbd");
87 #else
88 		/*
89 		 * XXX Icky i386 console hack.
90 		 */
91 		kbd_idle = getidle("vga");
92 #endif
93 		mouse_idle = getidle("mouse");
94 		idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle;
95 	} else {
96 		snprintf(devname, sizeof devname, "%s/%.*s", _PATH_DEV,
97 		    (int)sizeof (tty), tty);
98 		if (stat(devname, &st) < 0) {
99 #ifdef DEBUG
100 			printf("%s: %m\n", devname);
101 #endif
102 			return (0);
103 		}
104 		time(&now);
105 #ifdef DEBUG
106 		printf("%s: now=%d atime=%d\n", devname, now, st.st_atime);
107 #endif
108 		idle = now - st.st_atime;
109 		idle = (idle + 30) / 60; /* secs->mins */
110 	}
111 	if (idle < 0)
112 		idle = 0;
113 
114 	return (idle);
115 }
116 
117 int *
rusers_num_svc(void * arg,struct svc_req * rqstp)118 rusers_num_svc(void *arg, struct svc_req *rqstp)
119 {
120 	static int num_users = 0;
121 	struct utmp usr;
122 	int fd;
123 
124 	fd = dup(utmp_fd);
125 	if (fd == -1) {
126 		syslog(LOG_ERR, "%m");
127 		return (0);
128 	}
129 	lseek(fd, (off_t)0, SEEK_SET);
130 	ufp = fdopen(fd, "r");
131 	if (!ufp) {
132 		close(fd);
133 		syslog(LOG_ERR, "%m");
134 		return (0);
135 	}
136 
137 	/* only entries with both name and line fields */
138 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
139 		if (*usr.ut_name && *usr.ut_line)
140 			num_users++;
141 
142 	fclose(ufp);
143 	return (&num_users);
144 }
145 
146 static utmp_array *
do_names_3(int all)147 do_names_3(int all)
148 {
149 	static utmp_array ut;
150 	struct utmp usr;
151 	int fd, nusers = 0;
152 
153 	bzero((char *)&ut, sizeof(ut));
154 	ut.utmp_array_val = &utmps[0];
155 
156 	fd = dup(utmp_fd);
157 	if (fd == -1) {
158 		syslog(LOG_ERR, "%m");
159 		return (0);
160 	}
161 	lseek(fd, (off_t)0, SEEK_SET);
162 	ufp = fdopen(fd, "r");
163 	if (!ufp) {
164 		close(fd);
165 		syslog(LOG_ERR, "%m");
166 		return (NULL);
167 	}
168 
169 	/* only entries with both name and line fields */
170 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
171 	    nusers < MAXUSERS)
172 		if (*usr.ut_name && *usr.ut_line) {
173 			utmps[nusers].ut_type = RUSERS_USER_PROCESS;
174 			utmps[nusers].ut_time = usr.ut_time;
175 			utmps[nusers].ut_idle = getidle(usr.ut_line);
176 			utmps[nusers].ut_line = line[nusers];
177 			memset(line[nusers], 0, sizeof(line[nusers]));
178 			memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
179 			line[nusers][UT_LINESIZE] = '\0';
180 			utmps[nusers].ut_user = name[nusers];
181 			memset(name[nusers], 0, sizeof(name[nusers]));
182 			memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
183 			name[nusers][UT_NAMESIZE] = '\0';
184 			utmps[nusers].ut_host = host[nusers];
185 			memset(host[nusers], 0, sizeof(host[nusers]));
186 			memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
187 			host[nusers][UT_HOSTSIZE] = '\0';
188 			nusers++;
189 		}
190 	ut.utmp_array_len = nusers;
191 
192 	fclose(ufp);
193 	return (&ut);
194 }
195 
196 utmp_array *
rusersproc_names_3_svc(void * arg,struct svc_req * rqstp)197 rusersproc_names_3_svc(void *arg, struct svc_req *rqstp)
198 {
199 	return (do_names_3(0));
200 }
201 
202 utmp_array *
rusersproc_allnames_3_svc(void * arg,struct svc_req * rqstp)203 rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp)
204 {
205 	return (do_names_3(1));
206 }
207 
208 static struct utmpidlearr *
do_names_2(int all)209 do_names_2(int all)
210 {
211 	static struct utmpidlearr ut;
212 	struct utmp usr;
213 	int fd, nusers = 0;
214 
215 	bzero((char *)&ut, sizeof(ut));
216 	ut.uia_arr = utmp_idlep;
217 	ut.uia_cnt = 0;
218 
219 	fd = dup(utmp_fd);
220 	if (fd == -1) {
221 		syslog(LOG_ERR, "%m");
222 		return (0);
223 	}
224 	lseek(fd, (off_t)0, SEEK_SET);
225 	ufp = fdopen(fd, "r");
226 	if (!ufp) {
227 		close(fd);
228 		syslog(LOG_ERR, "%m");
229 		return (NULL);
230 	}
231 
232 	/* only entries with both name and line fields */
233 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
234 	    nusers < MAXUSERS)
235 		if (*usr.ut_name && *usr.ut_line) {
236 			utmp_idlep[nusers] = &utmp_idle[nusers];
237 			utmp_idle[nusers].ui_utmp.ut_time = usr.ut_time;
238 			utmp_idle[nusers].ui_idle = getidle(usr.ut_line);
239 			utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
240 			memset(line[nusers], 0, sizeof(line[nusers]));
241 			memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
242 			line[nusers][UT_LINESIZE] = '\0';
243 			utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
244 			memset(name[nusers], 0, sizeof(name[nusers]));
245 			memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
246 			name[nusers][UT_NAMESIZE] = '\0';
247 			utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
248 			memset(host[nusers], 0, sizeof(host[nusers]));
249 			memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
250 			host[nusers][UT_HOSTSIZE] = '\0';
251 			nusers++;
252 		}
253 
254 	ut.uia_cnt = nusers;
255 	fclose(ufp);
256 	return (&ut);
257 }
258 
259 struct utmpidlearr *
rusersproc_names_2_svc(void * arg,struct svc_req * rqstp)260 rusersproc_names_2_svc(void *arg, struct svc_req *rqstp)
261 {
262 	return (do_names_2(0));
263 }
264 
265 struct utmpidlearr *
rusersproc_allnames_2_svc(void * arg,struct svc_req * rqstp)266 rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp)
267 {
268 	return (do_names_2(1));
269 }
270 
271 static struct utmparr *
do_names_1(int all)272 do_names_1(int all)
273 {
274 	static struct utmparr ut;
275 	struct utmp usr;
276 	int fd, nusers = 0;
277 
278 	bzero((char *)&ut, sizeof(ut));
279 	ut.uta_arr = ru_utmpp;
280 	ut.uta_cnt = 0;
281 
282 	fd = dup(utmp_fd);
283 	if (fd == -1) {
284 		syslog(LOG_ERR, "%m");
285 		return (0);
286 	}
287 	lseek(fd, (off_t)0, SEEK_SET);
288 	ufp = fdopen(fd, "r");
289 	if (!ufp) {
290 		close(fd);
291 		syslog(LOG_ERR, "%m");
292 		return (NULL);
293 	}
294 
295 	/* only entries with both name and line fields */
296 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
297 	    nusers < MAXUSERS)
298 		if (*usr.ut_name && *usr.ut_line) {
299 			ru_utmpp[nusers] = &ru_utmp[nusers];
300 			ru_utmp[nusers].ut_time = usr.ut_time;
301 			ru_utmp[nusers].ut_line = line[nusers];
302 			memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
303 			line[nusers][UT_LINESIZE] = '\0';
304 			ru_utmp[nusers].ut_name = name[nusers];
305 			memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
306 			name[nusers][UT_NAMESIZE] = '\0';
307 			ru_utmp[nusers].ut_host = host[nusers];
308 			memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
309 			host[nusers][UT_HOSTSIZE] = '\0';
310 			nusers++;
311 		}
312 
313 	ut.uta_cnt = nusers;
314 	fclose(ufp);
315 	return (&ut);
316 }
317 
318 struct utmparr *
rusersproc_names_1_svc(void * arg,struct svc_req * rqstp)319 rusersproc_names_1_svc(void *arg, struct svc_req *rqstp)
320 {
321 	return (do_names_1(0));
322 }
323 
324 struct utmparr *
rusersproc_allnames_1_svc(void * arg,struct svc_req * rqstp)325 rusersproc_allnames_1_svc(void *arg, struct svc_req *rqstp)
326 {
327 	return (do_names_1(1));
328 }
329 
330 void
rusers_service(struct svc_req * rqstp,SVCXPRT * transp)331 rusers_service(struct svc_req *rqstp, SVCXPRT *transp)
332 {
333 	char *(*local)(void *, struct svc_req *);
334 	xdrproc_t xdr_argument, xdr_result;
335 	union {
336 		int fill;
337 	} argument;
338 	char *result;
339 
340 	switch (rqstp->rq_proc) {
341 	case NULLPROC:
342 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
343 		goto leave;
344 
345 	case RUSERSPROC_NUM:
346 		xdr_argument = (xdrproc_t)xdr_void;
347 		xdr_result = (xdrproc_t)xdr_int;
348 		switch (rqstp->rq_vers) {
349 		case RUSERSVERS_3:
350 		case RUSERSVERS_IDLE:
351 		case RUSERSVERS_ORIG:
352 			local = (char *(*)(void *, struct svc_req *))
353 			    rusers_num_svc;
354 			break;
355 		default:
356 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
357 			goto leave;
358 			/*NOTREACHED*/
359 		}
360 		break;
361 
362 	case RUSERSPROC_NAMES:
363 		xdr_argument = (xdrproc_t)xdr_void;
364 		xdr_result = (xdrproc_t)xdr_utmp_array;
365 		switch (rqstp->rq_vers) {
366 		case RUSERSVERS_3:
367 			local = (char *(*)(void *, struct svc_req *))
368 			    rusersproc_names_3_svc;
369 			break;
370 
371 		case RUSERSVERS_IDLE:
372 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
373 			local = (char *(*)(void *, struct svc_req *))
374 			    rusersproc_names_2_svc;
375 			break;
376 
377 		case RUSERSVERS_ORIG:
378 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
379 			local = (char *(*)(void *, struct svc_req *))
380 			    rusersproc_names_1_svc;
381 			break;
382 
383 		default:
384 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
385 			goto leave;
386 			/*NOTREACHED*/
387 		}
388 		break;
389 
390 	case RUSERSPROC_ALLNAMES:
391 		xdr_argument = (xdrproc_t)xdr_void;
392 		xdr_result = (xdrproc_t)xdr_utmp_array;
393 		switch (rqstp->rq_vers) {
394 		case RUSERSVERS_3:
395 			local = (char *(*)(void *, struct svc_req *))
396 			    rusersproc_allnames_3_svc;
397 			break;
398 
399 		case RUSERSVERS_IDLE:
400 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
401 			local = (char *(*)(void *, struct svc_req *))
402 			    rusersproc_allnames_2_svc;
403 			break;
404 
405 		case RUSERSVERS_ORIG:
406 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
407 			local = (char *(*)(void *, struct svc_req *))
408 			    rusersproc_allnames_1_svc;
409 			break;
410 
411 		default:
412 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
413 			goto leave;
414 			/*NOTREACHED*/
415 		}
416 		break;
417 
418 	default:
419 		svcerr_noproc(transp);
420 		goto leave;
421 	}
422 	bzero((char *)&argument, sizeof(argument));
423 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
424 		svcerr_decode(transp);
425 		goto leave;
426 	}
427 	result = (*local)(&argument, rqstp);
428 	if (result != NULL && !svc_sendreply(transp, xdr_result, result))
429 		svcerr_systemerr(transp);
430 
431 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
432 		syslog(LOG_ERR, "unable to free arguments");
433 		exit(1);
434 	}
435 leave:
436 	if (from_inetd)
437 		exit(0);
438 }
439