1/* $OpenBSD: rusers_proc.c,v 1.27 2019/06/28 13:32:53 deraadt 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/socket.h> 32#include <sys/stat.h> 33#include <sys/types.h> 34#include <sys/time.h> 35#include <paths.h> 36#include <utmp.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <syslog.h> 40#include <unistd.h> 41#include <limits.h> 42#include <string.h> 43#include <rpc/rpc.h> 44#include <rpcsvc/rusers.h> /* New version */ 45#include <rpcsvc/rnusers.h> /* Old version */ 46 47extern int utmp_fd; 48 49typedef char ut_line_t[UT_LINESIZE+1]; 50typedef char ut_name_t[UT_NAMESIZE+1]; 51typedef char ut_host_t[UT_HOSTSIZE+1]; 52 53struct rusers_utmp utmps[MAXUSERS]; 54struct utmpidle *utmp_idlep[MAXUSERS]; 55struct utmpidle utmp_idle[MAXUSERS]; 56struct ru_utmp *ru_utmpp[MAXUSERS]; 57struct ru_utmp ru_utmp[MAXUSERS]; 58ut_line_t line[MAXUSERS]; 59ut_name_t name[MAXUSERS]; 60ut_host_t host[MAXUSERS]; 61 62int *rusers_num_svc(void *, struct svc_req *); 63struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *); 64struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *); 65struct utmparr *rusersproc_names_1_svc(void *, struct svc_req *); 66struct utmparr *rusersproc_allnames_1_svc(void *, struct svc_req *); 67void rusers_service(struct svc_req *, SVCXPRT *); 68 69extern int from_inetd; 70 71FILE *ufp; 72 73static long 74getidle(char *tty, int len) 75{ 76 char devname[PATH_MAX]; 77 struct stat st; 78 long idle; 79 time_t now; 80 81 snprintf(devname, sizeof devname, "%s/%.*s", _PATH_DEV, 82 len, tty); 83 if (stat(devname, &st) == -1) { 84#ifdef DEBUG 85 printf("%s: %m\n", devname); 86#endif 87 return (0); 88 } 89 time(&now); 90#ifdef DEBUG 91 printf("%s: now=%lld atime=%lld\n", devname, (long long)now, 92 (long long)st.st_atime); 93#endif 94 idle = now - st.st_atime; 95 idle = (idle + 30) / 60; /* secs->mins */ 96 if (idle < 0) 97 idle = 0; 98 99 return (idle); 100} 101 102int * 103rusers_num_svc(void *arg, struct svc_req *rqstp) 104{ 105 static int num_users = 0; 106 struct utmp usr; 107 int fd; 108 109 fd = dup(utmp_fd); 110 if (fd == -1) { 111 syslog(LOG_ERR, "%m"); 112 return (0); 113 } 114 lseek(fd, 0, SEEK_SET); 115 ufp = fdopen(fd, "r"); 116 if (!ufp) { 117 close(fd); 118 syslog(LOG_ERR, "%m"); 119 return (0); 120 } 121 122 /* only entries with both name and line fields */ 123 while (fread(&usr, sizeof(usr), 1, ufp) == 1) 124 if (*usr.ut_name && *usr.ut_line) 125 num_users++; 126 127 fclose(ufp); 128 return (&num_users); 129} 130 131static utmp_array * 132do_names_3(int all) 133{ 134 static utmp_array ut; 135 struct utmp usr; 136 int fd, nusers = 0; 137 138 bzero(&ut, sizeof(ut)); 139 ut.utmp_array_val = &utmps[0]; 140 141 fd = dup(utmp_fd); 142 if (fd == -1) { 143 syslog(LOG_ERR, "%m"); 144 return (0); 145 } 146 lseek(fd, 0, SEEK_SET); 147 ufp = fdopen(fd, "r"); 148 if (!ufp) { 149 close(fd); 150 syslog(LOG_ERR, "%m"); 151 return (NULL); 152 } 153 154 /* only entries with both name and line fields */ 155 while (fread(&usr, sizeof(usr), 1, ufp) == 1 && 156 nusers < MAXUSERS) 157 if (*usr.ut_name && *usr.ut_line) { 158 utmps[nusers].ut_type = RUSERS_USER_PROCESS; 159 utmps[nusers].ut_time = usr.ut_time; 160 utmps[nusers].ut_idle = getidle(usr.ut_line, 161 sizeof usr.ut_line); 162 utmps[nusers].ut_line = line[nusers]; 163 memset(line[nusers], 0, sizeof(line[nusers])); 164 memcpy(line[nusers], usr.ut_line, UT_LINESIZE); 165 line[nusers][UT_LINESIZE] = '\0'; 166 utmps[nusers].ut_user = name[nusers]; 167 memset(name[nusers], 0, sizeof(name[nusers])); 168 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE); 169 name[nusers][UT_NAMESIZE] = '\0'; 170 utmps[nusers].ut_host = host[nusers]; 171 memset(host[nusers], 0, sizeof(host[nusers])); 172 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE); 173 host[nusers][UT_HOSTSIZE] = '\0'; 174 nusers++; 175 } 176 ut.utmp_array_len = nusers; 177 178 fclose(ufp); 179 return (&ut); 180} 181 182utmp_array * 183rusersproc_names_3_svc(void *arg, struct svc_req *rqstp) 184{ 185 return (do_names_3(0)); 186} 187 188utmp_array * 189rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp) 190{ 191 return (do_names_3(1)); 192} 193 194static struct utmpidlearr * 195do_names_2(int all) 196{ 197 static struct utmpidlearr ut; 198 struct utmp usr; 199 int fd, nusers = 0; 200 201 bzero(&ut, sizeof(ut)); 202 ut.uia_arr = utmp_idlep; 203 ut.uia_cnt = 0; 204 205 fd = dup(utmp_fd); 206 if (fd == -1) { 207 syslog(LOG_ERR, "%m"); 208 return (0); 209 } 210 lseek(fd, 0, SEEK_SET); 211 ufp = fdopen(fd, "r"); 212 if (!ufp) { 213 close(fd); 214 syslog(LOG_ERR, "%m"); 215 return (NULL); 216 } 217 218 /* only entries with both name and line fields */ 219 while (fread(&usr, sizeof(usr), 1, ufp) == 1 && 220 nusers < MAXUSERS) 221 if (*usr.ut_name && *usr.ut_line) { 222 utmp_idlep[nusers] = &utmp_idle[nusers]; 223 utmp_idle[nusers].ui_utmp.ut_time = usr.ut_time; 224 utmp_idle[nusers].ui_idle = getidle(usr.ut_line, 225 sizeof usr.ut_line); 226 utmp_idle[nusers].ui_utmp.ut_line = line[nusers]; 227 memset(line[nusers], 0, sizeof(line[nusers])); 228 memcpy(line[nusers], usr.ut_line, UT_LINESIZE); 229 line[nusers][UT_LINESIZE] = '\0'; 230 utmp_idle[nusers].ui_utmp.ut_name = name[nusers]; 231 memset(name[nusers], 0, sizeof(name[nusers])); 232 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE); 233 name[nusers][UT_NAMESIZE] = '\0'; 234 utmp_idle[nusers].ui_utmp.ut_host = host[nusers]; 235 memset(host[nusers], 0, sizeof(host[nusers])); 236 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE); 237 host[nusers][UT_HOSTSIZE] = '\0'; 238 nusers++; 239 } 240 241 ut.uia_cnt = nusers; 242 fclose(ufp); 243 return (&ut); 244} 245 246struct utmpidlearr * 247rusersproc_names_2_svc(void *arg, struct svc_req *rqstp) 248{ 249 return (do_names_2(0)); 250} 251 252struct utmpidlearr * 253rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp) 254{ 255 return (do_names_2(1)); 256} 257 258static struct utmparr * 259do_names_1(int all) 260{ 261 static struct utmparr ut; 262 struct utmp usr; 263 int fd, nusers = 0; 264 265 bzero(&ut, sizeof(ut)); 266 ut.uta_arr = ru_utmpp; 267 ut.uta_cnt = 0; 268 269 fd = dup(utmp_fd); 270 if (fd == -1) { 271 syslog(LOG_ERR, "%m"); 272 return (0); 273 } 274 lseek(fd, 0, SEEK_SET); 275 ufp = fdopen(fd, "r"); 276 if (!ufp) { 277 close(fd); 278 syslog(LOG_ERR, "%m"); 279 return (NULL); 280 } 281 282 /* only entries with both name and line fields */ 283 while (fread(&usr, sizeof(usr), 1, ufp) == 1 && 284 nusers < MAXUSERS) 285 if (*usr.ut_name && *usr.ut_line) { 286 ru_utmpp[nusers] = &ru_utmp[nusers]; 287 ru_utmp[nusers].ut_time = usr.ut_time; 288 ru_utmp[nusers].ut_line = line[nusers]; 289 memcpy(line[nusers], usr.ut_line, UT_LINESIZE); 290 line[nusers][UT_LINESIZE] = '\0'; 291 ru_utmp[nusers].ut_name = name[nusers]; 292 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE); 293 name[nusers][UT_NAMESIZE] = '\0'; 294 ru_utmp[nusers].ut_host = host[nusers]; 295 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE); 296 host[nusers][UT_HOSTSIZE] = '\0'; 297 nusers++; 298 } 299 300 ut.uta_cnt = nusers; 301 fclose(ufp); 302 return (&ut); 303} 304 305struct utmparr * 306rusersproc_names_1_svc(void *arg, struct svc_req *rqstp) 307{ 308 return (do_names_1(0)); 309} 310 311struct utmparr * 312rusersproc_allnames_1_svc(void *arg, struct svc_req *rqstp) 313{ 314 return (do_names_1(1)); 315} 316 317void 318rusers_service(struct svc_req *rqstp, SVCXPRT *transp) 319{ 320 char *(*local)(void *, struct svc_req *); 321 xdrproc_t xdr_argument, xdr_result; 322 union { 323 int fill; 324 } argument; 325 char *result; 326 327 switch (rqstp->rq_proc) { 328 case NULLPROC: 329 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 330 goto leave; 331 332 case RUSERSPROC_NUM: 333 xdr_argument = (xdrproc_t)xdr_void; 334 xdr_result = (xdrproc_t)xdr_int; 335 switch (rqstp->rq_vers) { 336 case RUSERSVERS_3: 337 case RUSERSVERS_IDLE: 338 case RUSERSVERS_ORIG: 339 local = (char *(*)(void *, struct svc_req *)) 340 rusers_num_svc; 341 break; 342 default: 343 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 344 goto leave; 345 /*NOTREACHED*/ 346 } 347 break; 348 349 case RUSERSPROC_NAMES: 350 xdr_argument = (xdrproc_t)xdr_void; 351 xdr_result = (xdrproc_t)xdr_utmp_array; 352 switch (rqstp->rq_vers) { 353 case RUSERSVERS_3: 354 local = (char *(*)(void *, struct svc_req *)) 355 rusersproc_names_3_svc; 356 break; 357 358 case RUSERSVERS_IDLE: 359 xdr_result = (xdrproc_t)xdr_utmpidlearr; 360 local = (char *(*)(void *, struct svc_req *)) 361 rusersproc_names_2_svc; 362 break; 363 364 case RUSERSVERS_ORIG: 365 xdr_result = (xdrproc_t)xdr_utmpidlearr; 366 local = (char *(*)(void *, struct svc_req *)) 367 rusersproc_names_1_svc; 368 break; 369 370 default: 371 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 372 goto leave; 373 /*NOTREACHED*/ 374 } 375 break; 376 377 case RUSERSPROC_ALLNAMES: 378 xdr_argument = (xdrproc_t)xdr_void; 379 xdr_result = (xdrproc_t)xdr_utmp_array; 380 switch (rqstp->rq_vers) { 381 case RUSERSVERS_3: 382 local = (char *(*)(void *, struct svc_req *)) 383 rusersproc_allnames_3_svc; 384 break; 385 386 case RUSERSVERS_IDLE: 387 xdr_result = (xdrproc_t)xdr_utmpidlearr; 388 local = (char *(*)(void *, struct svc_req *)) 389 rusersproc_allnames_2_svc; 390 break; 391 392 case RUSERSVERS_ORIG: 393 xdr_result = (xdrproc_t)xdr_utmpidlearr; 394 local = (char *(*)(void *, struct svc_req *)) 395 rusersproc_allnames_1_svc; 396 break; 397 398 default: 399 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3); 400 goto leave; 401 /*NOTREACHED*/ 402 } 403 break; 404 405 default: 406 svcerr_noproc(transp); 407 goto leave; 408 } 409 bzero((char *)&argument, sizeof(argument)); 410 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 411 svcerr_decode(transp); 412 goto leave; 413 } 414 result = (*local)(&argument, rqstp); 415 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) 416 svcerr_systemerr(transp); 417 418 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 419 syslog(LOG_ERR, "unable to free arguments"); 420 exit(1); 421 } 422leave: 423 if (from_inetd) 424 exit(0); 425} 426