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 */ 63static size_t maxusers3 = 0; 64static struct rusers_utmp *utmps; 65 66#include <rpcsvc/rnusers.h> /* Old version */ 67static size_t maxusers2 = 0; 68static struct utmpidle **utmp_idlep; 69static struct utmpidle *utmp_idle; 70 71typedef char *(*rusersproc)(void *, struct svc_req *); 72 73#ifndef _PATH_DEV 74#define _PATH_DEV "/dev" 75#endif 76 77 78extern int from_inetd; 79 80static int getarrays2(int); 81static int getarrays3(int); 82static int getidle(const char *, char *); 83static int *rusers_num_svc(void *, struct svc_req *); 84static utmp_array *do_names_3(int); 85static struct utmpidlearr *do_names_2(int); 86 87/* XXX */ 88struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *); 89struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *); 90 91 92#ifdef XIDLE 93static Display *dpy; 94static sigjmp_buf openAbort; 95 96static int XqueryIdle(char *); 97static void abortOpen(int); 98 99static void 100abortOpen(int n) 101{ 102 siglongjmp(openAbort, 1); 103} 104 105static int 106XqueryIdle(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 143static int 144getarrays2(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 174static int 175getarrays3(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 195static int 196/*ARGUSED*/ 197getidle(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 246static struct utmpentry *ue = NULL; 247static int nusers = 0; 248 249static int * 250/*ARGSUSED*/ 251rusers_num_svc(void *arg, struct svc_req *rqstp) 252{ 253 nusers = getutentries(NULL, &ue); 254 return &nusers; 255} 256 257static utmp_array * 258do_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 288utmp_array * 289/*ARGSUSED*/ 290rusersproc_names_3_svc(void *arg, struct svc_req *rqstp) 291{ 292 293 return do_names_3(0); 294} 295 296utmp_array * 297/*ARGSUSED*/ 298rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp) 299{ 300 301 return do_names_3(1); 302} 303 304static struct utmpidlearr * 305do_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 337struct utmpidlearr * 338/*ARGSUSED*/ 339rusersproc_names_2_svc(void *arg, struct svc_req *rqstp) 340{ 341 return do_names_2(0); 342} 343 344struct utmpidlearr * 345/*ARGSUSED*/ 346rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp) 347{ 348 return do_names_2(1); 349} 350 351void 352rusers_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, (xdrproc_t)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 } 439leave: 440 if (from_inetd) 441 exit(0); 442} 443