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