1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1993, John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#ifndef lint 33static const char rcsid[] = 34 "$FreeBSD$"; 35#endif /* not lint */ 36 37#ifdef DEBUG 38#include <errno.h> 39#endif 40#include <stdio.h> 41#include <string.h> 42#include <sys/param.h> 43#include <sys/stat.h> 44#include <stdlib.h> 45#include <syslog.h> 46#include <utmpx.h> 47#ifdef XIDLE 48#include <setjmp.h> 49#include <X11/Xlib.h> 50#include <X11/extensions/xidle.h> 51#endif 52#include <rpcsvc/rnusers.h> 53 54#include "extern.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 64#ifdef XIDLE 65static Display *dpy; 66 67static jmp_buf openAbort; 68 69static void 70abortOpen(void) 71{ 72 longjmp (openAbort, 1); 73} 74 75XqueryIdle(char *display) 76{ 77 int first_event, first_error; 78 Time IdleTime; 79 80 (void) signal (SIGALRM, abortOpen); 81 (void) alarm ((unsigned) 10); 82 if (!setjmp (openAbort)) { 83 if (!(dpy= XOpenDisplay(display))) { 84 syslog(LOG_ERR, "Cannot open display %s", display); 85 return(-1); 86 } 87 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 88 if (!XGetIdleTime(dpy, &IdleTime)) { 89 syslog(LOG_ERR, "%s: unable to get idle time", display); 90 return(-1); 91 } 92 } else { 93 syslog(LOG_ERR, "%s: Xidle extension not loaded", display); 94 return(-1); 95 } 96 XCloseDisplay(dpy); 97 } else { 98 syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display); 99 return(-1); 100 } 101 (void) signal (SIGALRM, SIG_DFL); 102 (void) alarm ((unsigned) 0); 103 104 IdleTime /= 1000; 105 return((IdleTime + 30) / 60); 106} 107#endif 108 109static u_int 110getidle(const char *tty, const char *display __unused) 111{ 112 struct stat st; 113 char ttyname[PATH_MAX]; 114 time_t now; 115 u_long idle; 116 117 /* 118 * If this is an X terminal or console, then try the 119 * XIdle extension 120 */ 121#ifdef XIDLE 122 if (display && *display && (idle = XqueryIdle(display)) >= 0) 123 return(idle); 124#endif 125 idle = 0; 126 if (*tty == 'X') { 127 u_long kbd_idle, mouse_idle; 128#if !defined(__FreeBSD__) 129 kbd_idle = getidle("kbd", NULL); 130#else 131 kbd_idle = getidle("vga", NULL); 132#endif 133 mouse_idle = getidle("mouse", NULL); 134 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle; 135 } else { 136 sprintf(ttyname, "%s/%s", _PATH_DEV, tty); 137 if (stat(ttyname, &st) < 0) { 138#ifdef DEBUG 139 printf("%s: %s\n", ttyname, strerror(errno)); 140#endif 141 return(-1); 142 } 143 time(&now); 144#ifdef DEBUG 145 printf("%s: now=%d atime=%d\n", ttyname, now, 146 st.st_atime); 147#endif 148 idle = now - st.st_atime; 149 idle = (idle + 30) / 60; /* secs->mins */ 150 } 151 152 return(idle); 153} 154 155static utmpidlearr * 156do_names_2(void) 157{ 158 static utmpidlearr ut; 159 struct utmpx *usr; 160 int nusers = 0; 161 162 memset(&ut, 0, sizeof(ut)); 163 ut.utmpidlearr_val = &utmp_idle[0]; 164 165 setutxent(); 166 while ((usr = getutxent()) != NULL && nusers < MAXUSERS) { 167 if (usr->ut_type != USER_PROCESS) 168 continue; 169 170 memcpy(&utmp_list[nusers], usr, sizeof(*usr)); 171 utmp_idle[nusers].ui_utmp.ut_time = usr->ut_tv.tv_sec; 172 utmp_idle[nusers].ui_idle = 173 getidle(usr->ut_line, usr->ut_host); 174 utmp_idle[nusers].ui_utmp.ut_line = 175 utmp_list[nusers].ut_line; 176 utmp_idle[nusers].ui_utmp.ut_name = 177 utmp_list[nusers].ut_user; 178 utmp_idle[nusers].ui_utmp.ut_host = 179 utmp_list[nusers].ut_host; 180 181 nusers++; 182 } 183 endutxent(); 184 185 ut.utmpidlearr_len = nusers; 186 return(&ut); 187} 188 189static int * 190rusers_num(void *argp __unused, struct svc_req *rqstp __unused) 191{ 192 static int num_users = 0; 193 struct utmpx *usr; 194 195 setutxent(); 196 while ((usr = getutxent()) != NULL) { 197 if (usr->ut_type != USER_PROCESS) 198 continue; 199 num_users++; 200 } 201 endutxent(); 202 203 return(&num_users); 204} 205 206static utmparr * 207do_names_1(void) 208{ 209 utmpidlearr *utidle; 210 static utmparr ut; 211 unsigned int i; 212 213 bzero((char *)&ut, sizeof(ut)); 214 215 utidle = do_names_2(); 216 if (utidle) { 217 ut.utmparr_len = utidle->utmpidlearr_len; 218 ut.utmparr_val = &old_utmp[0]; 219 for (i = 0; i < ut.utmparr_len; i++) 220 bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i], 221 sizeof(old_utmp[0])); 222 223 } 224 225 return(&ut); 226} 227 228utmpidlearr * 229rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 230{ 231 232 return (do_names_2()); 233} 234 235utmpidlearr * 236rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 237{ 238 239 return (do_names_2()); 240} 241 242utmparr * 243rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 244{ 245 246 return (do_names_1()); 247} 248 249utmparr * 250rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 251{ 252 253 return (do_names_1()); 254} 255 256typedef void *(*rusersproc_t)(void *, struct svc_req *); 257 258void 259rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 260{ 261 union { 262 int fill; 263 } argument; 264 char *result; 265 xdrproc_t xdr_argument, xdr_result; 266 rusersproc_t local; 267 268 switch (rqstp->rq_proc) { 269 case NULLPROC: 270 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 271 goto leave; 272 273 case RUSERSPROC_NUM: 274 xdr_argument = (xdrproc_t)xdr_void; 275 xdr_result = (xdrproc_t)xdr_int; 276 local = (rusersproc_t)rusers_num; 277 break; 278 279 case RUSERSPROC_NAMES: 280 xdr_argument = (xdrproc_t)xdr_void; 281 xdr_result = (xdrproc_t)xdr_utmpidlearr; 282 switch (rqstp->rq_vers) { 283 case RUSERSVERS_ORIG: 284 local = (rusersproc_t)rusersproc_names_1_svc; 285 break; 286 case RUSERSVERS_IDLE: 287 local = (rusersproc_t)rusersproc_names_2_svc; 288 break; 289 default: 290 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 291 goto leave; 292 /*NOTREACHED*/ 293 } 294 break; 295 296 case RUSERSPROC_ALLNAMES: 297 xdr_argument = (xdrproc_t)xdr_void; 298 xdr_result = (xdrproc_t)xdr_utmpidlearr; 299 switch (rqstp->rq_vers) { 300 case RUSERSVERS_ORIG: 301 local = (rusersproc_t)rusersproc_allnames_1_svc; 302 break; 303 case RUSERSVERS_IDLE: 304 local = (rusersproc_t)rusersproc_allnames_2_svc; 305 break; 306 default: 307 svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE); 308 goto leave; 309 /*NOTREACHED*/ 310 } 311 break; 312 313 default: 314 svcerr_noproc(transp); 315 goto leave; 316 } 317 bzero(&argument, sizeof(argument)); 318 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 319 svcerr_decode(transp); 320 goto leave; 321 } 322 result = (*local)(&argument, rqstp); 323 if (result != NULL && 324 !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 325 svcerr_systemerr(transp); 326 } 327 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) { 328 syslog(LOG_ERR, "unable to free arguments"); 329 exit(1); 330 } 331leave: 332 if (from_inetd) 333 exit(0); 334} 335