rusers_proc.c revision 1.3 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 kbd_idle = getidle("kbd", NULL);
158 mouse_idle = getidle("mouse", NULL);
159 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
160 }
161 else {
162 sprintf(devname, "%s/%s", _PATH_DEV, tty);
163 if (stat(devname, &st) < 0) {
164 syslog(LOG_ERR, "%s: %m", devname);
165 return(-1);
166 }
167 time(&now);
168 #ifdef DEBUG
169 printf("%s: now=%d atime=%d\n", devname, now,
170 st.st_atime);
171 #endif
172 idle = now - st.st_atime;
173 idle = (idle + 30) / 60; /* secs->mins */
174 }
175 if (idle < 0) idle = 0;
176
177 return(idle);
178 }
179
180 static utmpidlearr *
181 do_names_2(int all)
182 {
183 static utmpidlearr ut;
184 struct utmp usr;
185 int nusers = 0;
186
187 bzero((char *)&ut, sizeof(ut));
188 ut.utmpidlearr_val = &utmp_idle[0];
189
190 ufp = fopen(_PATH_UTMP, "r");
191 if (!ufp) {
192 syslog(LOG_ERR, "%m");
193 return(&ut);
194 }
195
196 /* only entries with both name and line fields */
197 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
198 nusers < MAXUSERS)
199 if (*usr.ut_name && *usr.ut_line &&
200 strncmp(usr.ut_name, IGNOREUSER,
201 sizeof(usr.ut_name))
202 #ifdef OSF
203 && usr.ut_type == USER_PROCESS
204 #endif
205 ) {
206 utmp_idle[nusers].ui_utmp.ut_time =
207 usr.ut_time;
208 utmp_idle[nusers].ui_idle =
209 getidle(usr.ut_line, usr.ut_host);
210 utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
211 strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
212 utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
213 strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
214 utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
215 strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
216 nusers++;
217 }
218
219 ut.utmpidlearr_len = nusers;
220 fclose(ufp);
221 return(&ut);
222 }
223
224 int *
225 rusers_num()
226 {
227 int num_users = 0;
228 struct utmp usr;
229
230 ufp = fopen(_PATH_UTMP, "r");
231 if (!ufp) {
232 syslog(LOG_ERR, "%m");
233 return(0);
234 }
235
236 /* only entries with both name and line fields */
237 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
238 if (*usr.ut_name && *usr.ut_line &&
239 strncmp(usr.ut_name, IGNOREUSER,
240 sizeof(usr.ut_name))
241 #ifdef OSF
242 && usr.ut_type == USER_PROCESS
243 #endif
244 ) {
245 num_users++;
246 }
247
248 fclose(ufp);
249 return(&num_users);
250 }
251
252 static utmparr *
253 do_names_1(int all)
254 {
255 utmpidlearr *utidle;
256 utmparr ut;
257 int i;
258
259 bzero((char *)&ut, sizeof(ut));
260
261 utidle = do_names_2(all);
262 if (utidle) {
263 ut.utmparr_len = utidle->utmpidlearr_len;
264 ut.utmparr_val = &old_utmp[0];
265 for (i = 0; i < ut.utmparr_len; i++)
266 bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
267 sizeof(old_utmp[0]));
268
269 }
270
271 return(&ut);
272 }
273
274 utmpidlearr *
275 rusersproc_names_2()
276 {
277 return(do_names_2(0));
278 }
279
280 utmpidlearr *
281 rusersproc_allnames_2()
282 {
283 return(do_names_2(1));
284 }
285
286 utmparr *
287 rusersproc_names_1()
288 {
289 return(do_names_1(0));
290 }
291
292 utmparr *
293 rusersproc_allnames_1()
294 {
295 return(do_names_1(1));
296 }
297
298 void
299 rusers_service(rqstp, transp)
300 struct svc_req *rqstp;
301 SVCXPRT *transp;
302 {
303 union {
304 int fill;
305 } argument;
306 char *result;
307 bool_t (*xdr_argument)(), (*xdr_result)();
308 char *(*local)();
309
310 switch (rqstp->rq_proc) {
311 case NULLPROC:
312 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
313 goto leave;
314
315 case RUSERSPROC_NUM:
316 xdr_argument = xdr_void;
317 xdr_result = xdr_int;
318 local = (char *(*)()) rusers_num;
319 break;
320
321 case RUSERSPROC_NAMES:
322 xdr_argument = xdr_void;
323 xdr_result = xdr_utmpidlearr;
324 switch (rqstp->rq_vers) {
325 case RUSERSVERS_ORIG:
326 local = (char *(*)()) rusersproc_names_1;
327 break;
328 case RUSERSVERS_IDLE:
329 local = (char *(*)()) rusersproc_names_2;
330 break;
331 default:
332 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
333 goto leave;
334 /*NOTREACHED*/
335 }
336 break;
337
338 case RUSERSPROC_ALLNAMES:
339 xdr_argument = xdr_void;
340 xdr_result = xdr_utmpidlearr;
341 switch (rqstp->rq_vers) {
342 case RUSERSVERS_ORIG:
343 local = (char *(*)()) rusersproc_allnames_1;
344 break;
345 case RUSERSVERS_IDLE:
346 local = (char *(*)()) rusersproc_allnames_2;
347 break;
348 default:
349 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
350 goto leave;
351 /*NOTREACHED*/
352 }
353 break;
354
355 default:
356 svcerr_noproc(transp);
357 goto leave;
358 }
359 bzero((char *)&argument, sizeof(argument));
360 if (!svc_getargs(transp, xdr_argument, &argument)) {
361 svcerr_decode(transp);
362 goto leave;
363 }
364 result = (*local)(&argument, rqstp);
365 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
366 svcerr_systemerr(transp);
367 }
368 if (!svc_freeargs(transp, xdr_argument, &argument)) {
369 (void)fprintf(stderr, "unable to free arguments\n");
370 exit(1);
371 }
372 leave:
373 if (from_inetd)
374 exit(0);
375 }
376