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 const char rcsid[] = 36 "$Id: rusers_proc.c,v 1.8 1998/01/07 07:54:17 charnier Exp $"; 37 #endif /* not lint */ 38 39 #ifdef DEBUG 40 #include <errno.h> 41 #endif 42 #include <stdio.h> 43 #include <string.h> 44 #include <sys/param.h> 45 #include <sys/stat.h> 46 #include <syslog.h> 47 #include <utmp.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(NULL); 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_svc(argp, rqstp) 291 void *argp; 292 struct svc_req *rqstp; 293 { 294 return(do_names_2(0)); 295 } 296 297 utmpidlearr * 298 rusersproc_allnames_2_svc(argp, rqstp) 299 void *argp; 300 struct svc_req *rqstp; 301 { 302 return(do_names_2(1)); 303 } 304 305 utmparr * 306 rusersproc_names_1_svc(argp, rqstp) 307 void *argp; 308 struct svc_req *rqstp; 309 { 310 return(do_names_1(0)); 311 } 312 313 utmparr * 314 rusersproc_allnames_1_svc(argp, rqstp) 315 void *argp; 316 struct svc_req *rqstp; 317 { 318 return(do_names_1(1)); 319 } 320 321 void 322 rusers_service(rqstp, transp) 323 struct svc_req *rqstp; 324 SVCXPRT *transp; 325 { 326 union { 327 int fill; 328 } argument; 329 char *result; 330 bool_t (*xdr_argument)(), (*xdr_result)(); 331 char *(*local)(); 332 333 switch (rqstp->rq_proc) { 334 case NULLPROC: 335 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 336 goto leave; 337 338 case RUSERSPROC_NUM: 339 xdr_argument = xdr_void; 340 xdr_result = xdr_int; 341 local = (char *(*)()) rusers_num; 342 break; 343 344 case RUSERSPROC_NAMES: 345 xdr_argument = xdr_void; 346 xdr_result = xdr_utmpidlearr; 347 switch (rqstp->rq_vers) { 348 case RUSERSVERS_ORIG: 349 local = (char *(*)()) rusersproc_names_1_svc; 350 break; 351 case RUSERSVERS_IDLE: 352 local = (char *(*)()) rusersproc_names_2_svc; 353 break; 354 default: 355 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 356 goto leave; 357 /*NOTREACHED*/ 358 } 359 break; 360 361 case RUSERSPROC_ALLNAMES: 362 xdr_argument = xdr_void; 363 xdr_result = xdr_utmpidlearr; 364 switch (rqstp->rq_vers) { 365 case RUSERSVERS_ORIG: 366 local = (char *(*)()) rusersproc_allnames_1_svc; 367 break; 368 case RUSERSVERS_IDLE: 369 local = (char *(*)()) rusersproc_allnames_2_svc; 370 break; 371 default: 372 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 373 goto leave; 374 /*NOTREACHED*/ 375 } 376 break; 377 378 default: 379 svcerr_noproc(transp); 380 goto leave; 381 } 382 bzero((char *)&argument, sizeof(argument)); 383 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 384 svcerr_decode(transp); 385 goto leave; 386 } 387 result = (*local)(&argument, rqstp); 388 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 389 svcerr_systemerr(transp); 390 } 391 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 392 syslog(LOG_ERR, "unable to free arguments"); 393 exit(1); 394 } 395 leave: 396 if (from_inetd) 397 exit(0); 398 } 399