12337Scsgr/*- 22337Scsgr * Copyright (c) 1993, John Brezak 32337Scsgr * All rights reserved. 42337Scsgr * 52337Scsgr * Redistribution and use in source and binary forms, with or without 62337Scsgr * modification, are permitted provided that the following conditions 72337Scsgr * are met: 82337Scsgr * 1. Redistributions of source code must retain the above copyright 92337Scsgr * notice, this list of conditions and the following disclaimer. 102337Scsgr * 2. Redistributions in binary form must reproduce the above copyright 112337Scsgr * notice, this list of conditions and the following disclaimer in the 122337Scsgr * documentation and/or other materials provided with the distribution. 132337Scsgr * 3. All advertising materials mentioning features or use of this software 142337Scsgr * must display the following acknowledgement: 152337Scsgr * This product includes software developed by the University of 162337Scsgr * California, Berkeley and its contributors. 172337Scsgr * 4. Neither the name of the University nor the names of its contributors 182337Scsgr * may be used to endorse or promote products derived from this software 192337Scsgr * without specific prior written permission. 202337Scsgr * 212337Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 222337Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232337Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242337Scsgr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 252337Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 262337Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 272337Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 282337Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 292337Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 302337Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 312337Scsgr * SUCH DAMAGE. 322337Scsgr */ 332337Scsgr 342337Scsgr#ifndef lint 3531422Scharnierstatic const char rcsid[] = 3650476Speter "$FreeBSD$"; 372337Scsgr#endif /* not lint */ 382337Scsgr 3932312Scharnier#ifdef DEBUG 4032312Scharnier#include <errno.h> 4132312Scharnier#endif 422337Scsgr#include <stdio.h> 4331422Scharnier#include <string.h> 4431422Scharnier#include <sys/param.h> 452337Scsgr#include <sys/stat.h> 46115668Sobrien#include <stdlib.h> 4731422Scharnier#include <syslog.h> 48202210Sed#include <utmpx.h> 492337Scsgr#ifdef XIDLE 502337Scsgr#include <setjmp.h> 512337Scsgr#include <X11/Xlib.h> 522337Scsgr#include <X11/extensions/xidle.h> 532337Scsgr#endif 542337Scsgr#include <rpcsvc/rnusers.h> 552337Scsgr 562337Scsgr#ifndef _PATH_DEV 572337Scsgr#define _PATH_DEV "/dev" 582337Scsgr#endif 592337Scsgr 60201146Sedstatic utmpidle utmp_idle[MAXUSERS]; 61201192Sedstatic utmp old_utmp[MAXUSERS]; 62201192Sedstatic struct utmpx utmp_list[MAXUSERS]; 632337Scsgr 642337Scsgrextern int from_inetd; 652337Scsgr 66201146Sedvoid rusers_service(struct svc_req *, SVCXPRT *); 672337Scsgr 682337Scsgr#ifdef XIDLE 69201146Sedstatic Display *dpy; 702337Scsgr 712337Scsgrstatic jmp_buf openAbort; 722337Scsgr 732337Scsgrstatic void 7490336SimpabortOpen(void) 752337Scsgr{ 762337Scsgr longjmp (openAbort, 1); 772337Scsgr} 782337Scsgr 792337ScsgrXqueryIdle(char *display) 802337Scsgr{ 81201146Sed int first_event, first_error; 82201146Sed Time IdleTime; 832337Scsgr 84201146Sed (void) signal (SIGALRM, abortOpen); 85201146Sed (void) alarm ((unsigned) 10); 86201146Sed if (!setjmp (openAbort)) { 87201146Sed if (!(dpy= XOpenDisplay(display))) { 88201146Sed syslog(LOG_ERR, "Cannot open display %s", display); 89201146Sed return(-1); 90201146Sed } 91201146Sed if (XidleQueryExtension(dpy, &first_event, &first_error)) { 92201146Sed if (!XGetIdleTime(dpy, &IdleTime)) { 93201146Sed syslog(LOG_ERR, "%s: unable to get idle time", display); 94201146Sed return(-1); 95201146Sed } 96201146Sed } else { 97201146Sed syslog(LOG_ERR, "%s: Xidle extension not loaded", display); 98201146Sed return(-1); 99201146Sed } 100201146Sed XCloseDisplay(dpy); 101201146Sed } else { 102201146Sed syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display); 103201146Sed return(-1); 104201146Sed } 105201146Sed (void) signal (SIGALRM, SIG_DFL); 106201146Sed (void) alarm ((unsigned) 0); 1072337Scsgr 108201146Sed IdleTime /= 1000; 109201146Sed return((IdleTime + 30) / 60); 1102337Scsgr} 1112337Scsgr#endif 1122337Scsgr 1132337Scsgrstatic u_int 114201146Sedgetidle(const char *tty, const char *display __unused) 1152337Scsgr{ 116201146Sed struct stat st; 117201146Sed char ttyname[PATH_MAX]; 118201146Sed time_t now; 119201146Sed u_long idle; 1208870Srgrimes 121201146Sed /* 122201146Sed * If this is an X terminal or console, then try the 123201146Sed * XIdle extension 124201146Sed */ 1252337Scsgr#ifdef XIDLE 126201146Sed if (display && *display && (idle = XqueryIdle(display)) >= 0) 127201146Sed return(idle); 1282337Scsgr#endif 129201146Sed idle = 0; 130201146Sed if (*tty == 'X') { 131201146Sed u_long kbd_idle, mouse_idle; 1324131Sjkh#if !defined(__FreeBSD__) 133201146Sed kbd_idle = getidle("kbd", NULL); 1342337Scsgr#else 135201146Sed kbd_idle = getidle("vga", NULL); 1362337Scsgr#endif 137201146Sed mouse_idle = getidle("mouse", NULL); 138201146Sed idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle; 139201146Sed } else { 140201146Sed sprintf(ttyname, "%s/%s", _PATH_DEV, tty); 141201146Sed if (stat(ttyname, &st) < 0) { 1422337Scsgr#ifdef DEBUG 143201146Sed printf("%s: %s\n", ttyname, strerror(errno)); 1442337Scsgr#endif 145201146Sed return(-1); 146201146Sed } 147201146Sed time(&now); 1482337Scsgr#ifdef DEBUG 149201146Sed printf("%s: now=%d atime=%d\n", ttyname, now, 150201146Sed st.st_atime); 1512337Scsgr#endif 152201146Sed idle = now - st.st_atime; 153201146Sed idle = (idle + 30) / 60; /* secs->mins */ 154201146Sed } 1552337Scsgr 156201146Sed return(idle); 1572337Scsgr} 1588870Srgrimes 1592337Scsgrstatic utmpidlearr * 160201146Seddo_names_2(void) 1612337Scsgr{ 162201146Sed static utmpidlearr ut; 163201192Sed struct utmpx *usr; 164201146Sed int nusers = 0; 1658870Srgrimes 166201192Sed memset(&ut, 0, sizeof(ut)); 167201146Sed ut.utmpidlearr_val = &utmp_idle[0]; 1688870Srgrimes 169201192Sed setutxent(); 170201192Sed while ((usr = getutxent()) != NULL && nusers < MAXUSERS) { 171201192Sed if (usr->ut_type != USER_PROCESS) 172201192Sed continue; 1732337Scsgr 174201192Sed memcpy(&utmp_list[nusers], usr, sizeof(*usr)); 175201192Sed utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec; 176201192Sed utmp_idle[nusers].ui_idle = 177201192Sed getidle(usr->ut_line, usr->ut_host); 178201192Sed utmp_idle[nusers].ui_utmp.ut_line = 179201192Sed utmp_list[nusers].ut_line; 180201192Sed utmp_idle[nusers].ui_utmp.ut_name = 181201192Sed utmp_list[nusers].ut_user; 182201192Sed utmp_idle[nusers].ui_utmp.ut_host = 183201192Sed utmp_list[nusers].ut_host; 1848870Srgrimes 185201192Sed nusers++; 186201192Sed } 187201192Sed endutxent(); 1882337Scsgr 189201146Sed ut.utmpidlearr_len = nusers; 190201146Sed return(&ut); 1912337Scsgr} 1922337Scsgr 193201146Sedstatic int * 194201146Sedrusers_num(void *argp __unused, struct svc_req *rqstp __unused) 1952337Scsgr{ 196201146Sed static int num_users = 0; 197201192Sed struct utmpx *usr; 198201192Sed 199201192Sed setutxent(); 200201192Sed while ((usr = getutxent()) != NULL) { 201201192Sed if (usr->ut_type != USER_PROCESS) 202201192Sed continue; 203201192Sed num_users++; 204201146Sed } 205201192Sed endutxent(); 206201192Sed 207201146Sed return(&num_users); 2082337Scsgr} 2092337Scsgr 2102337Scsgrstatic utmparr * 211201146Seddo_names_1(void) 2122337Scsgr{ 213201146Sed utmpidlearr *utidle; 214201146Sed static utmparr ut; 215201146Sed unsigned int i; 2168870Srgrimes 217201146Sed bzero((char *)&ut, sizeof(ut)); 2188870Srgrimes 219201146Sed utidle = do_names_2(); 220201146Sed if (utidle) { 221201146Sed ut.utmparr_len = utidle->utmpidlearr_len; 222201146Sed ut.utmparr_val = &old_utmp[0]; 223201146Sed for (i = 0; i < ut.utmparr_len; i++) 224201146Sed bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i], 225201146Sed sizeof(old_utmp[0])); 2268870Srgrimes 227201146Sed } 2288870Srgrimes 229201146Sed return(&ut); 2302337Scsgr} 2312337Scsgr 2322337Scsgrutmpidlearr * 233201146Sedrusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 2342337Scsgr{ 235201146Sed 236201146Sed return (do_names_2()); 2372337Scsgr} 2382337Scsgr 2392337Scsgrutmpidlearr * 240201146Sedrusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 2412337Scsgr{ 242201146Sed 243201146Sed return (do_names_2()); 2442337Scsgr} 2452337Scsgr 2462337Scsgrutmparr * 247201146Sedrusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 2482337Scsgr{ 249201146Sed 250201146Sed return (do_names_1()); 2512337Scsgr} 2522337Scsgr 2532337Scsgrutmparr * 254201146Sedrusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 2552337Scsgr{ 256201146Sed 257201146Sed return (do_names_1()); 2582337Scsgr} 2592337Scsgr 260201146Sedtypedef void *(*rusersproc_t)(void *, struct svc_req *); 261201146Sed 2622337Scsgrvoid 26390336Simprusers_service(struct svc_req *rqstp, SVCXPRT *transp) 2642337Scsgr{ 2652337Scsgr union { 2662337Scsgr int fill; 2672337Scsgr } argument; 2682337Scsgr char *result; 269201146Sed xdrproc_t xdr_argument, xdr_result; 270201146Sed rusersproc_t local; 2712337Scsgr 2722337Scsgr switch (rqstp->rq_proc) { 2732337Scsgr case NULLPROC: 27495658Sdes (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 2752337Scsgr goto leave; 2762337Scsgr 2772337Scsgr case RUSERSPROC_NUM: 278201146Sed xdr_argument = (xdrproc_t)xdr_void; 279201146Sed xdr_result = (xdrproc_t)xdr_int; 280201146Sed local = (rusersproc_t)rusers_num; 2812337Scsgr break; 2822337Scsgr 2832337Scsgr case RUSERSPROC_NAMES: 284201146Sed xdr_argument = (xdrproc_t)xdr_void; 285201146Sed xdr_result = (xdrproc_t)xdr_utmpidlearr; 286201146Sed switch (rqstp->rq_vers) { 287201146Sed case RUSERSVERS_ORIG: 288201146Sed local = (rusersproc_t)rusersproc_names_1_svc; 289201146Sed break; 290201146Sed case RUSERSVERS_IDLE: 291201146Sed local = (rusersproc_t)rusersproc_names_2_svc; 292201146Sed break; 293201146Sed default: 294201146Sed svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 295201146Sed goto leave; 296201146Sed /*NOTREACHED*/ 297201146Sed } 2982337Scsgr break; 2992337Scsgr 3002337Scsgr case RUSERSPROC_ALLNAMES: 301201146Sed xdr_argument = (xdrproc_t)xdr_void; 302201146Sed xdr_result = (xdrproc_t)xdr_utmpidlearr; 303201146Sed switch (rqstp->rq_vers) { 304201146Sed case RUSERSVERS_ORIG: 305201146Sed local = (rusersproc_t)rusersproc_allnames_1_svc; 306201146Sed break; 307201146Sed case RUSERSVERS_IDLE: 308201146Sed local = (rusersproc_t)rusersproc_allnames_2_svc; 309201146Sed break; 310201146Sed default: 311201146Sed svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 312201146Sed goto leave; 313201146Sed /*NOTREACHED*/ 314201146Sed } 3152337Scsgr break; 3162337Scsgr 3172337Scsgr default: 3182337Scsgr svcerr_noproc(transp); 3192337Scsgr goto leave; 3202337Scsgr } 32195658Sdes bzero(&argument, sizeof(argument)); 32295658Sdes if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 3232337Scsgr svcerr_decode(transp); 3242337Scsgr goto leave; 3252337Scsgr } 3262337Scsgr result = (*local)(&argument, rqstp); 32795658Sdes if (result != NULL && 32895658Sdes !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 3292337Scsgr svcerr_systemerr(transp); 3302337Scsgr } 33195658Sdes if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) { 33232312Scharnier syslog(LOG_ERR, "unable to free arguments"); 33332312Scharnier exit(1); 33432312Scharnier } 3352337Scsgrleave: 336201146Sed if (from_inetd) 337201146Sed exit(0); 3382337Scsgr} 339