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