rusers_proc.c revision 115668
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 115668 2003-06-02 02:35:18Z obrien $"; 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 82typedef char ut_line_t[UT_LINESIZE+1]; 83typedef char ut_name_t[UT_NAMESIZE+1]; 84typedef char ut_host_t[UT_HOSTSIZE+1]; 85 86utmpidle utmp_idle[MAXUSERS]; 87rutmp old_utmp[MAXUSERS]; 88ut_line_t line[MAXUSERS]; 89ut_name_t name[MAXUSERS]; 90ut_host_t host[MAXUSERS]; 91 92extern int from_inetd; 93 94FILE *ufp; 95 96#ifdef XIDLE 97Display *dpy; 98 99static jmp_buf openAbort; 100 101static void 102abortOpen(void) 103{ 104 longjmp (openAbort, 1); 105} 106 107XqueryIdle(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 143static u_int 144getidle(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 191static utmpidlearr * 192do_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 240int * 241rusers_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 268static utmparr * 269do_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 290utmpidlearr * 291rusersproc_names_2_svc(void *argp, struct svc_req *rqstp) 292{ 293 return(do_names_2(0)); 294} 295 296utmpidlearr * 297rusersproc_allnames_2_svc(void *argp, struct svc_req *rqstp) 298{ 299 return(do_names_2(1)); 300} 301 302utmparr * 303rusersproc_names_1_svc(void *argp, struct svc_req *rqstp) 304{ 305 return(do_names_1(0)); 306} 307 308utmparr * 309rusersproc_allnames_1_svc(void *argp, struct svc_req *rqstp) 310{ 311 return(do_names_1(1)); 312} 313 314void 315rusers_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 } 387leave: 388 if (from_inetd) 389 exit(0); 390} 391