rusers_proc.c revision 201146
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 201146 2009-12-28 23:01:24Z ed $"; 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 86static utmpidle utmp_idle[MAXUSERS]; 87static rutmp old_utmp[MAXUSERS]; 88static ut_line_t line[MAXUSERS]; 89static ut_name_t name[MAXUSERS]; 90static ut_host_t host[MAXUSERS]; 91 92extern int from_inetd; 93 94void rusers_service(struct svc_req *, SVCXPRT *); 95 96static FILE *ufp; 97 98#ifdef XIDLE 99static Display *dpy; 100 101static jmp_buf openAbort; 102 103static void 104abortOpen(void) 105{ 106 longjmp (openAbort, 1); 107} 108 109XqueryIdle(char *display) 110{ 111 int first_event, first_error; 112 Time IdleTime; 113 114 (void) signal (SIGALRM, abortOpen); 115 (void) alarm ((unsigned) 10); 116 if (!setjmp (openAbort)) { 117 if (!(dpy= XOpenDisplay(display))) { 118 syslog(LOG_ERR, "Cannot open display %s", display); 119 return(-1); 120 } 121 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 122 if (!XGetIdleTime(dpy, &IdleTime)) { 123 syslog(LOG_ERR, "%s: unable to get idle time", display); 124 return(-1); 125 } 126 } else { 127 syslog(LOG_ERR, "%s: Xidle extension not loaded", display); 128 return(-1); 129 } 130 XCloseDisplay(dpy); 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(const char *tty, const char *display __unused) 145{ 146 struct stat st; 147 char ttyname[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 } else { 170 sprintf(ttyname, "%s/%s", _PATH_DEV, tty); 171 if (stat(ttyname, &st) < 0) { 172#ifdef DEBUG 173 printf("%s: %s\n", ttyname, strerror(errno)); 174#endif 175 return(-1); 176 } 177 time(&now); 178#ifdef DEBUG 179 printf("%s: now=%d atime=%d\n", ttyname, now, 180 st.st_atime); 181#endif 182 idle = now - st.st_atime; 183 idle = (idle + 30) / 60; /* secs->mins */ 184 } 185 186 return(idle); 187} 188 189static utmpidlearr * 190do_names_2(void) 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 238static int * 239rusers_num(void *argp __unused, struct svc_req *rqstp __unused) 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 266static utmparr * 267do_names_1(void) 268{ 269 utmpidlearr *utidle; 270 static utmparr ut; 271 unsigned int i; 272 273 bzero((char *)&ut, sizeof(ut)); 274 275 utidle = do_names_2(); 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 288utmpidlearr * 289rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 290{ 291 292 return (do_names_2()); 293} 294 295utmpidlearr * 296rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 297{ 298 299 return (do_names_2()); 300} 301 302utmparr * 303rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 304{ 305 306 return (do_names_1()); 307} 308 309utmparr * 310rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 311{ 312 313 return (do_names_1()); 314} 315 316typedef void *(*rusersproc_t)(void *, struct svc_req *); 317 318void 319rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 320{ 321 union { 322 int fill; 323 } argument; 324 char *result; 325 xdrproc_t xdr_argument, xdr_result; 326 rusersproc_t local; 327 328 switch (rqstp->rq_proc) { 329 case NULLPROC: 330 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 331 goto leave; 332 333 case RUSERSPROC_NUM: 334 xdr_argument = (xdrproc_t)xdr_void; 335 xdr_result = (xdrproc_t)xdr_int; 336 local = (rusersproc_t)rusers_num; 337 break; 338 339 case RUSERSPROC_NAMES: 340 xdr_argument = (xdrproc_t)xdr_void; 341 xdr_result = (xdrproc_t)xdr_utmpidlearr; 342 switch (rqstp->rq_vers) { 343 case RUSERSVERS_ORIG: 344 local = (rusersproc_t)rusersproc_names_1_svc; 345 break; 346 case RUSERSVERS_IDLE: 347 local = (rusersproc_t)rusersproc_names_2_svc; 348 break; 349 default: 350 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 351 goto leave; 352 /*NOTREACHED*/ 353 } 354 break; 355 356 case RUSERSPROC_ALLNAMES: 357 xdr_argument = (xdrproc_t)xdr_void; 358 xdr_result = (xdrproc_t)xdr_utmpidlearr; 359 switch (rqstp->rq_vers) { 360 case RUSERSVERS_ORIG: 361 local = (rusersproc_t)rusersproc_allnames_1_svc; 362 break; 363 case RUSERSVERS_IDLE: 364 local = (rusersproc_t)rusersproc_allnames_2_svc; 365 break; 366 default: 367 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 368 goto leave; 369 /*NOTREACHED*/ 370 } 371 break; 372 373 default: 374 svcerr_noproc(transp); 375 goto leave; 376 } 377 bzero(&argument, sizeof(argument)); 378 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 379 svcerr_decode(transp); 380 goto leave; 381 } 382 result = (*local)(&argument, rqstp); 383 if (result != NULL && 384 !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 385 svcerr_systemerr(transp); 386 } 387 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) { 388 syslog(LOG_ERR, "unable to free arguments"); 389 exit(1); 390 } 391leave: 392 if (from_inetd) 393 exit(0); 394} 395