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