12337Scsgr/*-
22337Scsgr * Copyright (c) 1993, John Brezak
32337Scsgr * All rights reserved.
42337Scsgr *
52337Scsgr * Redistribution and use in source and binary forms, with or without
62337Scsgr * modification, are permitted provided that the following conditions
72337Scsgr * are met:
82337Scsgr * 1. Redistributions of source code must retain the above copyright
92337Scsgr *    notice, this list of conditions and the following disclaimer.
102337Scsgr * 2. Redistributions in binary form must reproduce the above copyright
112337Scsgr *    notice, this list of conditions and the following disclaimer in the
122337Scsgr *    documentation and/or other materials provided with the distribution.
13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors
142337Scsgr *    may be used to endorse or promote products derived from this software
152337Scsgr *    without specific prior written permission.
162337Scsgr *
172337Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
182337Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
192337Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202337Scsgr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
212337Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222337Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232337Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242337Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252337Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262337Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272337Scsgr * SUCH DAMAGE.
282337Scsgr */
292337Scsgr
302337Scsgr#ifndef lint
3131422Scharnierstatic const char rcsid[] =
3250476Speter  "$FreeBSD$";
332337Scsgr#endif /* not lint */
342337Scsgr
3532312Scharnier#ifdef DEBUG
3632312Scharnier#include <errno.h>
3732312Scharnier#endif
382337Scsgr#include <stdio.h>
3931422Scharnier#include <string.h>
4031422Scharnier#include <sys/param.h>
412337Scsgr#include <sys/stat.h>
42115668Sobrien#include <stdlib.h>
4331422Scharnier#include <syslog.h>
44202210Sed#include <utmpx.h>
452337Scsgr#ifdef XIDLE
462337Scsgr#include <setjmp.h>
472337Scsgr#include <X11/Xlib.h>
482337Scsgr#include <X11/extensions/xidle.h>
492337Scsgr#endif
502337Scsgr#include <rpcsvc/rnusers.h>
512337Scsgr
52241777Sed#include "extern.h"
53241777Sed
542337Scsgr#ifndef _PATH_DEV
552337Scsgr#define _PATH_DEV "/dev"
562337Scsgr#endif
572337Scsgr
58201146Sedstatic utmpidle utmp_idle[MAXUSERS];
59201192Sedstatic utmp old_utmp[MAXUSERS];
60201192Sedstatic struct utmpx utmp_list[MAXUSERS];
612337Scsgr
622337Scsgr#ifdef XIDLE
63201146Sedstatic Display *dpy;
642337Scsgr
652337Scsgrstatic jmp_buf openAbort;
662337Scsgr
672337Scsgrstatic void
6890336SimpabortOpen(void)
692337Scsgr{
702337Scsgr    longjmp (openAbort, 1);
712337Scsgr}
722337Scsgr
732337ScsgrXqueryIdle(char *display)
742337Scsgr{
75201146Sed	int first_event, first_error;
76201146Sed	Time IdleTime;
772337Scsgr
78201146Sed	(void) signal (SIGALRM, abortOpen);
79201146Sed	(void) alarm ((unsigned) 10);
80201146Sed	if (!setjmp (openAbort)) {
81201146Sed		if (!(dpy= XOpenDisplay(display))) {
82201146Sed			syslog(LOG_ERR, "Cannot open display %s", display);
83201146Sed			return(-1);
84201146Sed		}
85201146Sed		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
86201146Sed			if (!XGetIdleTime(dpy, &IdleTime)) {
87201146Sed				syslog(LOG_ERR, "%s: unable to get idle time", display);
88201146Sed				return(-1);
89201146Sed			}
90201146Sed		} else {
91201146Sed			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
92201146Sed			return(-1);
93201146Sed		}
94201146Sed		XCloseDisplay(dpy);
95201146Sed	} else {
96201146Sed		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
97201146Sed		return(-1);
98201146Sed	}
99201146Sed	(void) signal (SIGALRM, SIG_DFL);
100201146Sed	(void) alarm ((unsigned) 0);
1012337Scsgr
102201146Sed	IdleTime /= 1000;
103201146Sed	return((IdleTime + 30) / 60);
1042337Scsgr}
1052337Scsgr#endif
1062337Scsgr
1072337Scsgrstatic u_int
108201146Sedgetidle(const char *tty, const char *display __unused)
1092337Scsgr{
110201146Sed	struct stat st;
111201146Sed	char ttyname[PATH_MAX];
112201146Sed	time_t now;
113201146Sed	u_long idle;
1148870Srgrimes
115201146Sed	/*
116201146Sed	 * If this is an X terminal or console, then try the
117201146Sed	 * XIdle extension
118201146Sed	 */
1192337Scsgr#ifdef XIDLE
120201146Sed	if (display && *display && (idle = XqueryIdle(display)) >= 0)
121201146Sed		return(idle);
1222337Scsgr#endif
123201146Sed	idle = 0;
124201146Sed	if (*tty == 'X') {
125201146Sed		u_long kbd_idle, mouse_idle;
1264131Sjkh#if	!defined(__FreeBSD__)
127201146Sed		kbd_idle = getidle("kbd", NULL);
1282337Scsgr#else
129201146Sed		kbd_idle = getidle("vga", NULL);
1302337Scsgr#endif
131201146Sed		mouse_idle = getidle("mouse", NULL);
132201146Sed		idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
133201146Sed	} else {
134201146Sed		sprintf(ttyname, "%s/%s", _PATH_DEV, tty);
135201146Sed		if (stat(ttyname, &st) < 0) {
1362337Scsgr#ifdef DEBUG
137201146Sed			printf("%s: %s\n", ttyname, strerror(errno));
1382337Scsgr#endif
139201146Sed			return(-1);
140201146Sed		}
141201146Sed		time(&now);
1422337Scsgr#ifdef DEBUG
143201146Sed		printf("%s: now=%d atime=%d\n", ttyname, now,
144201146Sed		       st.st_atime);
1452337Scsgr#endif
146201146Sed		idle = now - st.st_atime;
147201146Sed		idle = (idle + 30) / 60; /* secs->mins */
148201146Sed	}
1492337Scsgr
150201146Sed	return(idle);
1512337Scsgr}
1528870Srgrimes
1532337Scsgrstatic utmpidlearr *
154201146Seddo_names_2(void)
1552337Scsgr{
156201146Sed	static utmpidlearr ut;
157201192Sed	struct utmpx *usr;
158201146Sed	int nusers = 0;
1598870Srgrimes
160201192Sed	memset(&ut, 0, sizeof(ut));
161201146Sed	ut.utmpidlearr_val = &utmp_idle[0];
1628870Srgrimes
163201192Sed	setutxent();
164201192Sed	while ((usr = getutxent()) != NULL && nusers < MAXUSERS) {
165201192Sed		if (usr->ut_type != USER_PROCESS)
166201192Sed			continue;
1672337Scsgr
168201192Sed		memcpy(&utmp_list[nusers], usr, sizeof(*usr));
169201192Sed		utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec;
170201192Sed		utmp_idle[nusers].ui_idle =
171201192Sed		    getidle(usr->ut_line, usr->ut_host);
172201192Sed		utmp_idle[nusers].ui_utmp.ut_line =
173201192Sed		    utmp_list[nusers].ut_line;
174201192Sed		utmp_idle[nusers].ui_utmp.ut_name =
175201192Sed		    utmp_list[nusers].ut_user;
176201192Sed		utmp_idle[nusers].ui_utmp.ut_host =
177201192Sed		    utmp_list[nusers].ut_host;
1788870Srgrimes
179201192Sed		nusers++;
180201192Sed	}
181201192Sed	endutxent();
1822337Scsgr
183201146Sed	ut.utmpidlearr_len = nusers;
184201146Sed	return(&ut);
1852337Scsgr}
1862337Scsgr
187201146Sedstatic int *
188201146Sedrusers_num(void *argp __unused, struct svc_req *rqstp __unused)
1892337Scsgr{
190201146Sed	static int num_users = 0;
191201192Sed	struct utmpx *usr;
192201192Sed
193201192Sed	setutxent();
194201192Sed	while ((usr = getutxent()) != NULL) {
195201192Sed		if (usr->ut_type != USER_PROCESS)
196201192Sed			continue;
197201192Sed		num_users++;
198201146Sed	}
199201192Sed	endutxent();
200201192Sed
201201146Sed	return(&num_users);
2022337Scsgr}
2032337Scsgr
2042337Scsgrstatic utmparr *
205201146Seddo_names_1(void)
2062337Scsgr{
207201146Sed	utmpidlearr *utidle;
208201146Sed	static utmparr ut;
209201146Sed	unsigned int i;
2108870Srgrimes
211201146Sed	bzero((char *)&ut, sizeof(ut));
2128870Srgrimes
213201146Sed	utidle = do_names_2();
214201146Sed	if (utidle) {
215201146Sed		ut.utmparr_len = utidle->utmpidlearr_len;
216201146Sed		ut.utmparr_val = &old_utmp[0];
217201146Sed		for (i = 0; i < ut.utmparr_len; i++)
218201146Sed			bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
219201146Sed			      sizeof(old_utmp[0]));
2208870Srgrimes
221201146Sed	}
2228870Srgrimes
223201146Sed	return(&ut);
2242337Scsgr}
2252337Scsgr
2262337Scsgrutmpidlearr *
227201146Sedrusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2282337Scsgr{
229201146Sed
230201146Sed	return (do_names_2());
2312337Scsgr}
2322337Scsgr
2332337Scsgrutmpidlearr *
234201146Sedrusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2352337Scsgr{
236201146Sed
237201146Sed	return (do_names_2());
2382337Scsgr}
2392337Scsgr
2402337Scsgrutmparr *
241201146Sedrusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
2422337Scsgr{
243201146Sed
244201146Sed	return (do_names_1());
2452337Scsgr}
2462337Scsgr
2472337Scsgrutmparr *
248201146Sedrusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
2492337Scsgr{
250201146Sed
251201146Sed	return (do_names_1());
2522337Scsgr}
2532337Scsgr
254201146Sedtypedef void *(*rusersproc_t)(void *, struct svc_req *);
255201146Sed
2562337Scsgrvoid
25790336Simprusers_service(struct svc_req *rqstp, SVCXPRT *transp)
2582337Scsgr{
2592337Scsgr	union {
2602337Scsgr		int fill;
2612337Scsgr	} argument;
2622337Scsgr	char *result;
263201146Sed	xdrproc_t xdr_argument, xdr_result;
264201146Sed	rusersproc_t local;
2652337Scsgr
2662337Scsgr	switch (rqstp->rq_proc) {
2672337Scsgr	case NULLPROC:
26895658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
2692337Scsgr		goto leave;
2702337Scsgr
2712337Scsgr	case RUSERSPROC_NUM:
272201146Sed		xdr_argument = (xdrproc_t)xdr_void;
273201146Sed		xdr_result = (xdrproc_t)xdr_int;
274201146Sed		local = (rusersproc_t)rusers_num;
2752337Scsgr		break;
2762337Scsgr
2772337Scsgr	case RUSERSPROC_NAMES:
278201146Sed		xdr_argument = (xdrproc_t)xdr_void;
279201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
280201146Sed		switch (rqstp->rq_vers) {
281201146Sed		case RUSERSVERS_ORIG:
282201146Sed			local = (rusersproc_t)rusersproc_names_1_svc;
283201146Sed			break;
284201146Sed		case RUSERSVERS_IDLE:
285201146Sed			local = (rusersproc_t)rusersproc_names_2_svc;
286201146Sed			break;
287201146Sed		default:
288201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
289201146Sed			goto leave;
290201146Sed			/*NOTREACHED*/
291201146Sed		}
2922337Scsgr		break;
2932337Scsgr
2942337Scsgr	case RUSERSPROC_ALLNAMES:
295201146Sed		xdr_argument = (xdrproc_t)xdr_void;
296201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
297201146Sed		switch (rqstp->rq_vers) {
298201146Sed		case RUSERSVERS_ORIG:
299201146Sed			local = (rusersproc_t)rusersproc_allnames_1_svc;
300201146Sed			break;
301201146Sed		case RUSERSVERS_IDLE:
302201146Sed			local = (rusersproc_t)rusersproc_allnames_2_svc;
303201146Sed			break;
304201146Sed		default:
305201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
306201146Sed			goto leave;
307201146Sed			/*NOTREACHED*/
308201146Sed		}
3092337Scsgr		break;
3102337Scsgr
3112337Scsgr	default:
3122337Scsgr		svcerr_noproc(transp);
3132337Scsgr		goto leave;
3142337Scsgr	}
31595658Sdes	bzero(&argument, sizeof(argument));
31695658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
3172337Scsgr		svcerr_decode(transp);
3182337Scsgr		goto leave;
3192337Scsgr	}
3202337Scsgr	result = (*local)(&argument, rqstp);
32195658Sdes	if (result != NULL &&
32295658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
3232337Scsgr		svcerr_systemerr(transp);
3242337Scsgr	}
32595658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
32632312Scharnier		syslog(LOG_ERR, "unable to free arguments");
32732312Scharnier		exit(1);
32832312Scharnier	}
3292337Scsgrleave:
330201146Sed	if (from_inetd)
331201146Sed		exit(0);
3322337Scsgr}
333