rusers_proc.c revision 95658
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 95658 2002-04-28 15:18:50Z des $";
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(void)
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(void)
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(void *argp, struct svc_req *rqstp)
291{
292        return(do_names_2(0));
293}
294
295utmpidlearr *
296rusersproc_allnames_2_svc(void *argp, struct svc_req *rqstp)
297{
298        return(do_names_2(1));
299}
300
301utmparr *
302rusersproc_names_1_svc(void *argp, struct svc_req *rqstp)
303{
304	return(do_names_1(0));
305}
306
307utmparr *
308rusersproc_allnames_1_svc(void *argp, struct svc_req *rqstp)
309{
310        return(do_names_1(1));
311}
312
313void
314rusers_service(struct svc_req *rqstp, SVCXPRT *transp)
315{
316	union {
317		int fill;
318	} argument;
319	char *result;
320	bool_t (*xdr_argument)(), (*xdr_result)();
321	char *(*local)();
322
323	switch (rqstp->rq_proc) {
324	case NULLPROC:
325		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
326		goto leave;
327
328	case RUSERSPROC_NUM:
329		xdr_argument = xdr_void;
330		xdr_result = xdr_int;
331                local = (char *(*)()) rusers_num;
332		break;
333
334	case RUSERSPROC_NAMES:
335		xdr_argument = xdr_void;
336		xdr_result = xdr_utmpidlearr;
337                switch (rqstp->rq_vers) {
338                case RUSERSVERS_ORIG:
339                        local = (char *(*)()) rusersproc_names_1_svc;
340                        break;
341                case RUSERSVERS_IDLE:
342                        local = (char *(*)()) rusersproc_names_2_svc;
343                        break;
344                default:
345                        svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
346                        goto leave;
347                        /*NOTREACHED*/
348                }
349		break;
350
351	case RUSERSPROC_ALLNAMES:
352		xdr_argument = xdr_void;
353		xdr_result = xdr_utmpidlearr;
354                switch (rqstp->rq_vers) {
355                case RUSERSVERS_ORIG:
356                        local = (char *(*)()) rusersproc_allnames_1_svc;
357                        break;
358                case RUSERSVERS_IDLE:
359                        local = (char *(*)()) rusersproc_allnames_2_svc;
360                        break;
361                default:
362                        svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
363                        goto leave;
364                        /*NOTREACHED*/
365                }
366		break;
367
368	default:
369		svcerr_noproc(transp);
370		goto leave;
371	}
372	bzero(&argument, sizeof(argument));
373	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
374		svcerr_decode(transp);
375		goto leave;
376	}
377	result = (*local)(&argument, rqstp);
378	if (result != NULL &&
379	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
380		svcerr_systemerr(transp);
381	}
382	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
383		syslog(LOG_ERR, "unable to free arguments");
384		exit(1);
385	}
386leave:
387        if (from_inetd)
388                exit(0);
389}
390