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