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