1 /* $NetBSD: rusers_proc.c,v 1.26 2009/03/16 00:56:16 lukem 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.26 2009/03/16 00:56:16 lukem 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 62 #include <rpcsvc/rusers.h> /* New version */ 63 static size_t maxusers3 = 0; 64 static struct rusers_utmp *utmps; 65 66 #include <rpcsvc/rnusers.h> /* Old version */ 67 static size_t maxusers2 = 0; 68 static struct utmpidle **utmp_idlep; 69 static struct utmpidle *utmp_idle; 70 71 typedef char *(*rusersproc)(void *, struct svc_req *); 72 73 #ifndef _PATH_DEV 74 #define _PATH_DEV "/dev" 75 #endif 76 77 78 extern int from_inetd; 79 80 static int getarrays2(int); 81 static int getarrays3(int); 82 static int getidle(const char *, char *); 83 static int *rusers_num_svc(void *, struct svc_req *); 84 static utmp_array *do_names_3(int); 85 static struct utmpidlearr *do_names_2(int); 86 87 /* XXX */ 88 struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *); 89 struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *); 90 91 92 #ifdef XIDLE 93 static Display *dpy; 94 static sigjmp_buf openAbort; 95 96 static int XqueryIdle(char *); 97 static void abortOpen(int); 98 99 static void 100 abortOpen(int n) 101 { 102 siglongjmp(openAbort, 1); 103 } 104 105 static int 106 XqueryIdle(char *display) 107 { 108 int first_event, first_error; 109 Time IdleTime; 110 111 (void)signal(SIGALRM, abortOpen); 112 (void)alarm(10); 113 if (!sigsetjmp(openAbort, 0)) { 114 if ((dpy = XOpenDisplay(display)) == NULL) { 115 syslog(LOG_DEBUG, "cannot open display %s", display); 116 return -1; 117 } 118 if (XidleQueryExtension(dpy, &first_event, &first_error)) { 119 if (!XGetIdleTime(dpy, &IdleTime)) { 120 syslog(LOG_DEBUG, 121 "%s: unable to get idle time", display); 122 return -1; 123 } 124 } else { 125 syslog(LOG_DEBUG, "%s: Xidle extension not loaded", 126 display); 127 return -1; 128 } 129 XCloseDisplay(dpy); 130 } else { 131 syslog(LOG_DEBUG, "%s: server grabbed for over 10 seconds", 132 display); 133 return -1; 134 } 135 (void)alarm(0); 136 (void)signal(SIGALRM, SIG_DFL); 137 138 IdleTime /= 1000; 139 return (IdleTime + 30) / 60; 140 } 141 #endif /* XIDLE */ 142 143 static int 144 getarrays2(int ne) 145 { 146 struct utmpidle **nutmp_idlep; 147 struct utmpidle *nutmp_idle; 148 149 /* Limit to MAXUSERS for version 2 */ 150 if (ne > MAXUSERS) 151 ne = MAXUSERS; 152 153 if (maxusers2 == 0) { 154 nutmp_idlep = malloc(sizeof(*nutmp_idlep) * ne); 155 nutmp_idle = malloc(sizeof(*nutmp_idle) * ne); 156 } else { 157 nutmp_idlep = realloc(utmp_idlep, sizeof(*nutmp_idlep) * ne); 158 nutmp_idle = realloc(utmp_idle, sizeof(*nutmp_idle) * ne); 159 } 160 161 if (nutmp_idlep == NULL || nutmp_idle == NULL) { 162 syslog(LOG_WARNING, "Cannot allocate data for %u users (%m)", 163 ne); 164 free(nutmp_idlep); 165 free(nutmp_idle); 166 return 0; 167 } 168 169 utmp_idlep = nutmp_idlep; 170 utmp_idle = nutmp_idle; 171 return maxusers2 = ne; 172 } 173 174 static int 175 getarrays3(int ne) 176 { 177 struct rusers_utmp *nutmps; 178 179 if (maxusers3 == 0) { 180 nutmps = malloc(sizeof(*nutmps) * ne); 181 } else { 182 nutmps = realloc(utmps, sizeof(*nutmps) * ne); 183 } 184 185 if (nutmps == NULL) { 186 syslog(LOG_WARNING, "Cannot allocate data for %u users (%m)", 187 ne); 188 return 0; 189 } 190 191 utmps = nutmps; 192 return maxusers3 = ne; 193 } 194 195 static int 196 /*ARGUSED*/ 197 getidle(const char *tty, char *display) 198 { 199 struct stat st; 200 char dev_name[PATH_MAX]; 201 time_t now; 202 long idle; 203 204 /* 205 * If this is an X terminal or console, then try the 206 * XIdle extension 207 */ 208 #ifdef XIDLE 209 if (display && *display && strchr(display, ':') != NULL && 210 (idle = XqueryIdle(display)) >= 0) 211 return idle; 212 #endif 213 idle = 0; 214 if (*tty == 'X') { 215 long kbd_idle, mouse_idle; 216 #if !defined(i386) 217 kbd_idle = getidle("kbd", NULL); 218 #else 219 /* 220 * XXX Icky i386 console hack. 221 */ 222 kbd_idle = getidle("vga", NULL); 223 #endif 224 mouse_idle = getidle("mouse", NULL); 225 idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle; 226 } else { 227 snprintf(dev_name, sizeof dev_name, "%s/%s", _PATH_DEV, tty); 228 if (stat(dev_name, &st) == -1) { 229 syslog(LOG_WARNING, "Cannot stat %s (%m)", dev_name); 230 return 0; 231 } 232 (void)time(&now); 233 #ifdef DEBUG 234 printf("%s: now=%ld atime=%ld\n", dev_name, 235 (long)now, (long)st.st_atime); 236 #endif 237 idle = now - st.st_atime; 238 idle = (idle + 30) / 60; /* secs->mins */ 239 } 240 if (idle < 0) 241 idle = 0; 242 243 return idle; 244 } 245 246 static struct utmpentry *ue = NULL; 247 static int nusers = 0; 248 249 static int * 250 /*ARGSUSED*/ 251 rusers_num_svc(void *arg, struct svc_req *rqstp) 252 { 253 nusers = getutentries(NULL, &ue); 254 return &nusers; 255 } 256 257 static utmp_array * 258 do_names_3(int all) 259 { 260 static utmp_array ut; 261 struct utmpentry *e; 262 size_t nu; 263 int idle; 264 265 nusers = getutentries(NULL, &ue); 266 nusers = getarrays3(nusers); 267 268 (void)memset(&ut, 0, sizeof(ut)); 269 ut.utmp_array_val = utmps; 270 271 for (nu = 0, e = ue; e != NULL && nu < (size_t)nusers; e = e->next) { 272 if ((idle = getidle(e->line, e->host)) > 0 && !all) 273 continue; 274 utmps[nu].ut_type = RUSERS_USER_PROCESS; 275 utmps[nu].ut_time = e->tv.tv_sec; 276 utmps[nu].ut_idle = idle; 277 utmps[nu].ut_line = e->line; 278 utmps[nu].ut_user = e->name; 279 utmps[nu].ut_host = e->host; 280 nu++; 281 } 282 283 ut.utmp_array_len = nu; 284 285 return &ut; 286 } 287 288 utmp_array * 289 /*ARGSUSED*/ 290 rusersproc_names_3_svc(void *arg, struct svc_req *rqstp) 291 { 292 293 return do_names_3(0); 294 } 295 296 utmp_array * 297 /*ARGSUSED*/ 298 rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp) 299 { 300 301 return do_names_3(1); 302 } 303 304 static struct utmpidlearr * 305 do_names_2(int all) 306 { 307 static struct utmpidlearr ut; 308 struct utmpentry *e; 309 size_t nu; 310 int idle; 311 312 nusers = getutentries(NULL, &ue); 313 nusers = getarrays2(nusers); 314 (void)memset(&ut, 0, sizeof(ut)); 315 ut.uia_arr = utmp_idlep; 316 ut.uia_cnt = 0; 317 318 for (nu = 0, e = ue; e != NULL && nu < (size_t)nusers; e = e->next) { 319 if ((idle = getidle(e->line, e->host)) > 0 && !all) 320 continue; 321 utmp_idlep[nu] = &utmp_idle[nu]; 322 utmp_idle[nu].ui_utmp.ut_time = e->tv.tv_sec; 323 utmp_idle[nu].ui_idle = idle; 324 (void)strncpy(utmp_idle[nu].ui_utmp.ut_line, e->line, 325 sizeof(utmp_idle[nu].ui_utmp.ut_line)); 326 (void)strncpy(utmp_idle[nu].ui_utmp.ut_name, e->name, 327 sizeof(utmp_idle[nu].ui_utmp.ut_name)); 328 (void)strncpy(utmp_idle[nu].ui_utmp.ut_host, e->host, 329 sizeof(utmp_idle[nu].ui_utmp.ut_host)); 330 nu++; 331 } 332 333 ut.uia_cnt = nu; 334 return &ut; 335 } 336 337 struct utmpidlearr * 338 /*ARGSUSED*/ 339 rusersproc_names_2_svc(void *arg, struct svc_req *rqstp) 340 { 341 return do_names_2(0); 342 } 343 344 struct utmpidlearr * 345 /*ARGSUSED*/ 346 rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp) 347 { 348 return do_names_2(1); 349 } 350 351 void 352 rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 353 { 354 union { 355 int fill; 356 } argument; 357 char *result; 358 xdrproc_t xdr_argument, xdr_result; 359 rusersproc local; 360 361 switch (rqstp->rq_proc) { 362 case NULLPROC: 363 (void)svc_sendreply(transp, xdr_void, NULL); 364 goto leave; 365 366 case RUSERSPROC_NUM: 367 xdr_argument = (xdrproc_t)xdr_void; 368 xdr_result = (xdrproc_t)xdr_int; 369 switch (rqstp->rq_vers) { 370 case RUSERSVERS_3: 371 case RUSERSVERS_IDLE: 372 local = (char *(*)(void *, struct svc_req *)) 373 rusers_num_svc; 374 break; 375 default: 376 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 377 goto leave; 378 /*NOTREACHED*/ 379 } 380 break; 381 382 case RUSERSPROC_NAMES: 383 xdr_argument = (xdrproc_t)xdr_void; 384 xdr_result = (xdrproc_t)xdr_utmp_array; 385 switch (rqstp->rq_vers) { 386 case RUSERSVERS_3: 387 local = (rusersproc)rusersproc_names_3_svc; 388 break; 389 390 case RUSERSVERS_IDLE: 391 xdr_result = (xdrproc_t)xdr_utmpidlearr; 392 local = (rusersproc)rusersproc_names_2_svc; 393 break; 394 395 default: 396 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 397 goto leave; 398 /*NOTREACHED*/ 399 } 400 break; 401 402 case RUSERSPROC_ALLNAMES: 403 xdr_argument = (xdrproc_t)xdr_void; 404 xdr_result = (xdrproc_t)xdr_utmp_array; 405 switch (rqstp->rq_vers) { 406 case RUSERSVERS_3: 407 local = (rusersproc)rusersproc_allnames_3_svc; 408 break; 409 410 case RUSERSVERS_IDLE: 411 xdr_result = (xdrproc_t)xdr_utmpidlearr; 412 local = (rusersproc)rusersproc_allnames_2_svc; 413 break; 414 415 default: 416 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 417 goto leave; 418 /*NOTREACHED*/ 419 } 420 break; 421 422 default: 423 svcerr_noproc(transp); 424 goto leave; 425 } 426 (void)memset(&argument, 0, sizeof(argument)); 427 if (!svc_getargs(transp, xdr_argument, (caddr_t)(void *)&argument)) { 428 svcerr_decode(transp); 429 goto leave; 430 } 431 result = (*local)(&argument, rqstp); 432 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 433 svcerr_systemerr(transp); 434 } 435 if (!svc_freeargs(transp, xdr_argument, (caddr_t)(void *)&argument)) { 436 syslog(LOG_ERR, "unable to free arguments"); 437 exit(1); 438 } 439 leave: 440 if (from_inetd) 441 exit(0); 442 } 443