1 /* $NetBSD: rusers_proc.c,v 1.24 2002/11/04 22:03:39 christos Exp $ */ 2 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #ifndef lint 33 __RCSID("$NetBSD: rusers_proc.c,v 1.24 2002/11/04 22:03:39 christos Exp $"); 34 #endif /* not lint */ 35 36 #include <sys/types.h> 37 #include <sys/time.h> 38 #include <sys/socket.h> 39 #include <sys/param.h> 40 #include <sys/stat.h> 41 42 #include <stdio.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include <time.h> 46 #include <unistd.h> 47 #include <signal.h> 48 #include <syslog.h> 49 #include <utmp.h> 50 51 #include <rpc/rpc.h> 52 53 #include "rusers_proc.h" 54 #include "utmpentry.h" 55 56 #ifdef XIDLE 57 #include <setjmp.h> 58 #include <X11/Xlib.h> 59 #include <X11/extensions/xidle.h> 60 #endif 61 #include <rpcsvc/rusers.h> /* New version */ 62 #include <rpcsvc/rnusers.h> /* Old version */ 63 64 #ifndef _PATH_DEV 65 #define _PATH_DEV "/dev" 66 #endif 67 68 static struct rusers_utmp utmps[MAXUSERS]; 69 static struct utmpidle *utmp_idlep[MAXUSERS]; 70 static struct utmpidle utmp_idle[MAXUSERS]; 71 72 extern int from_inetd; 73 74 static int getidle(char *, char *); 75 static int *rusers_num_svc(void *, struct svc_req *); 76 static utmp_array *do_names_3(int); 77 static struct utmpidlearr *do_names_2(int); 78 79 /* XXX */ 80 struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *); 81 struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *); 82 83 84 #ifdef XIDLE 85 static Display *dpy; 86 static sigjmp_buf openAbort; 87 88 static int XqueryIdle __P((char *)); 89 static void abortOpen __P((int)); 90 91 static void 92 abortOpen(int n) 93 { 94 siglongjmp(openAbort, 1); 95 } 96 97 static int 98 XqueryIdle(char *display) 99 { 100 int first_event, first_error; 101 Time IdleTime; 102 103 (void) signal(SIGALRM, abortOpen); 104 (void) alarm(10); 105 if (!sigsetjmp(openAbort, 0)) { 106 if ((dpy = XOpenDisplay(display)) == NULL) { 107 syslog(LOG_DEBUG, "cannot open display %s", display); 108 return (-1); 109 } 110 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 111 if (!XGetIdleTime(dpy, &IdleTime)) { 112 syslog(LOG_DEBUG, 113 "%s: unable to get idle time", display); 114 return (-1); 115 } 116 } else { 117 syslog(LOG_DEBUG, "%s: Xidle extension not loaded", 118 display); 119 return (-1); 120 } 121 XCloseDisplay(dpy); 122 } else { 123 syslog(LOG_DEBUG, "%s: server grabbed for over 10 seconds", 124 display); 125 return (-1); 126 } 127 (void) alarm(0); 128 (void) signal(SIGALRM, SIG_DFL); 129 130 IdleTime /= 1000; 131 return ((IdleTime + 30) / 60); 132 } 133 #endif /* XIDLE */ 134 135 static int 136 getidle(char *tty, char *display) 137 { 138 struct stat st; 139 char devname[PATH_MAX]; 140 time_t now; 141 long idle; 142 143 /* 144 * If this is an X terminal or console, then try the 145 * XIdle extension 146 */ 147 #ifdef XIDLE 148 if (display && *display && strchr(display, ':') != NULL && 149 (idle = XqueryIdle(display)) >= 0) 150 return (idle); 151 #endif 152 idle = 0; 153 if (*tty == 'X') { 154 long kbd_idle, mouse_idle; 155 #if !defined(i386) 156 kbd_idle = getidle("kbd", NULL); 157 #else 158 /* 159 * XXX Icky i386 console hack. 160 */ 161 kbd_idle = getidle("vga", NULL); 162 #endif 163 mouse_idle = getidle("mouse", NULL); 164 idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle; 165 } else { 166 snprintf(devname, sizeof devname, "%s/%s", _PATH_DEV, tty); 167 if (stat(devname, &st) == -1) { 168 syslog(LOG_WARNING, "Cannot stat %s (%m)", devname); 169 return 0; 170 } 171 (void)time(&now); 172 #ifdef DEBUG 173 printf("%s: now=%ld atime=%ld\n", devname, 174 (long)now, (long)st.st_atime); 175 #endif 176 idle = now - st.st_atime; 177 idle = (idle + 30) / 60; /* secs->mins */ 178 } 179 if (idle < 0) 180 idle = 0; 181 182 return idle; 183 } 184 185 static struct utmpentry *ue = NULL; 186 static int nusers = 0; 187 188 static int * 189 rusers_num_svc(void *arg, struct svc_req *rqstp) 190 { 191 nusers = getutentries(NULL, &ue); 192 return &nusers; 193 } 194 195 static utmp_array * 196 do_names_3(int all) 197 { 198 static utmp_array ut; 199 struct utmpentry *e; 200 int nu; 201 202 (void)memset(&ut, 0, sizeof(ut)); 203 ut.utmp_array_val = &utmps[0]; 204 205 nusers = getutentries(NULL, &ue); 206 207 for (nu = 0, e = ue; e != NULL && nu < MAXUSERS; e = e->next, nu++) { 208 utmps[nu].ut_type = RUSERS_USER_PROCESS; 209 utmps[nu].ut_time = e->tv.tv_sec; 210 utmps[nu].ut_idle = getidle(e->line, e->host); 211 utmps[nu].ut_line = e->line; 212 utmps[nu].ut_user = e->name; 213 utmps[nu].ut_host = e->host; 214 } 215 216 ut.utmp_array_len = nu; 217 218 return (&ut); 219 } 220 221 utmp_array * 222 rusersproc_names_3_svc(void *arg, struct svc_req *rqstp) 223 { 224 225 return (do_names_3(0)); 226 } 227 228 utmp_array * 229 rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp) 230 { 231 232 return (do_names_3(1)); 233 } 234 235 static struct utmpidlearr * 236 do_names_2(int all) 237 { 238 static struct utmpidlearr ut; 239 struct utmpentry *e; 240 int nu; 241 242 (void)memset(&ut, 0, sizeof(ut)); 243 ut.uia_arr = utmp_idlep; 244 ut.uia_cnt = 0; 245 246 nusers = getutentries(NULL, &ue); 247 248 for (nu = 0, e = ue; e != NULL && nu < MAXUSERS; e = e->next, nu++) { 249 utmp_idlep[nu] = &utmp_idle[nu]; 250 utmp_idle[nu].ui_utmp.ut_time = e->tv.tv_sec; 251 utmp_idle[nu].ui_idle = getidle(e->line, e->host); 252 (void)strncpy(utmp_idle[nu].ui_utmp.ut_line, e->line, 253 sizeof(utmp_idle[nu].ui_utmp.ut_line)); 254 (void)strncpy(utmp_idle[nu].ui_utmp.ut_name, e->name, 255 sizeof(utmp_idle[nu].ui_utmp.ut_name)); 256 (void)strncpy(utmp_idle[nu].ui_utmp.ut_host, e->host, 257 sizeof(utmp_idle[nu].ui_utmp.ut_host)); 258 } 259 260 ut.uia_cnt = nu; 261 return (&ut); 262 } 263 264 struct utmpidlearr * 265 rusersproc_names_2_svc(void *arg, struct svc_req *rqstp) 266 { 267 return (do_names_2(0)); 268 } 269 270 struct utmpidlearr * 271 rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp) 272 { 273 return (do_names_2(1)); 274 } 275 276 void 277 rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 278 { 279 union { 280 int fill; 281 } argument; 282 char *result; 283 xdrproc_t xdr_argument, xdr_result; 284 char *(*local) __P((void *, struct svc_req *)); 285 286 switch (rqstp->rq_proc) { 287 case NULLPROC: 288 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 289 goto leave; 290 291 case RUSERSPROC_NUM: 292 xdr_argument = (xdrproc_t)xdr_void; 293 xdr_result = (xdrproc_t)xdr_int; 294 switch (rqstp->rq_vers) { 295 case RUSERSVERS_3: 296 case RUSERSVERS_IDLE: 297 local = (char *(*) __P((void *, struct svc_req *))) 298 rusers_num_svc; 299 break; 300 default: 301 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 302 goto leave; 303 /*NOTREACHED*/ 304 } 305 break; 306 307 case RUSERSPROC_NAMES: 308 xdr_argument = (xdrproc_t)xdr_void; 309 xdr_result = (xdrproc_t)xdr_utmp_array; 310 switch (rqstp->rq_vers) { 311 case RUSERSVERS_3: 312 local = (char *(*) __P((void *, struct svc_req *))) 313 rusersproc_names_3_svc; 314 break; 315 316 case RUSERSVERS_IDLE: 317 xdr_result = (xdrproc_t)xdr_utmpidlearr; 318 local = (char *(*) __P((void *, struct svc_req *))) 319 rusersproc_names_2_svc; 320 break; 321 322 default: 323 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 324 goto leave; 325 /*NOTREACHED*/ 326 } 327 break; 328 329 case RUSERSPROC_ALLNAMES: 330 xdr_argument = (xdrproc_t)xdr_void; 331 xdr_result = (xdrproc_t)xdr_utmp_array; 332 switch (rqstp->rq_vers) { 333 case RUSERSVERS_3: 334 local = (char *(*) __P((void *, struct svc_req *))) 335 rusersproc_allnames_3_svc; 336 break; 337 338 case RUSERSVERS_IDLE: 339 xdr_result = (xdrproc_t)xdr_utmpidlearr; 340 local = (char *(*) __P((void *, struct svc_req *))) 341 rusersproc_allnames_2_svc; 342 break; 343 344 default: 345 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 346 goto leave; 347 /*NOTREACHED*/ 348 } 349 break; 350 351 default: 352 svcerr_noproc(transp); 353 goto leave; 354 } 355 memset((char *)&argument, 0, sizeof(argument)); 356 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 357 svcerr_decode(transp); 358 goto leave; 359 } 360 result = (*local)(&argument, rqstp); 361 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 362 svcerr_systemerr(transp); 363 } 364 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 365 syslog(LOG_ERR, "unable to free arguments"); 366 exit(1); 367 } 368 leave: 369 if (from_inetd) 370 exit(0); 371 } 372