1 /* $NetBSD: rusers_proc.c,v 1.23 2001/01/10 01:54:39 lukem 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.23 2001/01/10 01:54:39 lukem Exp $"); 34 #endif /* not lint */ 35 36 #include <sys/types.h> 37 #include <sys/time.h> 38 #include <sys/socket.h> 39 #include <sys/param.h> 40 #include <sys/stat.h> 41 42 #include <stdio.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include <time.h> 46 #include <unistd.h> 47 #include <signal.h> 48 #include <syslog.h> 49 #include <utmp.h> 50 51 #include <rpc/rpc.h> 52 53 #include "rusers_proc.h" 54 55 #ifdef XIDLE 56 #include <setjmp.h> 57 #include <X11/Xlib.h> 58 #include <X11/extensions/xidle.h> 59 #endif 60 #include <rpcsvc/rusers.h> /* New version */ 61 #include <rpcsvc/rnusers.h> /* Old version */ 62 63 #define IGNOREUSER "sleeper" 64 65 #ifdef OSF 66 #define _PATH_UTMP UTMP_FILE 67 #endif 68 69 #ifndef _PATH_UTMP 70 #define _PATH_UTMP "/etc/utmp" 71 #endif 72 73 #ifndef _PATH_DEV 74 #define _PATH_DEV "/dev" 75 #endif 76 77 #ifndef UT_LINESIZE 78 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line) 79 #endif 80 #ifndef UT_NAMESIZE 81 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) 82 #endif 83 #ifndef UT_HOSTSIZE 84 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) 85 #endif 86 87 typedef char ut_line_t[UT_LINESIZE]; 88 typedef char ut_name_t[UT_NAMESIZE]; 89 typedef char ut_host_t[UT_HOSTSIZE]; 90 91 static struct rusers_utmp utmps[MAXUSERS]; 92 static struct utmpidle *utmp_idlep[MAXUSERS]; 93 static struct utmpidle utmp_idle[MAXUSERS]; 94 static ut_line_t line[MAXUSERS]; 95 static ut_name_t name[MAXUSERS]; 96 static ut_host_t host[MAXUSERS]; 97 98 extern int from_inetd; 99 100 static int getidle(char *, char *); 101 static int *rusers_num_svc(void *, struct svc_req *); 102 static utmp_array *do_names_3(int); 103 static struct utmpidlearr *do_names_2(int); 104 105 /* XXX */ 106 struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *); 107 struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *); 108 109 110 #ifdef XIDLE 111 static Display *dpy; 112 static sigjmp_buf openAbort; 113 114 static int XqueryIdle __P((char *)); 115 static void abortOpen __P((int)); 116 117 static void 118 abortOpen(int n) 119 { 120 siglongjmp(openAbort, 1); 121 } 122 123 static int 124 XqueryIdle(char *display) 125 { 126 int first_event, first_error; 127 Time IdleTime; 128 129 (void) signal(SIGALRM, abortOpen); 130 (void) alarm(10); 131 if (!sigsetjmp(openAbort, 0)) { 132 if ((dpy = XOpenDisplay(display)) == NULL) { 133 syslog(LOG_DEBUG, "cannot open display %s", display); 134 return (-1); 135 } 136 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 137 if (!XGetIdleTime(dpy, &IdleTime)) { 138 syslog(LOG_DEBUG, "%s: unable to get idle time", 139 display); 140 return (-1); 141 } 142 } else { 143 syslog(LOG_DEBUG, "%s: Xidle extension not loaded", 144 display); 145 return (-1); 146 } 147 XCloseDisplay(dpy); 148 } else { 149 syslog(LOG_DEBUG, "%s: server grabbed for over 10 seconds", 150 display); 151 return (-1); 152 } 153 (void) alarm(0); 154 (void) signal(SIGALRM, SIG_DFL); 155 156 IdleTime /= 1000; 157 return ((IdleTime + 30) / 60); 158 } 159 #endif /* XIDLE */ 160 161 static int 162 getidle(char *tty, char *display) 163 { 164 struct stat st; 165 char devname[PATH_MAX]; 166 time_t now; 167 long idle; 168 169 /* 170 * If this is an X terminal or console, then try the 171 * XIdle extension 172 */ 173 #ifdef XIDLE 174 if (display && *display && strchr(display, ':') != NULL && 175 (idle = XqueryIdle(display)) >= 0) 176 return (idle); 177 #endif 178 idle = 0; 179 if (*tty == 'X') { 180 long kbd_idle, mouse_idle; 181 #if !defined(i386) 182 kbd_idle = getidle("kbd", NULL); 183 #else 184 /* 185 * XXX Icky i386 console hack. 186 */ 187 kbd_idle = getidle("vga", NULL); 188 #endif 189 mouse_idle = getidle("mouse", NULL); 190 idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle; 191 } else { 192 snprintf(devname, sizeof devname, "%s/%s", _PATH_DEV, tty); 193 if (stat(devname, &st) == -1) { 194 syslog(LOG_WARNING, "Cannot stat %s (%m)", devname); 195 return 0; 196 } 197 (void)time(&now); 198 #ifdef DEBUG 199 printf("%s: now=%ld atime=%ld\n", devname, 200 (long)now, (long)st.st_atime); 201 #endif 202 idle = now - st.st_atime; 203 idle = (idle + 30) / 60; /* secs->mins */ 204 } 205 if (idle < 0) 206 idle = 0; 207 208 return idle; 209 } 210 211 static int * 212 rusers_num_svc(void *arg, struct svc_req *rqstp) 213 { 214 static int num_users = 0; 215 struct utmp usr; 216 FILE *ufp; 217 218 ufp = fopen(_PATH_UTMP, "r"); 219 if (!ufp) { 220 syslog(LOG_WARNING, "%m"); 221 return (0); 222 } 223 224 /* only entries with both name and line fields */ 225 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 226 if (*usr.ut_name && *usr.ut_line && 227 strncmp(usr.ut_name, IGNOREUSER, 228 sizeof(usr.ut_name)) 229 #ifdef OSF 230 && usr.ut_type == USER_PROCESS 231 #endif 232 ) { 233 num_users++; 234 } 235 236 fclose(ufp); 237 return (&num_users); 238 } 239 240 static utmp_array * 241 do_names_3(int all) 242 { 243 static utmp_array ut; 244 struct utmp usr; 245 int nusers = 0; 246 FILE *ufp; 247 248 memset(&ut, 0, sizeof(ut)); 249 ut.utmp_array_val = &utmps[0]; 250 251 ufp = fopen(_PATH_UTMP, "r"); 252 if (!ufp) { 253 syslog(LOG_WARNING, "%m"); 254 return (NULL); 255 } 256 257 /* only entries with both name and line fields */ 258 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 259 nusers < MAXUSERS) 260 if (*usr.ut_name && *usr.ut_line && 261 strncmp(usr.ut_name, IGNOREUSER, 262 sizeof(usr.ut_name)) 263 #ifdef OSF 264 && usr.ut_type == USER_PROCESS 265 #endif 266 ) { 267 utmps[nusers].ut_type = RUSERS_USER_PROCESS; 268 utmps[nusers].ut_time = 269 usr.ut_time; 270 utmps[nusers].ut_idle = 271 getidle(usr.ut_line, usr.ut_host); 272 utmps[nusers].ut_line = line[nusers]; 273 strncpy(line[nusers], usr.ut_line, 274 sizeof(line[nusers])); 275 utmps[nusers].ut_user = name[nusers]; 276 strncpy(name[nusers], usr.ut_name, 277 sizeof(name[nusers])); 278 utmps[nusers].ut_host = host[nusers]; 279 strncpy(host[nusers], usr.ut_host, 280 sizeof(host[nusers])); 281 nusers++; 282 } 283 ut.utmp_array_len = nusers; 284 285 fclose(ufp); 286 return (&ut); 287 } 288 289 utmp_array * 290 rusersproc_names_3_svc(void *arg, struct svc_req *rqstp) 291 { 292 293 return (do_names_3(0)); 294 } 295 296 utmp_array * 297 rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp) 298 { 299 300 return (do_names_3(1)); 301 } 302 303 static struct utmpidlearr * 304 do_names_2(int all) 305 { 306 static struct utmpidlearr ut; 307 struct utmp usr; 308 int nusers = 0; 309 FILE *ufp; 310 311 memset((char *)&ut, 0, sizeof(ut)); 312 ut.uia_arr = utmp_idlep; 313 ut.uia_cnt = 0; 314 315 ufp = fopen(_PATH_UTMP, "r"); 316 if (!ufp) { 317 syslog(LOG_WARNING, "%m"); 318 return (NULL); 319 } 320 321 /* only entries with both name and line fields */ 322 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 323 nusers < MAXUSERS) 324 if (*usr.ut_name && *usr.ut_line && 325 strncmp(usr.ut_name, IGNOREUSER, 326 sizeof(usr.ut_name)) 327 #ifdef OSF 328 && usr.ut_type == USER_PROCESS 329 #endif 330 ) { 331 utmp_idlep[nusers] = &utmp_idle[nusers]; 332 utmp_idle[nusers].ui_utmp.ut_time = 333 usr.ut_time; 334 utmp_idle[nusers].ui_idle = 335 getidle(usr.ut_line, usr.ut_host); 336 strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, 337 sizeof(utmp_idle[nusers].ui_utmp.ut_line)); 338 strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, 339 sizeof(utmp_idle[nusers].ui_utmp.ut_name)); 340 strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, 341 sizeof(utmp_idle[nusers].ui_utmp.ut_host)); 342 nusers++; 343 } 344 345 ut.uia_cnt = nusers; 346 fclose(ufp); 347 return (&ut); 348 } 349 350 struct utmpidlearr * 351 rusersproc_names_2_svc(void *arg, struct svc_req *rqstp) 352 { 353 return (do_names_2(0)); 354 } 355 356 struct utmpidlearr * 357 rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp) 358 { 359 return (do_names_2(1)); 360 } 361 362 void 363 rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 364 { 365 union { 366 int fill; 367 } argument; 368 char *result; 369 xdrproc_t xdr_argument, xdr_result; 370 char *(*local) __P((void *, struct svc_req *)); 371 372 switch (rqstp->rq_proc) { 373 case NULLPROC: 374 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 375 goto leave; 376 377 case RUSERSPROC_NUM: 378 xdr_argument = (xdrproc_t)xdr_void; 379 xdr_result = (xdrproc_t)xdr_int; 380 switch (rqstp->rq_vers) { 381 case RUSERSVERS_3: 382 case RUSERSVERS_IDLE: 383 local = (char *(*) __P((void *, struct svc_req *))) 384 rusers_num_svc; 385 break; 386 default: 387 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 388 goto leave; 389 /*NOTREACHED*/ 390 } 391 break; 392 393 case RUSERSPROC_NAMES: 394 xdr_argument = (xdrproc_t)xdr_void; 395 xdr_result = (xdrproc_t)xdr_utmp_array; 396 switch (rqstp->rq_vers) { 397 case RUSERSVERS_3: 398 local = (char *(*) __P((void *, struct svc_req *))) 399 rusersproc_names_3_svc; 400 break; 401 402 case RUSERSVERS_IDLE: 403 xdr_result = (xdrproc_t)xdr_utmpidlearr; 404 local = (char *(*) __P((void *, struct svc_req *))) 405 rusersproc_names_2_svc; 406 break; 407 408 default: 409 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 410 goto leave; 411 /*NOTREACHED*/ 412 } 413 break; 414 415 case RUSERSPROC_ALLNAMES: 416 xdr_argument = (xdrproc_t)xdr_void; 417 xdr_result = (xdrproc_t)xdr_utmp_array; 418 switch (rqstp->rq_vers) { 419 case RUSERSVERS_3: 420 local = (char *(*) __P((void *, struct svc_req *))) 421 rusersproc_allnames_3_svc; 422 break; 423 424 case RUSERSVERS_IDLE: 425 xdr_result = (xdrproc_t)xdr_utmpidlearr; 426 local = (char *(*) __P((void *, struct svc_req *))) 427 rusersproc_allnames_2_svc; 428 break; 429 430 default: 431 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 432 goto leave; 433 /*NOTREACHED*/ 434 } 435 break; 436 437 default: 438 svcerr_noproc(transp); 439 goto leave; 440 } 441 memset((char *)&argument, 0, sizeof(argument)); 442 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 443 svcerr_decode(transp); 444 goto leave; 445 } 446 result = (*local)(&argument, rqstp); 447 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 448 svcerr_systemerr(transp); 449 } 450 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 451 syslog(LOG_ERR, "unable to free arguments"); 452 exit(1); 453 } 454 leave: 455 if (from_inetd) 456 exit(0); 457 } 458