rusers_proc.c revision 201192
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.
132337Scsgr * 3. All advertising materials mentioning features or use of this software
142337Scsgr *    must display the following acknowledgement:
152337Scsgr *	This product includes software developed by the University of
162337Scsgr *	California, Berkeley and its contributors.
172337Scsgr * 4. Neither the name of the University nor the names of its contributors
182337Scsgr *    may be used to endorse or promote products derived from this software
192337Scsgr *    without specific prior written permission.
202337Scsgr *
212337Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222337Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232337Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242337Scsgr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
252337Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
262337Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
272337Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
282337Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
292337Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302337Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312337Scsgr * SUCH DAMAGE.
322337Scsgr */
332337Scsgr
342337Scsgr#ifndef lint
3531422Scharnierstatic const char rcsid[] =
3650476Speter  "$FreeBSD: head/libexec/rpc.rusersd/rusers_proc.c 201192 2009-12-29 10:28:20Z ed $";
372337Scsgr#endif /* not lint */
382337Scsgr
3932312Scharnier#ifdef DEBUG
4032312Scharnier#include <errno.h>
4132312Scharnier#endif
422337Scsgr#include <stdio.h>
4331422Scharnier#include <string.h>
4431422Scharnier#include <sys/param.h>
452337Scsgr#include <sys/stat.h>
46115668Sobrien#include <stdlib.h>
4731422Scharnier#include <syslog.h>
48201192Sed#define	_ULOG_POSIX_NAMES
49201192Sed#include <ulog.h>
502337Scsgr#ifdef XIDLE
512337Scsgr#include <setjmp.h>
522337Scsgr#include <X11/Xlib.h>
532337Scsgr#include <X11/extensions/xidle.h>
542337Scsgr#endif
552337Scsgr#include <rpcsvc/rnusers.h>
562337Scsgr
572337Scsgr#ifndef _PATH_DEV
582337Scsgr#define _PATH_DEV "/dev"
592337Scsgr#endif
602337Scsgr
61201146Sedstatic utmpidle utmp_idle[MAXUSERS];
62201192Sedstatic utmp old_utmp[MAXUSERS];
63201192Sedstatic struct utmpx utmp_list[MAXUSERS];
642337Scsgr
652337Scsgrextern int from_inetd;
662337Scsgr
67201146Sedvoid rusers_service(struct svc_req *, SVCXPRT *);
682337Scsgr
692337Scsgr#ifdef XIDLE
70201146Sedstatic Display *dpy;
712337Scsgr
722337Scsgrstatic jmp_buf openAbort;
732337Scsgr
742337Scsgrstatic void
7590336SimpabortOpen(void)
762337Scsgr{
772337Scsgr    longjmp (openAbort, 1);
782337Scsgr}
792337Scsgr
802337ScsgrXqueryIdle(char *display)
812337Scsgr{
82201146Sed	int first_event, first_error;
83201146Sed	Time IdleTime;
842337Scsgr
85201146Sed	(void) signal (SIGALRM, abortOpen);
86201146Sed	(void) alarm ((unsigned) 10);
87201146Sed	if (!setjmp (openAbort)) {
88201146Sed		if (!(dpy= XOpenDisplay(display))) {
89201146Sed			syslog(LOG_ERR, "Cannot open display %s", display);
90201146Sed			return(-1);
91201146Sed		}
92201146Sed		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
93201146Sed			if (!XGetIdleTime(dpy, &IdleTime)) {
94201146Sed				syslog(LOG_ERR, "%s: unable to get idle time", display);
95201146Sed				return(-1);
96201146Sed			}
97201146Sed		} else {
98201146Sed			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
99201146Sed			return(-1);
100201146Sed		}
101201146Sed		XCloseDisplay(dpy);
102201146Sed	} else {
103201146Sed		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
104201146Sed		return(-1);
105201146Sed	}
106201146Sed	(void) signal (SIGALRM, SIG_DFL);
107201146Sed	(void) alarm ((unsigned) 0);
1082337Scsgr
109201146Sed	IdleTime /= 1000;
110201146Sed	return((IdleTime + 30) / 60);
1112337Scsgr}
1122337Scsgr#endif
1132337Scsgr
1142337Scsgrstatic u_int
115201146Sedgetidle(const char *tty, const char *display __unused)
1162337Scsgr{
117201146Sed	struct stat st;
118201146Sed	char ttyname[PATH_MAX];
119201146Sed	time_t now;
120201146Sed	u_long idle;
1218870Srgrimes
122201146Sed	/*
123201146Sed	 * If this is an X terminal or console, then try the
124201146Sed	 * XIdle extension
125201146Sed	 */
1262337Scsgr#ifdef XIDLE
127201146Sed	if (display && *display && (idle = XqueryIdle(display)) >= 0)
128201146Sed		return(idle);
1292337Scsgr#endif
130201146Sed	idle = 0;
131201146Sed	if (*tty == 'X') {
132201146Sed		u_long kbd_idle, mouse_idle;
1334131Sjkh#if	!defined(__FreeBSD__)
134201146Sed		kbd_idle = getidle("kbd", NULL);
1352337Scsgr#else
136201146Sed		kbd_idle = getidle("vga", NULL);
1372337Scsgr#endif
138201146Sed		mouse_idle = getidle("mouse", NULL);
139201146Sed		idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
140201146Sed	} else {
141201146Sed		sprintf(ttyname, "%s/%s", _PATH_DEV, tty);
142201146Sed		if (stat(ttyname, &st) < 0) {
1432337Scsgr#ifdef DEBUG
144201146Sed			printf("%s: %s\n", ttyname, strerror(errno));
1452337Scsgr#endif
146201146Sed			return(-1);
147201146Sed		}
148201146Sed		time(&now);
1492337Scsgr#ifdef DEBUG
150201146Sed		printf("%s: now=%d atime=%d\n", ttyname, now,
151201146Sed		       st.st_atime);
1522337Scsgr#endif
153201146Sed		idle = now - st.st_atime;
154201146Sed		idle = (idle + 30) / 60; /* secs->mins */
155201146Sed	}
1562337Scsgr
157201146Sed	return(idle);
1582337Scsgr}
1598870Srgrimes
1602337Scsgrstatic utmpidlearr *
161201146Seddo_names_2(void)
1622337Scsgr{
163201146Sed	static utmpidlearr ut;
164201192Sed	struct utmpx *usr;
165201146Sed	int nusers = 0;
1668870Srgrimes
167201192Sed	memset(&ut, 0, sizeof(ut));
168201146Sed	ut.utmpidlearr_val = &utmp_idle[0];
1698870Srgrimes
170201192Sed	setutxent();
171201192Sed	while ((usr = getutxent()) != NULL && nusers < MAXUSERS) {
172201192Sed		if (usr->ut_type != USER_PROCESS)
173201192Sed			continue;
1742337Scsgr
175201192Sed		memcpy(&utmp_list[nusers], usr, sizeof(*usr));
176201192Sed		utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec;
177201192Sed		utmp_idle[nusers].ui_idle =
178201192Sed		    getidle(usr->ut_line, usr->ut_host);
179201192Sed		utmp_idle[nusers].ui_utmp.ut_line =
180201192Sed		    utmp_list[nusers].ut_line;
181201192Sed		utmp_idle[nusers].ui_utmp.ut_name =
182201192Sed		    utmp_list[nusers].ut_user;
183201192Sed		utmp_idle[nusers].ui_utmp.ut_host =
184201192Sed		    utmp_list[nusers].ut_host;
1858870Srgrimes
186201192Sed		nusers++;
187201192Sed	}
188201192Sed	endutxent();
1892337Scsgr
190201146Sed	ut.utmpidlearr_len = nusers;
191201146Sed	return(&ut);
1922337Scsgr}
1932337Scsgr
194201146Sedstatic int *
195201146Sedrusers_num(void *argp __unused, struct svc_req *rqstp __unused)
1962337Scsgr{
197201146Sed	static int num_users = 0;
198201192Sed	struct utmpx *usr;
199201192Sed
200201192Sed	setutxent();
201201192Sed	while ((usr = getutxent()) != NULL) {
202201192Sed		if (usr->ut_type != USER_PROCESS)
203201192Sed			continue;
204201192Sed		num_users++;
205201146Sed	}
206201192Sed	endutxent();
207201192Sed
208201146Sed	return(&num_users);
2092337Scsgr}
2102337Scsgr
2112337Scsgrstatic utmparr *
212201146Seddo_names_1(void)
2132337Scsgr{
214201146Sed	utmpidlearr *utidle;
215201146Sed	static utmparr ut;
216201146Sed	unsigned int i;
2178870Srgrimes
218201146Sed	bzero((char *)&ut, sizeof(ut));
2198870Srgrimes
220201146Sed	utidle = do_names_2();
221201146Sed	if (utidle) {
222201146Sed		ut.utmparr_len = utidle->utmpidlearr_len;
223201146Sed		ut.utmparr_val = &old_utmp[0];
224201146Sed		for (i = 0; i < ut.utmparr_len; i++)
225201146Sed			bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
226201146Sed			      sizeof(old_utmp[0]));
2278870Srgrimes
228201146Sed	}
2298870Srgrimes
230201146Sed	return(&ut);
2312337Scsgr}
2322337Scsgr
2332337Scsgrutmpidlearr *
234201146Sedrusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2352337Scsgr{
236201146Sed
237201146Sed	return (do_names_2());
2382337Scsgr}
2392337Scsgr
2402337Scsgrutmpidlearr *
241201146Sedrusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2422337Scsgr{
243201146Sed
244201146Sed	return (do_names_2());
2452337Scsgr}
2462337Scsgr
2472337Scsgrutmparr *
248201146Sedrusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
2492337Scsgr{
250201146Sed
251201146Sed	return (do_names_1());
2522337Scsgr}
2532337Scsgr
2542337Scsgrutmparr *
255201146Sedrusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
2562337Scsgr{
257201146Sed
258201146Sed	return (do_names_1());
2592337Scsgr}
2602337Scsgr
261201146Sedtypedef void *(*rusersproc_t)(void *, struct svc_req *);
262201146Sed
2632337Scsgrvoid
26490336Simprusers_service(struct svc_req *rqstp, SVCXPRT *transp)
2652337Scsgr{
2662337Scsgr	union {
2672337Scsgr		int fill;
2682337Scsgr	} argument;
2692337Scsgr	char *result;
270201146Sed	xdrproc_t xdr_argument, xdr_result;
271201146Sed	rusersproc_t local;
2722337Scsgr
2732337Scsgr	switch (rqstp->rq_proc) {
2742337Scsgr	case NULLPROC:
27595658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
2762337Scsgr		goto leave;
2772337Scsgr
2782337Scsgr	case RUSERSPROC_NUM:
279201146Sed		xdr_argument = (xdrproc_t)xdr_void;
280201146Sed		xdr_result = (xdrproc_t)xdr_int;
281201146Sed		local = (rusersproc_t)rusers_num;
2822337Scsgr		break;
2832337Scsgr
2842337Scsgr	case RUSERSPROC_NAMES:
285201146Sed		xdr_argument = (xdrproc_t)xdr_void;
286201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
287201146Sed		switch (rqstp->rq_vers) {
288201146Sed		case RUSERSVERS_ORIG:
289201146Sed			local = (rusersproc_t)rusersproc_names_1_svc;
290201146Sed			break;
291201146Sed		case RUSERSVERS_IDLE:
292201146Sed			local = (rusersproc_t)rusersproc_names_2_svc;
293201146Sed			break;
294201146Sed		default:
295201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
296201146Sed			goto leave;
297201146Sed			/*NOTREACHED*/
298201146Sed		}
2992337Scsgr		break;
3002337Scsgr
3012337Scsgr	case RUSERSPROC_ALLNAMES:
302201146Sed		xdr_argument = (xdrproc_t)xdr_void;
303201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
304201146Sed		switch (rqstp->rq_vers) {
305201146Sed		case RUSERSVERS_ORIG:
306201146Sed			local = (rusersproc_t)rusersproc_allnames_1_svc;
307201146Sed			break;
308201146Sed		case RUSERSVERS_IDLE:
309201146Sed			local = (rusersproc_t)rusersproc_allnames_2_svc;
310201146Sed			break;
311201146Sed		default:
312201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
313201146Sed			goto leave;
314201146Sed			/*NOTREACHED*/
315201146Sed		}
3162337Scsgr		break;
3172337Scsgr
3182337Scsgr	default:
3192337Scsgr		svcerr_noproc(transp);
3202337Scsgr		goto leave;
3212337Scsgr	}
32295658Sdes	bzero(&argument, sizeof(argument));
32395658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
3242337Scsgr		svcerr_decode(transp);
3252337Scsgr		goto leave;
3262337Scsgr	}
3272337Scsgr	result = (*local)(&argument, rqstp);
32895658Sdes	if (result != NULL &&
32995658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
3302337Scsgr		svcerr_systemerr(transp);
3312337Scsgr	}
33295658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
33332312Scharnier		syslog(LOG_ERR, "unable to free arguments");
33432312Scharnier		exit(1);
33532312Scharnier	}
3362337Scsgrleave:
337201146Sed	if (from_inetd)
338201146Sed		exit(0);
3392337Scsgr}
340