1 /* $NetBSD: rusers_proc.c,v 1.15 1997/09/19 00:50:04 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #ifndef lint 33 __RCSID("$NetBSD: rusers_proc.c,v 1.15 1997/09/19 00:50:04 thorpej Exp $"); 34 #endif /* not lint */ 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <signal.h> 41 #include <syslog.h> 42 #include <utmp.h> 43 44 #include <sys/types.h> 45 #include <sys/time.h> 46 #include <sys/socket.h> 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 50 #include <rpc/rpc.h> 51 52 #include "rusers_proc.h" 53 54 #ifdef XIDLE 55 #include <setjmp.h> 56 #include <X11/Xlib.h> 57 #include <X11/extensions/xidle.h> 58 #endif 59 #include <rpcsvc/rusers.h> /* New version */ 60 #include <rpcsvc/rnusers.h> /* Old version */ 61 62 #define IGNOREUSER "sleeper" 63 64 #ifdef OSF 65 #define _PATH_UTMP UTMP_FILE 66 #endif 67 68 #ifndef _PATH_UTMP 69 #define _PATH_UTMP "/etc/utmp" 70 #endif 71 72 #ifndef _PATH_DEV 73 #define _PATH_DEV "/dev" 74 #endif 75 76 #ifndef UT_LINESIZE 77 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line) 78 #endif 79 #ifndef UT_NAMESIZE 80 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) 81 #endif 82 #ifndef UT_HOSTSIZE 83 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) 84 #endif 85 86 typedef char ut_line_t[UT_LINESIZE]; 87 typedef char ut_name_t[UT_NAMESIZE]; 88 typedef char ut_host_t[UT_HOSTSIZE]; 89 90 static struct rusers_utmp utmps[MAXUSERS]; 91 static struct utmpidle *utmp_idlep[MAXUSERS]; 92 static struct utmpidle utmp_idle[MAXUSERS]; 93 static ut_line_t line[MAXUSERS]; 94 static ut_name_t name[MAXUSERS]; 95 static ut_host_t host[MAXUSERS]; 96 97 extern int from_inetd; 98 99 static u_int getidle __P((char *, char *)); 100 static int *rusers_num_svc __P((void *, struct svc_req *)); 101 static utmp_array *do_names_3 __P((int)); 102 static struct utmpidlearr *do_names_2 __P((int)); 103 104 /* XXX */ 105 struct utmpidlearr *rusersproc_names_2_svc __P((void *, struct svc_req *)); 106 struct utmpidlearr *rusersproc_allnames_2_svc __P((void *, struct svc_req *)); 107 108 109 #ifdef XIDLE 110 static Display *dpy; 111 static sigjmp_buf openAbort; 112 113 static int XqueryIdle __P((char *)); 114 static void abortOpen __P((int)); 115 116 static void 117 abortOpen(n) 118 int n; 119 { 120 siglongjmp(openAbort, 1); 121 } 122 123 static int 124 XqueryIdle(display) 125 char *display; 126 { 127 int first_event, first_error; 128 Time IdleTime; 129 130 (void) signal(SIGALRM, abortOpen); 131 (void) alarm(10); 132 if (!sigsetjmp(openAbort, 0)) { 133 if ((dpy = XOpenDisplay(display)) == NULL) { 134 syslog(LOG_ERR, "cannot open display %s", display); 135 return (-1); 136 } 137 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 138 if (!XGetIdleTime(dpy, &IdleTime)) { 139 syslog(LOG_ERR, "%s: unable to get idle time", 140 display); 141 return (-1); 142 } 143 } else { 144 syslog(LOG_ERR, "%s: Xidle extension not loaded", 145 display); 146 return (-1); 147 } 148 XCloseDisplay(dpy); 149 } else { 150 syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", 151 display); 152 return (-1); 153 } 154 (void) alarm(0); 155 (void) signal(SIGALRM, SIG_DFL); 156 157 IdleTime /= 1000; 158 return ((IdleTime + 30) / 60); 159 } 160 #endif /* XIDLE */ 161 162 static u_int 163 getidle(tty, display) 164 char *tty, *display; 165 { 166 struct stat st; 167 char devname[PATH_MAX]; 168 time_t now; 169 u_long idle; 170 171 /* 172 * If this is an X terminal or console, then try the 173 * XIdle extension 174 */ 175 #ifdef XIDLE 176 if (display && *display && (idle = XqueryIdle(display)) >= 0) 177 return (idle); 178 #endif 179 idle = 0; 180 if (*tty == 'X') { 181 u_long kbd_idle, mouse_idle; 182 #if !defined(i386) 183 kbd_idle = getidle("kbd", NULL); 184 #else 185 /* 186 * XXX Icky i386 console hack. 187 */ 188 kbd_idle = getidle("vga", NULL); 189 #endif 190 mouse_idle = getidle("mouse", NULL); 191 idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle; 192 } else { 193 sprintf(devname, "%s/%s", _PATH_DEV, tty); 194 if (stat(devname, &st) < 0) { 195 #ifdef DEBUG 196 printf("%s: %m\n", devname); 197 #endif 198 return (-1); 199 } 200 time(&now); 201 #ifdef DEBUG 202 printf("%s: now=%d atime=%d\n", devname, now, st.st_atime); 203 #endif 204 idle = now - st.st_atime; 205 idle = (idle + 30) / 60; /* secs->mins */ 206 } 207 if (idle < 0) 208 idle = 0; 209 210 return (idle); 211 } 212 213 static int * 214 rusers_num_svc(arg, rqstp) 215 void *arg; 216 struct svc_req *rqstp; 217 { 218 static int num_users = 0; 219 struct utmp usr; 220 FILE *ufp; 221 222 ufp = fopen(_PATH_UTMP, "r"); 223 if (!ufp) { 224 syslog(LOG_ERR, "%m"); 225 return (0); 226 } 227 228 /* only entries with both name and line fields */ 229 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 230 if (*usr.ut_name && *usr.ut_line && 231 strncmp(usr.ut_name, IGNOREUSER, 232 sizeof(usr.ut_name)) 233 #ifdef OSF 234 && usr.ut_type == USER_PROCESS 235 #endif 236 ) { 237 num_users++; 238 } 239 240 fclose(ufp); 241 return (&num_users); 242 } 243 244 static utmp_array * 245 do_names_3(int all) 246 { 247 static utmp_array ut; 248 struct utmp usr; 249 int nusers = 0; 250 FILE *ufp; 251 252 memset(&ut, 0, sizeof(ut)); 253 ut.utmp_array_val = &utmps[0]; 254 255 ufp = fopen(_PATH_UTMP, "r"); 256 if (!ufp) { 257 syslog(LOG_ERR, "%m"); 258 return (NULL); 259 } 260 261 /* only entries with both name and line fields */ 262 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 263 nusers < MAXUSERS) 264 if (*usr.ut_name && *usr.ut_line && 265 strncmp(usr.ut_name, IGNOREUSER, 266 sizeof(usr.ut_name)) 267 #ifdef OSF 268 && usr.ut_type == USER_PROCESS 269 #endif 270 ) { 271 utmps[nusers].ut_type = RUSERS_USER_PROCESS; 272 utmps[nusers].ut_time = 273 usr.ut_time; 274 utmps[nusers].ut_idle = 275 getidle(usr.ut_line, usr.ut_host); 276 utmps[nusers].ut_line = line[nusers]; 277 strncpy(line[nusers], usr.ut_line, 278 sizeof(line[nusers])); 279 utmps[nusers].ut_user = name[nusers]; 280 strncpy(name[nusers], usr.ut_name, 281 sizeof(name[nusers])); 282 utmps[nusers].ut_host = host[nusers]; 283 strncpy(host[nusers], usr.ut_host, 284 sizeof(host[nusers])); 285 nusers++; 286 } 287 ut.utmp_array_len = nusers; 288 289 fclose(ufp); 290 return (&ut); 291 } 292 293 utmp_array * 294 rusersproc_names_3_svc(arg, rqstp) 295 void *arg; 296 struct svc_req *rqstp; 297 { 298 return (do_names_3(0)); 299 } 300 301 utmp_array * 302 rusersproc_allnames_3_svc(arg, rqstp) 303 void *arg; 304 struct svc_req *rqstp; 305 { 306 return (do_names_3(1)); 307 } 308 309 static struct utmpidlearr * 310 do_names_2(int all) 311 { 312 static struct utmpidlearr ut; 313 struct utmp usr; 314 int nusers = 0; 315 FILE *ufp; 316 317 bzero((char *)&ut, sizeof(ut)); 318 ut.uia_arr = utmp_idlep; 319 ut.uia_cnt = 0; 320 321 ufp = fopen(_PATH_UTMP, "r"); 322 if (!ufp) { 323 syslog(LOG_ERR, "%m"); 324 return (NULL); 325 } 326 327 /* only entries with both name and line fields */ 328 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 329 nusers < MAXUSERS) 330 if (*usr.ut_name && *usr.ut_line && 331 strncmp(usr.ut_name, IGNOREUSER, 332 sizeof(usr.ut_name)) 333 #ifdef OSF 334 && usr.ut_type == USER_PROCESS 335 #endif 336 ) { 337 utmp_idlep[nusers] = &utmp_idle[nusers]; 338 utmp_idle[nusers].ui_utmp.ut_time = 339 usr.ut_time; 340 utmp_idle[nusers].ui_idle = 341 getidle(usr.ut_line, usr.ut_host); 342 strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, 343 sizeof(utmp_idle[nusers].ui_utmp.ut_line)); 344 strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, 345 sizeof(utmp_idle[nusers].ui_utmp.ut_name)); 346 strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, 347 sizeof(utmp_idle[nusers].ui_utmp.ut_host)); 348 nusers++; 349 } 350 351 ut.uia_cnt = nusers; 352 fclose(ufp); 353 return (&ut); 354 } 355 356 struct utmpidlearr * 357 rusersproc_names_2_svc(arg, rqstp) 358 void *arg; 359 struct svc_req *rqstp; 360 { 361 return (do_names_2(0)); 362 } 363 364 struct utmpidlearr * 365 rusersproc_allnames_2_svc(arg, rqstp) 366 void *arg; 367 struct svc_req *rqstp; 368 { 369 return (do_names_2(1)); 370 } 371 372 void 373 rusers_service(rqstp, transp) 374 struct svc_req *rqstp; 375 SVCXPRT *transp; 376 { 377 union { 378 int fill; 379 } argument; 380 char *result; 381 xdrproc_t xdr_argument, xdr_result; 382 char *(*local) __P((void *, struct svc_req *)); 383 384 switch (rqstp->rq_proc) { 385 case NULLPROC: 386 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 387 goto leave; 388 389 case RUSERSPROC_NUM: 390 xdr_argument = (xdrproc_t)xdr_void; 391 xdr_result = (xdrproc_t)xdr_int; 392 switch (rqstp->rq_vers) { 393 case RUSERSVERS_3: 394 case RUSERSVERS_IDLE: 395 local = (char *(*) __P((void *, struct svc_req *))) 396 rusers_num_svc; 397 break; 398 default: 399 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 400 goto leave; 401 /*NOTREACHED*/ 402 } 403 break; 404 405 case RUSERSPROC_NAMES: 406 xdr_argument = (xdrproc_t)xdr_void; 407 xdr_result = (xdrproc_t)xdr_utmp_array; 408 switch (rqstp->rq_vers) { 409 case RUSERSVERS_3: 410 local = (char *(*) __P((void *, struct svc_req *))) 411 rusersproc_names_3_svc; 412 break; 413 414 case RUSERSVERS_IDLE: 415 xdr_result = (xdrproc_t)xdr_utmpidlearr; 416 local = (char *(*) __P((void *, struct svc_req *))) 417 rusersproc_names_2_svc; 418 break; 419 420 default: 421 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 422 goto leave; 423 /*NOTREACHED*/ 424 } 425 break; 426 427 case RUSERSPROC_ALLNAMES: 428 xdr_argument = (xdrproc_t)xdr_void; 429 xdr_result = (xdrproc_t)xdr_utmp_array; 430 switch (rqstp->rq_vers) { 431 case RUSERSVERS_3: 432 local = (char *(*) __P((void *, struct svc_req *))) 433 rusersproc_allnames_3_svc; 434 break; 435 436 case RUSERSVERS_IDLE: 437 xdr_result = (xdrproc_t)xdr_utmpidlearr; 438 local = (char *(*) __P((void *, struct svc_req *))) 439 rusersproc_allnames_2_svc; 440 break; 441 442 default: 443 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 444 goto leave; 445 /*NOTREACHED*/ 446 } 447 break; 448 449 default: 450 svcerr_noproc(transp); 451 goto leave; 452 } 453 bzero((char *)&argument, sizeof(argument)); 454 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 455 svcerr_decode(transp); 456 goto leave; 457 } 458 result = (*local)(&argument, rqstp); 459 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 460 svcerr_systemerr(transp); 461 } 462 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 463 (void)fprintf(stderr, "unable to free arguments\n"); 464 exit(1); 465 } 466 leave: 467 if (from_inetd) 468 exit(0); 469 } 470