xref: /freebsd/libexec/rpc.rusersd/rusers_proc.c (revision a7cb923912cfc221300ddc2ceccf48616a192dc2)
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
35 static const char rcsid[] =
36   "$FreeBSD$";
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 <stdlib.h>
47 #include <syslog.h>
48 #define	_ULOG_POSIX_NAMES
49 #include <ulog.h>
50 #ifdef XIDLE
51 #include <setjmp.h>
52 #include <X11/Xlib.h>
53 #include <X11/extensions/xidle.h>
54 #endif
55 #include <rpcsvc/rnusers.h>
56 
57 #ifndef _PATH_DEV
58 #define _PATH_DEV "/dev"
59 #endif
60 
61 static utmpidle utmp_idle[MAXUSERS];
62 static utmp old_utmp[MAXUSERS];
63 static struct utmpx utmp_list[MAXUSERS];
64 
65 extern int from_inetd;
66 
67 void rusers_service(struct svc_req *, SVCXPRT *);
68 
69 #ifdef XIDLE
70 static Display *dpy;
71 
72 static jmp_buf openAbort;
73 
74 static void
75 abortOpen(void)
76 {
77     longjmp (openAbort, 1);
78 }
79 
80 XqueryIdle(char *display)
81 {
82 	int first_event, first_error;
83 	Time IdleTime;
84 
85 	(void) signal (SIGALRM, abortOpen);
86 	(void) alarm ((unsigned) 10);
87 	if (!setjmp (openAbort)) {
88 		if (!(dpy= XOpenDisplay(display))) {
89 			syslog(LOG_ERR, "Cannot open display %s", display);
90 			return(-1);
91 		}
92 		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
93 			if (!XGetIdleTime(dpy, &IdleTime)) {
94 				syslog(LOG_ERR, "%s: unable to get idle time", display);
95 				return(-1);
96 			}
97 		} else {
98 			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
99 			return(-1);
100 		}
101 		XCloseDisplay(dpy);
102 	} else {
103 		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
104 		return(-1);
105 	}
106 	(void) signal (SIGALRM, SIG_DFL);
107 	(void) alarm ((unsigned) 0);
108 
109 	IdleTime /= 1000;
110 	return((IdleTime + 30) / 60);
111 }
112 #endif
113 
114 static u_int
115 getidle(const char *tty, const char *display __unused)
116 {
117 	struct stat st;
118 	char ttyname[PATH_MAX];
119 	time_t now;
120 	u_long idle;
121 
122 	/*
123 	 * If this is an X terminal or console, then try the
124 	 * XIdle extension
125 	 */
126 #ifdef XIDLE
127 	if (display && *display && (idle = XqueryIdle(display)) >= 0)
128 		return(idle);
129 #endif
130 	idle = 0;
131 	if (*tty == 'X') {
132 		u_long kbd_idle, mouse_idle;
133 #if	!defined(__FreeBSD__)
134 		kbd_idle = getidle("kbd", NULL);
135 #else
136 		kbd_idle = getidle("vga", NULL);
137 #endif
138 		mouse_idle = getidle("mouse", NULL);
139 		idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
140 	} else {
141 		sprintf(ttyname, "%s/%s", _PATH_DEV, tty);
142 		if (stat(ttyname, &st) < 0) {
143 #ifdef DEBUG
144 			printf("%s: %s\n", ttyname, strerror(errno));
145 #endif
146 			return(-1);
147 		}
148 		time(&now);
149 #ifdef DEBUG
150 		printf("%s: now=%d atime=%d\n", ttyname, now,
151 		       st.st_atime);
152 #endif
153 		idle = now - st.st_atime;
154 		idle = (idle + 30) / 60; /* secs->mins */
155 	}
156 
157 	return(idle);
158 }
159 
160 static utmpidlearr *
161 do_names_2(void)
162 {
163 	static utmpidlearr ut;
164 	struct utmpx *usr;
165 	int nusers = 0;
166 
167 	memset(&ut, 0, sizeof(ut));
168 	ut.utmpidlearr_val = &utmp_idle[0];
169 
170 	setutxent();
171 	while ((usr = getutxent()) != NULL && nusers < MAXUSERS) {
172 		if (usr->ut_type != USER_PROCESS)
173 			continue;
174 
175 		memcpy(&utmp_list[nusers], usr, sizeof(*usr));
176 		utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec;
177 		utmp_idle[nusers].ui_idle =
178 		    getidle(usr->ut_line, usr->ut_host);
179 		utmp_idle[nusers].ui_utmp.ut_line =
180 		    utmp_list[nusers].ut_line;
181 		utmp_idle[nusers].ui_utmp.ut_name =
182 		    utmp_list[nusers].ut_user;
183 		utmp_idle[nusers].ui_utmp.ut_host =
184 		    utmp_list[nusers].ut_host;
185 
186 		nusers++;
187 	}
188 	endutxent();
189 
190 	ut.utmpidlearr_len = nusers;
191 	return(&ut);
192 }
193 
194 static int *
195 rusers_num(void *argp __unused, struct svc_req *rqstp __unused)
196 {
197 	static int num_users = 0;
198 	struct utmpx *usr;
199 
200 	setutxent();
201 	while ((usr = getutxent()) != NULL) {
202 		if (usr->ut_type != USER_PROCESS)
203 			continue;
204 		num_users++;
205 	}
206 	endutxent();
207 
208 	return(&num_users);
209 }
210 
211 static utmparr *
212 do_names_1(void)
213 {
214 	utmpidlearr *utidle;
215 	static utmparr ut;
216 	unsigned int i;
217 
218 	bzero((char *)&ut, sizeof(ut));
219 
220 	utidle = do_names_2();
221 	if (utidle) {
222 		ut.utmparr_len = utidle->utmpidlearr_len;
223 		ut.utmparr_val = &old_utmp[0];
224 		for (i = 0; i < ut.utmparr_len; i++)
225 			bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
226 			      sizeof(old_utmp[0]));
227 
228 	}
229 
230 	return(&ut);
231 }
232 
233 utmpidlearr *
234 rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
235 {
236 
237 	return (do_names_2());
238 }
239 
240 utmpidlearr *
241 rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused)
242 {
243 
244 	return (do_names_2());
245 }
246 
247 utmparr *
248 rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
249 {
250 
251 	return (do_names_1());
252 }
253 
254 utmparr *
255 rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused)
256 {
257 
258 	return (do_names_1());
259 }
260 
261 typedef void *(*rusersproc_t)(void *, struct svc_req *);
262 
263 void
264 rusers_service(struct svc_req *rqstp, SVCXPRT *transp)
265 {
266 	union {
267 		int fill;
268 	} argument;
269 	char *result;
270 	xdrproc_t xdr_argument, xdr_result;
271 	rusersproc_t local;
272 
273 	switch (rqstp->rq_proc) {
274 	case NULLPROC:
275 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
276 		goto leave;
277 
278 	case RUSERSPROC_NUM:
279 		xdr_argument = (xdrproc_t)xdr_void;
280 		xdr_result = (xdrproc_t)xdr_int;
281 		local = (rusersproc_t)rusers_num;
282 		break;
283 
284 	case RUSERSPROC_NAMES:
285 		xdr_argument = (xdrproc_t)xdr_void;
286 		xdr_result = (xdrproc_t)xdr_utmpidlearr;
287 		switch (rqstp->rq_vers) {
288 		case RUSERSVERS_ORIG:
289 			local = (rusersproc_t)rusersproc_names_1_svc;
290 			break;
291 		case RUSERSVERS_IDLE:
292 			local = (rusersproc_t)rusersproc_names_2_svc;
293 			break;
294 		default:
295 			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
296 			goto leave;
297 			/*NOTREACHED*/
298 		}
299 		break;
300 
301 	case RUSERSPROC_ALLNAMES:
302 		xdr_argument = (xdrproc_t)xdr_void;
303 		xdr_result = (xdrproc_t)xdr_utmpidlearr;
304 		switch (rqstp->rq_vers) {
305 		case RUSERSVERS_ORIG:
306 			local = (rusersproc_t)rusersproc_allnames_1_svc;
307 			break;
308 		case RUSERSVERS_IDLE:
309 			local = (rusersproc_t)rusersproc_allnames_2_svc;
310 			break;
311 		default:
312 			svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
313 			goto leave;
314 			/*NOTREACHED*/
315 		}
316 		break;
317 
318 	default:
319 		svcerr_noproc(transp);
320 		goto leave;
321 	}
322 	bzero(&argument, sizeof(argument));
323 	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
324 		svcerr_decode(transp);
325 		goto leave;
326 	}
327 	result = (*local)(&argument, rqstp);
328 	if (result != NULL &&
329 	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
330 		svcerr_systemerr(transp);
331 	}
332 	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
333 		syslog(LOG_ERR, "unable to free arguments");
334 		exit(1);
335 	}
336 leave:
337 	if (from_inetd)
338 		exit(0);
339 }
340