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