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 "$FreeBSD$"; 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 <stdlib.h> 47 #include <syslog.h> 48 #include <utmp.h> 49 #ifdef XIDLE 50 #include <setjmp.h> 51 #include <X11/Xlib.h> 52 #include <X11/extensions/xidle.h> 53 #endif 54 #define utmp rutmp 55 #include <rpcsvc/rnusers.h> 56 #undef utmp 57 58 #define IGNOREUSER "sleeper" 59 60 #ifdef OSF 61 #define _PATH_UTMP UTMP_FILE 62 #endif 63 64 #ifndef _PATH_UTMP 65 #define _PATH_UTMP "/etc/utmp" 66 #endif 67 68 #ifndef _PATH_DEV 69 #define _PATH_DEV "/dev" 70 #endif 71 72 #ifndef UT_LINESIZE 73 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line) 74 #endif 75 #ifndef UT_NAMESIZE 76 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) 77 #endif 78 #ifndef UT_HOSTSIZE 79 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) 80 #endif 81 82 typedef char ut_line_t[UT_LINESIZE+1]; 83 typedef char ut_name_t[UT_NAMESIZE+1]; 84 typedef char ut_host_t[UT_HOSTSIZE+1]; 85 86 utmpidle utmp_idle[MAXUSERS]; 87 rutmp old_utmp[MAXUSERS]; 88 ut_line_t line[MAXUSERS]; 89 ut_name_t name[MAXUSERS]; 90 ut_host_t host[MAXUSERS]; 91 92 extern int from_inetd; 93 94 FILE *ufp; 95 96 #ifdef XIDLE 97 Display *dpy; 98 99 static jmp_buf openAbort; 100 101 static void 102 abortOpen(void) 103 { 104 longjmp (openAbort, 1); 105 } 106 107 XqueryIdle(char *display) 108 { 109 int first_event, first_error; 110 Time IdleTime; 111 112 (void) signal (SIGALRM, abortOpen); 113 (void) alarm ((unsigned) 10); 114 if (!setjmp (openAbort)) { 115 if (!(dpy= XOpenDisplay(display))) { 116 syslog(LOG_ERR, "Cannot open display %s", display); 117 return(-1); 118 } 119 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 120 if (!XGetIdleTime(dpy, &IdleTime)) { 121 syslog(LOG_ERR, "%s: unable to get idle time", display); 122 return(-1); 123 } 124 } 125 else { 126 syslog(LOG_ERR, "%s: Xidle extension not loaded", display); 127 return(-1); 128 } 129 XCloseDisplay(dpy); 130 } 131 else { 132 syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display); 133 return(-1); 134 } 135 (void) signal (SIGALRM, SIG_DFL); 136 (void) alarm ((unsigned) 0); 137 138 IdleTime /= 1000; 139 return((IdleTime + 30) / 60); 140 } 141 #endif 142 143 static u_int 144 getidle(char *tty, char *display) 145 { 146 struct stat st; 147 char devname[PATH_MAX]; 148 time_t now; 149 u_long idle; 150 151 /* 152 * If this is an X terminal or console, then try the 153 * XIdle extension 154 */ 155 #ifdef XIDLE 156 if (display && *display && (idle = XqueryIdle(display)) >= 0) 157 return(idle); 158 #endif 159 idle = 0; 160 if (*tty == 'X') { 161 u_long kbd_idle, mouse_idle; 162 #if !defined(__FreeBSD__) 163 kbd_idle = getidle("kbd", NULL); 164 #else 165 kbd_idle = getidle("vga", NULL); 166 #endif 167 mouse_idle = getidle("mouse", NULL); 168 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle; 169 } 170 else { 171 sprintf(devname, "%s/%s", _PATH_DEV, tty); 172 if (stat(devname, &st) < 0) { 173 #ifdef DEBUG 174 printf("%s: %s\n", devname, strerror(errno)); 175 #endif 176 return(-1); 177 } 178 time(&now); 179 #ifdef DEBUG 180 printf("%s: now=%d atime=%d\n", devname, now, 181 st.st_atime); 182 #endif 183 idle = now - st.st_atime; 184 idle = (idle + 30) / 60; /* secs->mins */ 185 } 186 if (idle < 0) idle = 0; 187 188 return(idle); 189 } 190 191 static utmpidlearr * 192 do_names_2(int all) 193 { 194 static utmpidlearr ut; 195 struct utmp usr; 196 int nusers = 0; 197 198 bzero((char *)&ut, sizeof(ut)); 199 ut.utmpidlearr_val = &utmp_idle[0]; 200 201 ufp = fopen(_PATH_UTMP, "r"); 202 if (!ufp) { 203 syslog(LOG_ERR, "%m"); 204 return(&ut); 205 } 206 207 /* only entries with both name and line fields */ 208 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 && 209 nusers < MAXUSERS) 210 if (*usr.ut_name && *usr.ut_line && 211 strncmp(usr.ut_name, IGNOREUSER, 212 sizeof(usr.ut_name)) 213 #ifdef OSF 214 && usr.ut_type == USER_PROCESS 215 #endif 216 ) { 217 utmp_idle[nusers].ui_utmp.ut_time = 218 usr.ut_time; 219 utmp_idle[nusers].ui_idle = 220 getidle(usr.ut_line, usr.ut_host); 221 utmp_idle[nusers].ui_utmp.ut_line = line[nusers]; 222 strncpy(line[nusers], usr.ut_line, UT_LINESIZE); 223 utmp_idle[nusers].ui_utmp.ut_name = name[nusers]; 224 strncpy(name[nusers], usr.ut_name, UT_NAMESIZE); 225 utmp_idle[nusers].ui_utmp.ut_host = host[nusers]; 226 strncpy(host[nusers], usr.ut_host, UT_HOSTSIZE); 227 228 /* Make sure entries are NUL terminated */ 229 line[nusers][UT_LINESIZE] = 230 name[nusers][UT_NAMESIZE] = 231 host[nusers][UT_HOSTSIZE] = '\0'; 232 nusers++; 233 } 234 235 ut.utmpidlearr_len = nusers; 236 fclose(ufp); 237 return(&ut); 238 } 239 240 int * 241 rusers_num(void) 242 { 243 static int num_users = 0; 244 struct utmp usr; 245 246 ufp = fopen(_PATH_UTMP, "r"); 247 if (!ufp) { 248 syslog(LOG_ERR, "%m"); 249 return(NULL); 250 } 251 252 /* only entries with both name and line fields */ 253 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 254 if (*usr.ut_name && *usr.ut_line && 255 strncmp(usr.ut_name, IGNOREUSER, 256 sizeof(usr.ut_name)) 257 #ifdef OSF 258 && usr.ut_type == USER_PROCESS 259 #endif 260 ) { 261 num_users++; 262 } 263 264 fclose(ufp); 265 return(&num_users); 266 } 267 268 static utmparr * 269 do_names_1(int all) 270 { 271 utmpidlearr *utidle; 272 static utmparr ut; 273 int i; 274 275 bzero((char *)&ut, sizeof(ut)); 276 277 utidle = do_names_2(all); 278 if (utidle) { 279 ut.utmparr_len = utidle->utmpidlearr_len; 280 ut.utmparr_val = &old_utmp[0]; 281 for (i = 0; i < ut.utmparr_len; i++) 282 bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i], 283 sizeof(old_utmp[0])); 284 285 } 286 287 return(&ut); 288 } 289 290 utmpidlearr * 291 rusersproc_names_2_svc(void *argp, struct svc_req *rqstp) 292 { 293 return(do_names_2(0)); 294 } 295 296 utmpidlearr * 297 rusersproc_allnames_2_svc(void *argp, struct svc_req *rqstp) 298 { 299 return(do_names_2(1)); 300 } 301 302 utmparr * 303 rusersproc_names_1_svc(void *argp, struct svc_req *rqstp) 304 { 305 return(do_names_1(0)); 306 } 307 308 utmparr * 309 rusersproc_allnames_1_svc(void *argp, struct svc_req *rqstp) 310 { 311 return(do_names_1(1)); 312 } 313 314 void 315 rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 316 { 317 union { 318 int fill; 319 } argument; 320 char *result; 321 bool_t (*xdr_argument)(), (*xdr_result)(); 322 char *(*local)(); 323 324 switch (rqstp->rq_proc) { 325 case NULLPROC: 326 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 327 goto leave; 328 329 case RUSERSPROC_NUM: 330 xdr_argument = xdr_void; 331 xdr_result = xdr_int; 332 local = (char *(*)()) rusers_num; 333 break; 334 335 case RUSERSPROC_NAMES: 336 xdr_argument = xdr_void; 337 xdr_result = xdr_utmpidlearr; 338 switch (rqstp->rq_vers) { 339 case RUSERSVERS_ORIG: 340 local = (char *(*)()) rusersproc_names_1_svc; 341 break; 342 case RUSERSVERS_IDLE: 343 local = (char *(*)()) rusersproc_names_2_svc; 344 break; 345 default: 346 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 347 goto leave; 348 /*NOTREACHED*/ 349 } 350 break; 351 352 case RUSERSPROC_ALLNAMES: 353 xdr_argument = xdr_void; 354 xdr_result = xdr_utmpidlearr; 355 switch (rqstp->rq_vers) { 356 case RUSERSVERS_ORIG: 357 local = (char *(*)()) rusersproc_allnames_1_svc; 358 break; 359 case RUSERSVERS_IDLE: 360 local = (char *(*)()) rusersproc_allnames_2_svc; 361 break; 362 default: 363 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 364 goto leave; 365 /*NOTREACHED*/ 366 } 367 break; 368 369 default: 370 svcerr_noproc(transp); 371 goto leave; 372 } 373 bzero(&argument, sizeof(argument)); 374 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 375 svcerr_decode(transp); 376 goto leave; 377 } 378 result = (*local)(&argument, rqstp); 379 if (result != NULL && 380 !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 381 svcerr_systemerr(transp); 382 } 383 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) { 384 syslog(LOG_ERR, "unable to free arguments"); 385 exit(1); 386 } 387 leave: 388 if (from_inetd) 389 exit(0); 390 } 391