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