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