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