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