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 33 static 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 60 static utmpidle utmp_idle[MAXUSERS]; 61 static utmp old_utmp[MAXUSERS]; 62 static struct utmpx utmp_list[MAXUSERS]; 63 64 #ifdef XIDLE 65 static Display *dpy; 66 67 static jmp_buf openAbort; 68 69 static void 70 abortOpen(void) 71 { 72 longjmp (openAbort, 1); 73 } 74 75 XqueryIdle(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 109 static u_int 110 getidle(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 155 static utmpidlearr * 156 do_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 189 static int * 190 rusers_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 206 static utmparr * 207 do_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 228 utmpidlearr * 229 rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 230 { 231 232 return (do_names_2()); 233 } 234 235 utmpidlearr * 236 rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 237 { 238 239 return (do_names_2()); 240 } 241 242 utmparr * 243 rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 244 { 245 246 return (do_names_1()); 247 } 248 249 utmparr * 250 rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 251 { 252 253 return (do_names_1()); 254 } 255 256 typedef void *(*rusersproc_t)(void *, struct svc_req *); 257 258 void 259 rusers_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 } 331 leave: 332 if (from_inetd) 333 exit(0); 334 } 335