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