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. 13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors 142337Scsgr * may be used to endorse or promote products derived from this software 152337Scsgr * without specific prior written permission. 162337Scsgr * 172337Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 182337Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 192337Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 202337Scsgr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 212337Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 222337Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 232337Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 242337Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 252337Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 262337Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 272337Scsgr * SUCH DAMAGE. 282337Scsgr */ 292337Scsgr 302337Scsgr#ifndef lint 3131422Scharnierstatic const char rcsid[] = 3250476Speter "$FreeBSD$"; 332337Scsgr#endif /* not lint */ 342337Scsgr 3532312Scharnier#ifdef DEBUG 3632312Scharnier#include <errno.h> 3732312Scharnier#endif 382337Scsgr#include <stdio.h> 3931422Scharnier#include <string.h> 4031422Scharnier#include <sys/param.h> 412337Scsgr#include <sys/stat.h> 42115668Sobrien#include <stdlib.h> 4331422Scharnier#include <syslog.h> 44202210Sed#include <utmpx.h> 452337Scsgr#ifdef XIDLE 462337Scsgr#include <setjmp.h> 472337Scsgr#include <X11/Xlib.h> 482337Scsgr#include <X11/extensions/xidle.h> 492337Scsgr#endif 502337Scsgr#include <rpcsvc/rnusers.h> 512337Scsgr 52241777Sed#include "extern.h" 53241777Sed 542337Scsgr#ifndef _PATH_DEV 552337Scsgr#define _PATH_DEV "/dev" 562337Scsgr#endif 572337Scsgr 58201146Sedstatic utmpidle utmp_idle[MAXUSERS]; 59201192Sedstatic utmp old_utmp[MAXUSERS]; 60201192Sedstatic struct utmpx utmp_list[MAXUSERS]; 612337Scsgr 622337Scsgr#ifdef XIDLE 63201146Sedstatic Display *dpy; 642337Scsgr 652337Scsgrstatic jmp_buf openAbort; 662337Scsgr 672337Scsgrstatic void 6890336SimpabortOpen(void) 692337Scsgr{ 702337Scsgr longjmp (openAbort, 1); 712337Scsgr} 722337Scsgr 732337ScsgrXqueryIdle(char *display) 742337Scsgr{ 75201146Sed int first_event, first_error; 76201146Sed Time IdleTime; 772337Scsgr 78201146Sed (void) signal (SIGALRM, abortOpen); 79201146Sed (void) alarm ((unsigned) 10); 80201146Sed if (!setjmp (openAbort)) { 81201146Sed if (!(dpy= XOpenDisplay(display))) { 82201146Sed syslog(LOG_ERR, "Cannot open display %s", display); 83201146Sed return(-1); 84201146Sed } 85201146Sed if (XidleQueryExtension(dpy, &first_event, &first_error)) { 86201146Sed if (!XGetIdleTime(dpy, &IdleTime)) { 87201146Sed syslog(LOG_ERR, "%s: unable to get idle time", display); 88201146Sed return(-1); 89201146Sed } 90201146Sed } else { 91201146Sed syslog(LOG_ERR, "%s: Xidle extension not loaded", display); 92201146Sed return(-1); 93201146Sed } 94201146Sed XCloseDisplay(dpy); 95201146Sed } else { 96201146Sed syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display); 97201146Sed return(-1); 98201146Sed } 99201146Sed (void) signal (SIGALRM, SIG_DFL); 100201146Sed (void) alarm ((unsigned) 0); 1012337Scsgr 102201146Sed IdleTime /= 1000; 103201146Sed return((IdleTime + 30) / 60); 1042337Scsgr} 1052337Scsgr#endif 1062337Scsgr 1072337Scsgrstatic u_int 108201146Sedgetidle(const char *tty, const char *display __unused) 1092337Scsgr{ 110201146Sed struct stat st; 111201146Sed char ttyname[PATH_MAX]; 112201146Sed time_t now; 113201146Sed u_long idle; 1148870Srgrimes 115201146Sed /* 116201146Sed * If this is an X terminal or console, then try the 117201146Sed * XIdle extension 118201146Sed */ 1192337Scsgr#ifdef XIDLE 120201146Sed if (display && *display && (idle = XqueryIdle(display)) >= 0) 121201146Sed return(idle); 1222337Scsgr#endif 123201146Sed idle = 0; 124201146Sed if (*tty == 'X') { 125201146Sed u_long kbd_idle, mouse_idle; 1264131Sjkh#if !defined(__FreeBSD__) 127201146Sed kbd_idle = getidle("kbd", NULL); 1282337Scsgr#else 129201146Sed kbd_idle = getidle("vga", NULL); 1302337Scsgr#endif 131201146Sed mouse_idle = getidle("mouse", NULL); 132201146Sed idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle; 133201146Sed } else { 134201146Sed sprintf(ttyname, "%s/%s", _PATH_DEV, tty); 135201146Sed if (stat(ttyname, &st) < 0) { 1362337Scsgr#ifdef DEBUG 137201146Sed printf("%s: %s\n", ttyname, strerror(errno)); 1382337Scsgr#endif 139201146Sed return(-1); 140201146Sed } 141201146Sed time(&now); 1422337Scsgr#ifdef DEBUG 143201146Sed printf("%s: now=%d atime=%d\n", ttyname, now, 144201146Sed st.st_atime); 1452337Scsgr#endif 146201146Sed idle = now - st.st_atime; 147201146Sed idle = (idle + 30) / 60; /* secs->mins */ 148201146Sed } 1492337Scsgr 150201146Sed return(idle); 1512337Scsgr} 1528870Srgrimes 1532337Scsgrstatic utmpidlearr * 154201146Seddo_names_2(void) 1552337Scsgr{ 156201146Sed static utmpidlearr ut; 157201192Sed struct utmpx *usr; 158201146Sed int nusers = 0; 1598870Srgrimes 160201192Sed memset(&ut, 0, sizeof(ut)); 161201146Sed ut.utmpidlearr_val = &utmp_idle[0]; 1628870Srgrimes 163201192Sed setutxent(); 164201192Sed while ((usr = getutxent()) != NULL && nusers < MAXUSERS) { 165201192Sed if (usr->ut_type != USER_PROCESS) 166201192Sed continue; 1672337Scsgr 168201192Sed memcpy(&utmp_list[nusers], usr, sizeof(*usr)); 169201192Sed utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec; 170201192Sed utmp_idle[nusers].ui_idle = 171201192Sed getidle(usr->ut_line, usr->ut_host); 172201192Sed utmp_idle[nusers].ui_utmp.ut_line = 173201192Sed utmp_list[nusers].ut_line; 174201192Sed utmp_idle[nusers].ui_utmp.ut_name = 175201192Sed utmp_list[nusers].ut_user; 176201192Sed utmp_idle[nusers].ui_utmp.ut_host = 177201192Sed utmp_list[nusers].ut_host; 1788870Srgrimes 179201192Sed nusers++; 180201192Sed } 181201192Sed endutxent(); 1822337Scsgr 183201146Sed ut.utmpidlearr_len = nusers; 184201146Sed return(&ut); 1852337Scsgr} 1862337Scsgr 187201146Sedstatic int * 188201146Sedrusers_num(void *argp __unused, struct svc_req *rqstp __unused) 1892337Scsgr{ 190201146Sed static int num_users = 0; 191201192Sed struct utmpx *usr; 192201192Sed 193201192Sed setutxent(); 194201192Sed while ((usr = getutxent()) != NULL) { 195201192Sed if (usr->ut_type != USER_PROCESS) 196201192Sed continue; 197201192Sed num_users++; 198201146Sed } 199201192Sed endutxent(); 200201192Sed 201201146Sed return(&num_users); 2022337Scsgr} 2032337Scsgr 2042337Scsgrstatic utmparr * 205201146Seddo_names_1(void) 2062337Scsgr{ 207201146Sed utmpidlearr *utidle; 208201146Sed static utmparr ut; 209201146Sed unsigned int i; 2108870Srgrimes 211201146Sed bzero((char *)&ut, sizeof(ut)); 2128870Srgrimes 213201146Sed utidle = do_names_2(); 214201146Sed if (utidle) { 215201146Sed ut.utmparr_len = utidle->utmpidlearr_len; 216201146Sed ut.utmparr_val = &old_utmp[0]; 217201146Sed for (i = 0; i < ut.utmparr_len; i++) 218201146Sed bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i], 219201146Sed sizeof(old_utmp[0])); 2208870Srgrimes 221201146Sed } 2228870Srgrimes 223201146Sed return(&ut); 2242337Scsgr} 2252337Scsgr 2262337Scsgrutmpidlearr * 227201146Sedrusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 2282337Scsgr{ 229201146Sed 230201146Sed return (do_names_2()); 2312337Scsgr} 2322337Scsgr 2332337Scsgrutmpidlearr * 234201146Sedrusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 2352337Scsgr{ 236201146Sed 237201146Sed return (do_names_2()); 2382337Scsgr} 2392337Scsgr 2402337Scsgrutmparr * 241201146Sedrusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 2422337Scsgr{ 243201146Sed 244201146Sed return (do_names_1()); 2452337Scsgr} 2462337Scsgr 2472337Scsgrutmparr * 248201146Sedrusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 2492337Scsgr{ 250201146Sed 251201146Sed return (do_names_1()); 2522337Scsgr} 2532337Scsgr 254201146Sedtypedef void *(*rusersproc_t)(void *, struct svc_req *); 255201146Sed 2562337Scsgrvoid 25790336Simprusers_service(struct svc_req *rqstp, SVCXPRT *transp) 2582337Scsgr{ 2592337Scsgr union { 2602337Scsgr int fill; 2612337Scsgr } argument; 2622337Scsgr char *result; 263201146Sed xdrproc_t xdr_argument, xdr_result; 264201146Sed rusersproc_t local; 2652337Scsgr 2662337Scsgr switch (rqstp->rq_proc) { 2672337Scsgr case NULLPROC: 26895658Sdes (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 2692337Scsgr goto leave; 2702337Scsgr 2712337Scsgr case RUSERSPROC_NUM: 272201146Sed xdr_argument = (xdrproc_t)xdr_void; 273201146Sed xdr_result = (xdrproc_t)xdr_int; 274201146Sed local = (rusersproc_t)rusers_num; 2752337Scsgr break; 2762337Scsgr 2772337Scsgr case RUSERSPROC_NAMES: 278201146Sed xdr_argument = (xdrproc_t)xdr_void; 279201146Sed xdr_result = (xdrproc_t)xdr_utmpidlearr; 280201146Sed switch (rqstp->rq_vers) { 281201146Sed case RUSERSVERS_ORIG: 282201146Sed local = (rusersproc_t)rusersproc_names_1_svc; 283201146Sed break; 284201146Sed case RUSERSVERS_IDLE: 285201146Sed local = (rusersproc_t)rusersproc_names_2_svc; 286201146Sed break; 287201146Sed default: 288201146Sed svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 289201146Sed goto leave; 290201146Sed /*NOTREACHED*/ 291201146Sed } 2922337Scsgr break; 2932337Scsgr 2942337Scsgr case RUSERSPROC_ALLNAMES: 295201146Sed xdr_argument = (xdrproc_t)xdr_void; 296201146Sed xdr_result = (xdrproc_t)xdr_utmpidlearr; 297201146Sed switch (rqstp->rq_vers) { 298201146Sed case RUSERSVERS_ORIG: 299201146Sed local = (rusersproc_t)rusersproc_allnames_1_svc; 300201146Sed break; 301201146Sed case RUSERSVERS_IDLE: 302201146Sed local = (rusersproc_t)rusersproc_allnames_2_svc; 303201146Sed break; 304201146Sed default: 305201146Sed svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 306201146Sed goto leave; 307201146Sed /*NOTREACHED*/ 308201146Sed } 3092337Scsgr break; 3102337Scsgr 3112337Scsgr default: 3122337Scsgr svcerr_noproc(transp); 3132337Scsgr goto leave; 3142337Scsgr } 31595658Sdes bzero(&argument, sizeof(argument)); 31695658Sdes if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 3172337Scsgr svcerr_decode(transp); 3182337Scsgr goto leave; 3192337Scsgr } 3202337Scsgr result = (*local)(&argument, rqstp); 32195658Sdes if (result != NULL && 32295658Sdes !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 3232337Scsgr svcerr_systemerr(transp); 3242337Scsgr } 32595658Sdes if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) { 32632312Scharnier syslog(LOG_ERR, "unable to free arguments"); 32732312Scharnier exit(1); 32832312Scharnier } 3292337Scsgrleave: 330201146Sed if (from_inetd) 331201146Sed exit(0); 3322337Scsgr} 333