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