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 35 static 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 60 static utmpidle utmp_idle[MAXUSERS]; 61 static utmp old_utmp[MAXUSERS]; 62 static struct utmpx utmp_list[MAXUSERS]; 63 64 extern int from_inetd; 65 66 void rusers_service(struct svc_req *, SVCXPRT *); 67 68 #ifdef XIDLE 69 static Display *dpy; 70 71 static jmp_buf openAbort; 72 73 static void 74 abortOpen(void) 75 { 76 longjmp (openAbort, 1); 77 } 78 79 XqueryIdle(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 113 static u_int 114 getidle(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 159 static utmpidlearr * 160 do_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 193 static int * 194 rusers_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 210 static utmparr * 211 do_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 232 utmpidlearr * 233 rusersproc_names_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 234 { 235 236 return (do_names_2()); 237 } 238 239 utmpidlearr * 240 rusersproc_allnames_2_svc(void *argp __unused, struct svc_req *rqstp __unused) 241 { 242 243 return (do_names_2()); 244 } 245 246 utmparr * 247 rusersproc_names_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 248 { 249 250 return (do_names_1()); 251 } 252 253 utmparr * 254 rusersproc_allnames_1_svc(void *argp __unused, struct svc_req *rqstp __unused) 255 { 256 257 return (do_names_1()); 258 } 259 260 typedef void *(*rusersproc_t)(void *, struct svc_req *); 261 262 void 263 rusers_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 } 335 leave: 336 if (from_inetd) 337 exit(0); 338 } 339