rusers_proc.c revision 201146
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 201146 2009-12-28 23:01:24Z 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>
4831422Scharnier#include <utmp.h>
492337Scsgr#ifdef XIDLE
502337Scsgr#include <setjmp.h>
512337Scsgr#include <X11/Xlib.h>
522337Scsgr#include <X11/extensions/xidle.h>
532337Scsgr#endif
542337Scsgr#define utmp rutmp
552337Scsgr#include <rpcsvc/rnusers.h>
562337Scsgr#undef utmp
572337Scsgr
582337Scsgr#define	IGNOREUSER	"sleeper"
592337Scsgr
602337Scsgr#ifdef OSF
612337Scsgr#define _PATH_UTMP UTMP_FILE
622337Scsgr#endif
632337Scsgr
642337Scsgr#ifndef _PATH_UTMP
652337Scsgr#define _PATH_UTMP "/etc/utmp"
662337Scsgr#endif
672337Scsgr
682337Scsgr#ifndef _PATH_DEV
692337Scsgr#define _PATH_DEV "/dev"
702337Scsgr#endif
712337Scsgr
722337Scsgr#ifndef UT_LINESIZE
732337Scsgr#define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line)
742337Scsgr#endif
752337Scsgr#ifndef UT_NAMESIZE
762337Scsgr#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
772337Scsgr#endif
782337Scsgr#ifndef UT_HOSTSIZE
792337Scsgr#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
802337Scsgr#endif
812337Scsgr
822337Scsgrtypedef char ut_line_t[UT_LINESIZE+1];
832337Scsgrtypedef char ut_name_t[UT_NAMESIZE+1];
842337Scsgrtypedef char ut_host_t[UT_HOSTSIZE+1];
852337Scsgr
86201146Sedstatic utmpidle utmp_idle[MAXUSERS];
87201146Sedstatic rutmp old_utmp[MAXUSERS];
88201146Sedstatic ut_line_t line[MAXUSERS];
89201146Sedstatic ut_name_t name[MAXUSERS];
90201146Sedstatic ut_host_t host[MAXUSERS];
912337Scsgr
922337Scsgrextern int from_inetd;
932337Scsgr
94201146Sedvoid rusers_service(struct svc_req *, SVCXPRT *);
952337Scsgr
96201146Sedstatic FILE *ufp;
97201146Sed
982337Scsgr#ifdef XIDLE
99201146Sedstatic Display *dpy;
1002337Scsgr
1012337Scsgrstatic jmp_buf openAbort;
1022337Scsgr
1032337Scsgrstatic void
10490336SimpabortOpen(void)
1052337Scsgr{
1062337Scsgr    longjmp (openAbort, 1);
1072337Scsgr}
1082337Scsgr
1092337ScsgrXqueryIdle(char *display)
1102337Scsgr{
111201146Sed	int first_event, first_error;
112201146Sed	Time IdleTime;
1132337Scsgr
114201146Sed	(void) signal (SIGALRM, abortOpen);
115201146Sed	(void) alarm ((unsigned) 10);
116201146Sed	if (!setjmp (openAbort)) {
117201146Sed		if (!(dpy= XOpenDisplay(display))) {
118201146Sed			syslog(LOG_ERR, "Cannot open display %s", display);
119201146Sed			return(-1);
120201146Sed		}
121201146Sed		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
122201146Sed			if (!XGetIdleTime(dpy, &IdleTime)) {
123201146Sed				syslog(LOG_ERR, "%s: unable to get idle time", display);
124201146Sed				return(-1);
125201146Sed			}
126201146Sed		} else {
127201146Sed			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
128201146Sed			return(-1);
129201146Sed		}
130201146Sed		XCloseDisplay(dpy);
131201146Sed	} else {
132201146Sed		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
133201146Sed		return(-1);
134201146Sed	}
135201146Sed	(void) signal (SIGALRM, SIG_DFL);
136201146Sed	(void) alarm ((unsigned) 0);
1372337Scsgr
138201146Sed	IdleTime /= 1000;
139201146Sed	return((IdleTime + 30) / 60);
1402337Scsgr}
1412337Scsgr#endif
1422337Scsgr
1432337Scsgrstatic u_int
144201146Sedgetidle(const char *tty, const char *display __unused)
1452337Scsgr{
146201146Sed	struct stat st;
147201146Sed	char ttyname[PATH_MAX];
148201146Sed	time_t now;
149201146Sed	u_long idle;
1508870Srgrimes
151201146Sed	/*
152201146Sed	 * If this is an X terminal or console, then try the
153201146Sed	 * XIdle extension
154201146Sed	 */
1552337Scsgr#ifdef XIDLE
156201146Sed	if (display && *display && (idle = XqueryIdle(display)) >= 0)
157201146Sed		return(idle);
1582337Scsgr#endif
159201146Sed	idle = 0;
160201146Sed	if (*tty == 'X') {
161201146Sed		u_long kbd_idle, mouse_idle;
1624131Sjkh#if	!defined(__FreeBSD__)
163201146Sed		kbd_idle = getidle("kbd", NULL);
1642337Scsgr#else
165201146Sed		kbd_idle = getidle("vga", NULL);
1662337Scsgr#endif
167201146Sed		mouse_idle = getidle("mouse", NULL);
168201146Sed		idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
169201146Sed	} else {
170201146Sed		sprintf(ttyname, "%s/%s", _PATH_DEV, tty);
171201146Sed		if (stat(ttyname, &st) < 0) {
1722337Scsgr#ifdef DEBUG
173201146Sed			printf("%s: %s\n", ttyname, strerror(errno));
1742337Scsgr#endif
175201146Sed			return(-1);
176201146Sed		}
177201146Sed		time(&now);
1782337Scsgr#ifdef DEBUG
179201146Sed		printf("%s: now=%d atime=%d\n", ttyname, now,
180201146Sed		       st.st_atime);
1812337Scsgr#endif
182201146Sed		idle = now - st.st_atime;
183201146Sed		idle = (idle + 30) / 60; /* secs->mins */
184201146Sed	}
1852337Scsgr
186201146Sed	return(idle);
1872337Scsgr}
1888870Srgrimes
1892337Scsgrstatic utmpidlearr *
190201146Seddo_names_2(void)
1912337Scsgr{
192201146Sed	static utmpidlearr ut;
1932337Scsgr	struct utmp usr;
194201146Sed	int nusers = 0;
1958870Srgrimes
196201146Sed	bzero((char *)&ut, sizeof(ut));
197201146Sed	ut.utmpidlearr_val = &utmp_idle[0];
1988870Srgrimes
1992337Scsgr	ufp = fopen(_PATH_UTMP, "r");
200201146Sed	if (!ufp) {
201201146Sed		syslog(LOG_ERR, "%m");
202201146Sed		return(&ut);
203201146Sed	}
2042337Scsgr
205201146Sed	/* only entries with both name and line fields */
206201146Sed	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
207201146Sed	       nusers < MAXUSERS)
208201146Sed		if (*usr.ut_name && *usr.ut_line &&
2092337Scsgr		    strncmp(usr.ut_name, IGNOREUSER,
210201146Sed			    sizeof(usr.ut_name))
2112337Scsgr#ifdef OSF
212201146Sed		    && usr.ut_type == USER_PROCESS
2132337Scsgr#endif
214201146Sed		    ) {
215201146Sed			utmp_idle[nusers].ui_utmp.ut_time =
216201146Sed				usr.ut_time;
217201146Sed			utmp_idle[nusers].ui_idle =
218201146Sed				getidle(usr.ut_line, usr.ut_host);
219201146Sed			utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
220201146Sed			strncpy(line[nusers], usr.ut_line, UT_LINESIZE);
221201146Sed			utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
222201146Sed			strncpy(name[nusers], usr.ut_name, UT_NAMESIZE);
223201146Sed			utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
224201146Sed			strncpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
2258870Srgrimes
2262337Scsgr			/* Make sure entries are NUL terminated */
2278870Srgrimes			line[nusers][UT_LINESIZE] =
2288870Srgrimes			name[nusers][UT_NAMESIZE] =
2292337Scsgr			host[nusers][UT_HOSTSIZE] = '\0';
230201146Sed			nusers++;
231201146Sed		}
2322337Scsgr
233201146Sed	ut.utmpidlearr_len = nusers;
234201146Sed	fclose(ufp);
235201146Sed	return(&ut);
2362337Scsgr}
2372337Scsgr
238201146Sedstatic int *
239201146Sedrusers_num(void *argp __unused, struct svc_req *rqstp __unused)
2402337Scsgr{
241201146Sed	static int num_users = 0;
2422337Scsgr	struct utmp usr;
2432337Scsgr
244201146Sed	ufp = fopen(_PATH_UTMP, "r");
245201146Sed	if (!ufp) {
246201146Sed		syslog(LOG_ERR, "%m");
247201146Sed		return(NULL);
248201146Sed	}
2492337Scsgr
250201146Sed	/* only entries with both name and line fields */
251201146Sed	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
252201146Sed		if (*usr.ut_name && *usr.ut_line &&
2532337Scsgr		    strncmp(usr.ut_name, IGNOREUSER,
254201146Sed			    sizeof(usr.ut_name))
2552337Scsgr#ifdef OSF
256201146Sed		    && usr.ut_type == USER_PROCESS
2572337Scsgr#endif
258201146Sed		    ) {
259201146Sed			num_users++;
260201146Sed		}
2612337Scsgr
262201146Sed	fclose(ufp);
263201146Sed	return(&num_users);
2642337Scsgr}
2652337Scsgr
2662337Scsgrstatic utmparr *
267201146Seddo_names_1(void)
2682337Scsgr{
269201146Sed	utmpidlearr *utidle;
270201146Sed	static utmparr ut;
271201146Sed	unsigned int i;
2728870Srgrimes
273201146Sed	bzero((char *)&ut, sizeof(ut));
2748870Srgrimes
275201146Sed	utidle = do_names_2();
276201146Sed	if (utidle) {
277201146Sed		ut.utmparr_len = utidle->utmpidlearr_len;
278201146Sed		ut.utmparr_val = &old_utmp[0];
279201146Sed		for (i = 0; i < ut.utmparr_len; i++)
280201146Sed			bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
281201146Sed			      sizeof(old_utmp[0]));
2828870Srgrimes
283201146Sed	}
2848870Srgrimes
285201146Sed	return(&ut);
2862337Scsgr}
2872337Scsgr
2882337Scsgrutmpidlearr *
289201146Sedrusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2902337Scsgr{
291201146Sed
292201146Sed	return (do_names_2());
2932337Scsgr}
2942337Scsgr
2952337Scsgrutmpidlearr *
296201146Sedrusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
2972337Scsgr{
298201146Sed
299201146Sed	return (do_names_2());
3002337Scsgr}
3012337Scsgr
3022337Scsgrutmparr *
303201146Sedrusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
3042337Scsgr{
305201146Sed
306201146Sed	return (do_names_1());
3072337Scsgr}
3082337Scsgr
3092337Scsgrutmparr *
310201146Sedrusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
3112337Scsgr{
312201146Sed
313201146Sed	return (do_names_1());
3142337Scsgr}
3152337Scsgr
316201146Sedtypedef void *(*rusersproc_t)(void *, struct svc_req *);
317201146Sed
3182337Scsgrvoid
31990336Simprusers_service(struct svc_req *rqstp, SVCXPRT *transp)
3202337Scsgr{
3212337Scsgr	union {
3222337Scsgr		int fill;
3232337Scsgr	} argument;
3242337Scsgr	char *result;
325201146Sed	xdrproc_t xdr_argument, xdr_result;
326201146Sed	rusersproc_t local;
3272337Scsgr
3282337Scsgr	switch (rqstp->rq_proc) {
3292337Scsgr	case NULLPROC:
33095658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
3312337Scsgr		goto leave;
3322337Scsgr
3332337Scsgr	case RUSERSPROC_NUM:
334201146Sed		xdr_argument = (xdrproc_t)xdr_void;
335201146Sed		xdr_result = (xdrproc_t)xdr_int;
336201146Sed		local = (rusersproc_t)rusers_num;
3372337Scsgr		break;
3382337Scsgr
3392337Scsgr	case RUSERSPROC_NAMES:
340201146Sed		xdr_argument = (xdrproc_t)xdr_void;
341201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
342201146Sed		switch (rqstp->rq_vers) {
343201146Sed		case RUSERSVERS_ORIG:
344201146Sed			local = (rusersproc_t)rusersproc_names_1_svc;
345201146Sed			break;
346201146Sed		case RUSERSVERS_IDLE:
347201146Sed			local = (rusersproc_t)rusersproc_names_2_svc;
348201146Sed			break;
349201146Sed		default:
350201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
351201146Sed			goto leave;
352201146Sed			/*NOTREACHED*/
353201146Sed		}
3542337Scsgr		break;
3552337Scsgr
3562337Scsgr	case RUSERSPROC_ALLNAMES:
357201146Sed		xdr_argument = (xdrproc_t)xdr_void;
358201146Sed		xdr_result = (xdrproc_t)xdr_utmpidlearr;
359201146Sed		switch (rqstp->rq_vers) {
360201146Sed		case RUSERSVERS_ORIG:
361201146Sed			local = (rusersproc_t)rusersproc_allnames_1_svc;
362201146Sed			break;
363201146Sed		case RUSERSVERS_IDLE:
364201146Sed			local = (rusersproc_t)rusersproc_allnames_2_svc;
365201146Sed			break;
366201146Sed		default:
367201146Sed			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
368201146Sed			goto leave;
369201146Sed			/*NOTREACHED*/
370201146Sed		}
3712337Scsgr		break;
3722337Scsgr
3732337Scsgr	default:
3742337Scsgr		svcerr_noproc(transp);
3752337Scsgr		goto leave;
3762337Scsgr	}
37795658Sdes	bzero(&argument, sizeof(argument));
37895658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
3792337Scsgr		svcerr_decode(transp);
3802337Scsgr		goto leave;
3812337Scsgr	}
3822337Scsgr	result = (*local)(&argument, rqstp);
38395658Sdes	if (result != NULL &&
38495658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
3852337Scsgr		svcerr_systemerr(transp);
3862337Scsgr	}
38795658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
38832312Scharnier		syslog(LOG_ERR, "unable to free arguments");
38932312Scharnier		exit(1);
39032312Scharnier	}
3912337Scsgrleave:
392201146Sed	if (from_inetd)
393201146Sed		exit(0);
3942337Scsgr}
395