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