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.3 1994/11/18 23:36:18 ats 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+1]; 82 typedef char ut_name_t[UT_NAMESIZE+1]; 83 typedef char ut_host_t[UT_HOSTSIZE+1]; 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(__FreeBSD__) 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, UT_LINESIZE); 222 utmp_idle[nusers].ui_utmp.ut_name = name[nusers]; 223 strncpy(name[nusers], usr.ut_name, UT_NAMESIZE); 224 utmp_idle[nusers].ui_utmp.ut_host = host[nusers]; 225 strncpy(host[nusers], usr.ut_host, UT_HOSTSIZE); 226 227 /* Make sure entries are NUL terminated */ 228 line[nusers][UT_LINESIZE] = 229 name[nusers][UT_NAMESIZE] = 230 host[nusers][UT_HOSTSIZE] = '\0'; 231 nusers++; 232 } 233 234 ut.utmpidlearr_len = nusers; 235 fclose(ufp); 236 return(&ut); 237 } 238 239 int * 240 rusers_num() 241 { 242 static int num_users = 0; 243 struct utmp usr; 244 245 ufp = fopen(_PATH_UTMP, "r"); 246 if (!ufp) { 247 syslog(LOG_ERR, "%m"); 248 return(0); 249 } 250 251 /* only entries with both name and line fields */ 252 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 253 if (*usr.ut_name && *usr.ut_line && 254 strncmp(usr.ut_name, IGNOREUSER, 255 sizeof(usr.ut_name)) 256 #ifdef OSF 257 && usr.ut_type == USER_PROCESS 258 #endif 259 ) { 260 num_users++; 261 } 262 263 fclose(ufp); 264 return(&num_users); 265 } 266 267 static utmparr * 268 do_names_1(int all) 269 { 270 utmpidlearr *utidle; 271 static utmparr ut; 272 int i; 273 274 bzero((char *)&ut, sizeof(ut)); 275 276 utidle = do_names_2(all); 277 if (utidle) { 278 ut.utmparr_len = utidle->utmpidlearr_len; 279 ut.utmparr_val = &old_utmp[0]; 280 for (i = 0; i < ut.utmparr_len; i++) 281 bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i], 282 sizeof(old_utmp[0])); 283 284 } 285 286 return(&ut); 287 } 288 289 utmpidlearr * 290 rusersproc_names_2() 291 { 292 return(do_names_2(0)); 293 } 294 295 utmpidlearr * 296 rusersproc_allnames_2() 297 { 298 return(do_names_2(1)); 299 } 300 301 utmparr * 302 rusersproc_names_1() 303 { 304 return(do_names_1(0)); 305 } 306 307 utmparr * 308 rusersproc_allnames_1() 309 { 310 return(do_names_1(1)); 311 } 312 313 void 314 rusers_service(rqstp, transp) 315 struct svc_req *rqstp; 316 SVCXPRT *transp; 317 { 318 union { 319 int fill; 320 } argument; 321 char *result; 322 bool_t (*xdr_argument)(), (*xdr_result)(); 323 char *(*local)(); 324 325 switch (rqstp->rq_proc) { 326 case NULLPROC: 327 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 328 goto leave; 329 330 case RUSERSPROC_NUM: 331 xdr_argument = xdr_void; 332 xdr_result = xdr_int; 333 local = (char *(*)()) rusers_num; 334 break; 335 336 case RUSERSPROC_NAMES: 337 xdr_argument = xdr_void; 338 xdr_result = xdr_utmpidlearr; 339 switch (rqstp->rq_vers) { 340 case RUSERSVERS_ORIG: 341 local = (char *(*)()) rusersproc_names_1; 342 break; 343 case RUSERSVERS_IDLE: 344 local = (char *(*)()) rusersproc_names_2; 345 break; 346 default: 347 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 348 goto leave; 349 /*NOTREACHED*/ 350 } 351 break; 352 353 case RUSERSPROC_ALLNAMES: 354 xdr_argument = xdr_void; 355 xdr_result = xdr_utmpidlearr; 356 switch (rqstp->rq_vers) { 357 case RUSERSVERS_ORIG: 358 local = (char *(*)()) rusersproc_allnames_1; 359 break; 360 case RUSERSVERS_IDLE: 361 local = (char *(*)()) rusersproc_allnames_2; 362 break; 363 default: 364 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 365 goto leave; 366 /*NOTREACHED*/ 367 } 368 break; 369 370 default: 371 svcerr_noproc(transp); 372 goto leave; 373 } 374 bzero((char *)&argument, sizeof(argument)); 375 if (!svc_getargs(transp, xdr_argument, &argument)) { 376 svcerr_decode(transp); 377 goto leave; 378 } 379 result = (*local)(&argument, rqstp); 380 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 381 svcerr_systemerr(transp); 382 } 383 if (!svc_freeargs(transp, xdr_argument, &argument)) { 384 (void)fprintf(stderr, "unable to free arguments\n"); 385 exit(1); 386 } 387 leave: 388 if (from_inetd) 389 exit(0); 390 } 391