Merge from vendor branch NTPD:
[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  * $DragonFly: src/libexec/rpc.rusersd/rusers_proc.c,v 1.3 2004/02/13 03:49:48 dillon Exp $
35  */
36
37 #ifdef DEBUG
38 #include <errno.h>
39 #endif
40 #include <stdio.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()
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(argp, rqstp)
289         void                    *argp;
290         struct svc_req          *rqstp;
291 {
292         return(do_names_2(0));
293 }
294
295 utmpidlearr *
296 rusersproc_allnames_2_svc(argp, rqstp)
297         void                    *argp;
298         struct svc_req          *rqstp;
299 {
300         return(do_names_2(1));
301 }
302
303 utmparr *
304 rusersproc_names_1_svc(argp, rqstp)
305         void                    *argp;
306         struct svc_req          *rqstp;
307 {
308         return(do_names_1(0));
309 }
310
311 utmparr *
312 rusersproc_allnames_1_svc(argp, rqstp)
313         void                    *argp;
314         struct svc_req          *rqstp;
315 {
316         return(do_names_1(1));
317 }
318
319 void
320 rusers_service(rqstp, transp)
321         struct svc_req *rqstp;
322         SVCXPRT *transp;
323 {
324         union {
325                 int fill;
326         } argument;
327         char *result;
328         bool_t (*xdr_argument)(), (*xdr_result)();
329         char *(*local)();
330
331         switch (rqstp->rq_proc) {
332         case NULLPROC:
333                 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
334                 goto leave;
335
336         case RUSERSPROC_NUM:
337                 xdr_argument = xdr_void;
338                 xdr_result = xdr_int;
339                 local = (char *(*)()) rusers_num;
340                 break;
341
342         case RUSERSPROC_NAMES:
343                 xdr_argument = xdr_void;
344                 xdr_result = xdr_utmpidlearr;
345                 switch (rqstp->rq_vers) {
346                 case RUSERSVERS_ORIG:
347                         local = (char *(*)()) rusersproc_names_1_svc;
348                         break;
349                 case RUSERSVERS_IDLE:
350                         local = (char *(*)()) rusersproc_names_2_svc;
351                         break;
352                 default:
353                         svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
354                         goto leave;
355                         /*NOTREACHED*/
356                 }
357                 break;
358
359         case RUSERSPROC_ALLNAMES:
360                 xdr_argument = xdr_void;
361                 xdr_result = xdr_utmpidlearr;
362                 switch (rqstp->rq_vers) {
363                 case RUSERSVERS_ORIG:
364                         local = (char *(*)()) rusersproc_allnames_1_svc;
365                         break;
366                 case RUSERSVERS_IDLE:
367                         local = (char *(*)()) rusersproc_allnames_2_svc;
368                         break;
369                 default:
370                         svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
371                         goto leave;
372                         /*NOTREACHED*/
373                 }
374                 break;
375
376         default:
377                 svcerr_noproc(transp);
378                 goto leave;
379         }
380         bzero((char *)&argument, sizeof(argument));
381         if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
382                 svcerr_decode(transp);
383                 goto leave;
384         }
385         result = (*local)(&argument, rqstp);
386         if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
387                 svcerr_systemerr(transp);
388         }
389         if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
390                 syslog(LOG_ERR, "unable to free arguments");
391                 exit(1);
392         }
393 leave:
394         if (from_inetd)
395                 exit(0);
396 }