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