rusers_proc.c revision 262435
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. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char rcsid[] =
32  "$FreeBSD: stable/10/libexec/rpc.rusersd/rusers_proc.c 262435 2014-02-24 08:21:49Z brueffer $";
33#endif /* not lint */
34
35#ifdef DEBUG
36#include <errno.h>
37#endif
38#include <stdio.h>
39#include <string.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42#include <stdlib.h>
43#include <syslog.h>
44#include <utmpx.h>
45#ifdef XIDLE
46#include <setjmp.h>
47#include <X11/Xlib.h>
48#include <X11/extensions/xidle.h>
49#endif
50#include <rpcsvc/rnusers.h>
51
52#include "extern.h"
53
54#ifndef _PATH_DEV
55#define _PATH_DEV "/dev"
56#endif
57
58static utmpidle utmp_idle[MAXUSERS];
59static utmp old_utmp[MAXUSERS];
60static struct utmpx utmp_list[MAXUSERS];
61
62#ifdef XIDLE
63static Display *dpy;
64
65static jmp_buf openAbort;
66
67static void
68abortOpen(void)
69{
70    longjmp (openAbort, 1);
71}
72
73XqueryIdle(char *display)
74{
75	int first_event, first_error;
76	Time IdleTime;
77
78	(void) signal (SIGALRM, abortOpen);
79	(void) alarm ((unsigned) 10);
80	if (!setjmp (openAbort)) {
81		if (!(dpy= XOpenDisplay(display))) {
82			syslog(LOG_ERR, "Cannot open display %s", display);
83			return(-1);
84		}
85		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
86			if (!XGetIdleTime(dpy, &IdleTime)) {
87				syslog(LOG_ERR, "%s: unable to get idle time", display);
88				return(-1);
89			}
90		} else {
91			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
92			return(-1);
93		}
94		XCloseDisplay(dpy);
95	} else {
96		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
97		return(-1);
98	}
99	(void) signal (SIGALRM, SIG_DFL);
100	(void) alarm ((unsigned) 0);
101
102	IdleTime /= 1000;
103	return((IdleTime + 30) / 60);
104}
105#endif
106
107static u_int
108getidle(const char *tty, const char *display __unused)
109{
110	struct stat st;
111	char ttyname[PATH_MAX];
112	time_t now;
113	u_long idle;
114
115	/*
116	 * If this is an X terminal or console, then try the
117	 * XIdle extension
118	 */
119#ifdef XIDLE
120	if (display && *display && (idle = XqueryIdle(display)) >= 0)
121		return(idle);
122#endif
123	idle = 0;
124	if (*tty == 'X') {
125		u_long kbd_idle, mouse_idle;
126#if	!defined(__FreeBSD__)
127		kbd_idle = getidle("kbd", NULL);
128#else
129		kbd_idle = getidle("vga", NULL);
130#endif
131		mouse_idle = getidle("mouse", NULL);
132		idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
133	} else {
134		sprintf(ttyname, "%s/%s", _PATH_DEV, tty);
135		if (stat(ttyname, &st) < 0) {
136#ifdef DEBUG
137			printf("%s: %s\n", ttyname, strerror(errno));
138#endif
139			return(-1);
140		}
141		time(&now);
142#ifdef DEBUG
143		printf("%s: now=%d atime=%d\n", ttyname, now,
144		       st.st_atime);
145#endif
146		idle = now - st.st_atime;
147		idle = (idle + 30) / 60; /* secs->mins */
148	}
149
150	return(idle);
151}
152
153static utmpidlearr *
154do_names_2(void)
155{
156	static utmpidlearr ut;
157	struct utmpx *usr;
158	int nusers = 0;
159
160	memset(&ut, 0, sizeof(ut));
161	ut.utmpidlearr_val = &utmp_idle[0];
162
163	setutxent();
164	while ((usr = getutxent()) != NULL && nusers < MAXUSERS) {
165		if (usr->ut_type != USER_PROCESS)
166			continue;
167
168		memcpy(&utmp_list[nusers], usr, sizeof(*usr));
169		utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec;
170		utmp_idle[nusers].ui_idle =
171		    getidle(usr->ut_line, usr->ut_host);
172		utmp_idle[nusers].ui_utmp.ut_line =
173		    utmp_list[nusers].ut_line;
174		utmp_idle[nusers].ui_utmp.ut_name =
175		    utmp_list[nusers].ut_user;
176		utmp_idle[nusers].ui_utmp.ut_host =
177		    utmp_list[nusers].ut_host;
178
179		nusers++;
180	}
181	endutxent();
182
183	ut.utmpidlearr_len = nusers;
184	return(&ut);
185}
186
187static int *
188rusers_num(void *argp __unused, struct svc_req *rqstp __unused)
189{
190	static int num_users = 0;
191	struct utmpx *usr;
192
193	setutxent();
194	while ((usr = getutxent()) != NULL) {
195		if (usr->ut_type != USER_PROCESS)
196			continue;
197		num_users++;
198	}
199	endutxent();
200
201	return(&num_users);
202}
203
204static utmparr *
205do_names_1(void)
206{
207	utmpidlearr *utidle;
208	static utmparr ut;
209	unsigned int i;
210
211	bzero((char *)&ut, sizeof(ut));
212
213	utidle = do_names_2();
214	if (utidle) {
215		ut.utmparr_len = utidle->utmpidlearr_len;
216		ut.utmparr_val = &old_utmp[0];
217		for (i = 0; i < ut.utmparr_len; i++)
218			bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
219			      sizeof(old_utmp[0]));
220
221	}
222
223	return(&ut);
224}
225
226utmpidlearr *
227rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
228{
229
230	return (do_names_2());
231}
232
233utmpidlearr *
234rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
235{
236
237	return (do_names_2());
238}
239
240utmparr *
241rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
242{
243
244	return (do_names_1());
245}
246
247utmparr *
248rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
249{
250
251	return (do_names_1());
252}
253
254typedef void *(*rusersproc_t)(void *, struct svc_req *);
255
256void
257rusers_service(struct svc_req *rqstp, SVCXPRT *transp)
258{
259	union {
260		int fill;
261	} argument;
262	char *result;
263	xdrproc_t xdr_argument, xdr_result;
264	rusersproc_t local;
265
266	switch (rqstp->rq_proc) {
267	case NULLPROC:
268		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
269		goto leave;
270
271	case RUSERSPROC_NUM:
272		xdr_argument = (xdrproc_t)xdr_void;
273		xdr_result = (xdrproc_t)xdr_int;
274		local = (rusersproc_t)rusers_num;
275		break;
276
277	case RUSERSPROC_NAMES:
278		xdr_argument = (xdrproc_t)xdr_void;
279		xdr_result = (xdrproc_t)xdr_utmpidlearr;
280		switch (rqstp->rq_vers) {
281		case RUSERSVERS_ORIG:
282			local = (rusersproc_t)rusersproc_names_1_svc;
283			break;
284		case RUSERSVERS_IDLE:
285			local = (rusersproc_t)rusersproc_names_2_svc;
286			break;
287		default:
288			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
289			goto leave;
290			/*NOTREACHED*/
291		}
292		break;
293
294	case RUSERSPROC_ALLNAMES:
295		xdr_argument = (xdrproc_t)xdr_void;
296		xdr_result = (xdrproc_t)xdr_utmpidlearr;
297		switch (rqstp->rq_vers) {
298		case RUSERSVERS_ORIG:
299			local = (rusersproc_t)rusersproc_allnames_1_svc;
300			break;
301		case RUSERSVERS_IDLE:
302			local = (rusersproc_t)rusersproc_allnames_2_svc;
303			break;
304		default:
305			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
306			goto leave;
307			/*NOTREACHED*/
308		}
309		break;
310
311	default:
312		svcerr_noproc(transp);
313		goto leave;
314	}
315	bzero(&argument, sizeof(argument));
316	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
317		svcerr_decode(transp);
318		goto leave;
319	}
320	result = (*local)(&argument, rqstp);
321	if (result != NULL &&
322	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
323		svcerr_systemerr(transp);
324	}
325	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
326		syslog(LOG_ERR, "unable to free arguments");
327		exit(1);
328	}
329leave:
330	if (from_inetd)
331		exit(0);
332}
333