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