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