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. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef lint 30 static char rcsid[] = "$Id: rusers_proc.c,v 1.7 1993/11/23 04:40:28 cgd Exp $"; 31 #endif /* not lint */ 32 33 #include <signal.h> 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <utmp.h> 37 #include <stdio.h> 38 #include <syslog.h> 39 #include <rpc/rpc.h> 40 #include <sys/socket.h> 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #ifdef XIDLE 44 #include <setjmp.h> 45 #include <X11/Xlib.h> 46 #include <X11/extensions/xidle.h> 47 #endif 48 #include <rpcsvc/rusers.h> /* New version */ 49 #include <rpcsvc/rnusers.h> /* Old version */ 50 51 #define IGNOREUSER "sleeper" 52 53 #ifdef OSF 54 #define _PATH_UTMP UTMP_FILE 55 #endif 56 57 #ifndef _PATH_UTMP 58 #define _PATH_UTMP "/etc/utmp" 59 #endif 60 61 #ifndef _PATH_DEV 62 #define _PATH_DEV "/dev" 63 #endif 64 65 #ifndef UT_LINESIZE 66 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line) 67 #endif 68 #ifndef UT_NAMESIZE 69 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) 70 #endif 71 #ifndef UT_HOSTSIZE 72 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) 73 #endif 74 75 typedef char ut_line_t[UT_LINESIZE]; 76 typedef char ut_name_t[UT_NAMESIZE]; 77 typedef char ut_host_t[UT_HOSTSIZE]; 78 79 struct rusers_utmp utmps[MAXUSERS]; 80 struct utmpidle *utmp_idlep[MAXUSERS]; 81 struct utmpidle utmp_idle[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; 144 145 /* 146 * If this is an X terminal or console, then try the 147 * XIdle extension 148 */ 149 #ifdef XIDLE 150 if (display && *display && (idle = XqueryIdle(display)) >= 0) 151 return(idle); 152 #endif 153 idle = 0; 154 if (*tty == 'X') { 155 u_long kbd_idle, mouse_idle; 156 #if !defined(i386) 157 kbd_idle = getidle("kbd", NULL); 158 #else 159 #if (__GNUC__ >= 2) 160 #warning i386 console hack here 161 #endif 162 kbd_idle = getidle("vga", NULL); 163 #endif 164 mouse_idle = getidle("mouse", NULL); 165 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle; 166 } 167 else { 168 sprintf(devname, "%s/%s", _PATH_DEV, tty); 169 if (stat(devname, &st) < 0) { 170 #ifdef DEBUG 171 printf("%s: %s\n", devname, strerror(errno)); 172 #endif 173 return(-1); 174 } 175 time(&now); 176 #ifdef DEBUG 177 printf("%s: now=%d atime=%d\n", devname, now, 178 st.st_atime); 179 #endif 180 idle = now - st.st_atime; 181 idle = (idle + 30) / 60; /* secs->mins */ 182 } 183 if (idle < 0) idle = 0; 184 185 return(idle); 186 } 187 188 int * 189 rusers_num() 190 { 191 int num_users = 0; 192 struct utmp usr; 193 194 ufp = fopen(_PATH_UTMP, "r"); 195 if (!ufp) { 196 syslog(LOG_ERR, "%m"); 197 return(0); 198 } 199 200 /* only entries with both name and line fields */ 201 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 202 if (*usr.ut_name && *usr.ut_line && 203 strncmp(usr.ut_name, IGNOREUSER, 204 sizeof(usr.ut_name)) 205 #ifdef OSF 206 && usr.ut_type == USER_PROCESS 207 #endif 208 ) { 209 num_users++; 210 } 211 212 fclose(ufp); 213 return(&num_users); 214 } 215 216 static utmp_array * 217 do_names_3(int all) 218 { 219 static utmp_array ut; 220 struct utmp usr; 221 int nusers = 0; 222 223 bzero((char *)&ut, sizeof(ut)); 224 ut.utmp_array_val = &utmps[0]; 225 226 ufp = fopen(_PATH_UTMP, "r"); 227 if (!ufp) { 228 syslog(LOG_ERR, "%m"); 229 return(&ut); 230 } 231 232 /* only entries with both name and line fields */ 233 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 234 nusers < MAXUSERS) 235 if (*usr.ut_name && *usr.ut_line && 236 strncmp(usr.ut_name, IGNOREUSER, 237 sizeof(usr.ut_name)) 238 #ifdef OSF 239 && usr.ut_type == USER_PROCESS 240 #endif 241 ) { 242 utmps[nusers].ut_type = RUSERS_USER_PROCESS; 243 utmps[nusers].ut_time = 244 usr.ut_time; 245 utmps[nusers].ut_idle = 246 getidle(usr.ut_line, usr.ut_host); 247 utmps[nusers].ut_line = line[nusers]; 248 strncpy(line[nusers], usr.ut_line, sizeof(line[nusers])); 249 utmps[nusers].ut_user = name[nusers]; 250 strncpy(name[nusers], usr.ut_name, sizeof(name[nusers])); 251 utmps[nusers].ut_host = host[nusers]; 252 strncpy(host[nusers], usr.ut_host, sizeof(host[nusers])); 253 nusers++; 254 } 255 ut.utmp_array_len = nusers; 256 257 fclose(ufp); 258 return(&ut); 259 } 260 261 utmp_array * 262 rusersproc_names_3() 263 { 264 return(do_names_3(0)); 265 } 266 267 utmp_array * 268 rusersproc_allnames_3() 269 { 270 return(do_names_3(1)); 271 } 272 273 static struct utmpidlearr * 274 do_names_2(int all) 275 { 276 static struct utmpidlearr ut; 277 struct utmp usr; 278 int nusers = 0; 279 280 bzero((char *)&ut, sizeof(ut)); 281 ut.uia_arr = utmp_idlep; 282 ut.uia_cnt = 0; 283 284 ufp = fopen(_PATH_UTMP, "r"); 285 if (!ufp) { 286 syslog(LOG_ERR, "%m"); 287 return(&ut); 288 } 289 290 /* only entries with both name and line fields */ 291 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 292 nusers < MAXUSERS) 293 if (*usr.ut_name && *usr.ut_line && 294 strncmp(usr.ut_name, IGNOREUSER, 295 sizeof(usr.ut_name)) 296 #ifdef OSF 297 && usr.ut_type == USER_PROCESS 298 #endif 299 ) { 300 utmp_idlep[nusers] = &utmp_idle[nusers]; 301 utmp_idle[nusers].ui_utmp.ut_time = 302 usr.ut_time; 303 utmp_idle[nusers].ui_idle = 304 getidle(usr.ut_line, usr.ut_host); 305 strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, sizeof(utmp_idle[nusers].ui_utmp.ut_line)); 306 strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, sizeof(utmp_idle[nusers].ui_utmp.ut_name)); 307 strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, sizeof(utmp_idle[nusers].ui_utmp.ut_host)); 308 nusers++; 309 } 310 311 ut.uia_cnt = nusers; 312 fclose(ufp); 313 return(&ut); 314 } 315 316 struct utmpidlearr * 317 rusersproc_names_2() 318 { 319 return(do_names_2(0)); 320 } 321 322 struct utmpidlearr * 323 rusersproc_allnames_2() 324 { 325 return(do_names_2(1)); 326 } 327 328 void 329 rusers_service(rqstp, transp) 330 struct svc_req *rqstp; 331 SVCXPRT *transp; 332 { 333 union { 334 int fill; 335 } argument; 336 char *result; 337 bool_t (*xdr_argument)(), (*xdr_result)(); 338 char *(*local)(); 339 340 switch (rqstp->rq_proc) { 341 case NULLPROC: 342 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 343 goto leave; 344 345 case RUSERSPROC_NUM: 346 xdr_argument = xdr_void; 347 xdr_result = xdr_int; 348 switch (rqstp->rq_vers) { 349 case RUSERSVERS_3: 350 case RUSERSVERS_IDLE: 351 local = (char *(*)()) rusers_num; 352 break; 353 default: 354 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 355 goto leave; 356 /*NOTREACHED*/ 357 } 358 break; 359 360 case RUSERSPROC_NAMES: 361 xdr_argument = xdr_void; 362 xdr_result = xdr_utmp_array; 363 switch (rqstp->rq_vers) { 364 case RUSERSVERS_3: 365 local = (char *(*)()) rusersproc_names_3; 366 break; 367 368 case RUSERSVERS_IDLE: 369 xdr_result = xdr_utmpidlearr; 370 local = (char *(*)()) rusersproc_names_2; 371 break; 372 373 default: 374 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 375 goto leave; 376 /*NOTREACHED*/ 377 } 378 break; 379 380 case RUSERSPROC_ALLNAMES: 381 xdr_argument = xdr_void; 382 xdr_result = xdr_utmp_array; 383 switch (rqstp->rq_vers) { 384 case RUSERSVERS_3: 385 local = (char *(*)()) rusersproc_allnames_3; 386 break; 387 388 case RUSERSVERS_IDLE: 389 xdr_result = xdr_utmpidlearr; 390 local = (char *(*)()) rusersproc_allnames_2; 391 break; 392 393 default: 394 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 395 goto leave; 396 /*NOTREACHED*/ 397 } 398 break; 399 400 default: 401 svcerr_noproc(transp); 402 goto leave; 403 } 404 bzero((char *)&argument, sizeof(argument)); 405 if (!svc_getargs(transp, xdr_argument, &argument)) { 406 svcerr_decode(transp); 407 goto leave; 408 } 409 result = (*local)(&argument, rqstp); 410 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 411 svcerr_systemerr(transp); 412 } 413 if (!svc_freeargs(transp, xdr_argument, &argument)) { 414 (void)fprintf(stderr, "unable to free arguments\n"); 415 exit(1); 416 } 417 leave: 418 if (from_inetd) 419 exit(0); 420 } 421