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