1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * Copyright 1998 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 /* 28 * University Copyright- Copyright (c) 1982, 1986, 1988 29 * The Regents of the University of California 30 * All Rights Reserved 31 * 32 * University Acknowledgment- Portions of this document are derived from 33 * software developed by the University of California, Berkeley, and its 34 * contributors. 35 */ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 #include <stdio.h> 40 #include <signal.h> 41 #include <sys/stat.h> 42 #include <rpc/rpc.h> 43 #include <memory.h> 44 #include <netconfig.h> 45 #include <stropts.h> 46 #include <syslog.h> 47 #include <utmpx.h> 48 #include <rpcsvc/rusers.h> 49 #include <sys/resource.h> 50 #include <limits.h> 51 52 #ifdef DEBUG 53 #define RPC_SVC_FG 54 #endif 55 56 #define _RPCSVC_CLOSEDOWN 120 57 58 static void rusers_service(); 59 static void closedown(); 60 static void msgout(); 61 static unsigned min(); 62 63 static int _rpcpmstart; /* Started by a port monitor ? */ 64 static int _rpcfdtype; /* Whether Stream or Datagram ? */ 65 static int _rpcsvcdirty; /* Still serving ? */ 66 static int _rpcsvcrecent; /* set when we serivce a request; tested */ 67 /* and cleared by closedown() routine */ 68 69 #define DIV60(t) ((t+30)/60) /* x/60 rounded */ 70 71 #define ALL_ENTRIES 1 72 #define REAL_USERS 0 73 74 utmp_array utmp_array_res; 75 int used_array_len = 0; 76 struct utmpidlearr utmpidlearr; 77 78 main() 79 { 80 pid_t pid; 81 int i; 82 int connmaxrec = RPC_MAXDATASIZE; 83 84 /* 85 * Set non-blocking mode and maximum record size for 86 * connection oriented RPC transports. 87 */ 88 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 89 msgout("unable to set maximum RPC record size"); 90 } 91 92 /* 93 * If stdin looks like a TLI endpoint, we assume 94 * that we were started by a port monitor. If 95 * t_getstate fails with TBADF, this is not a 96 * TLI endpoint. 97 */ 98 if (t_getstate(0) != -1 || t_errno != TBADF) { 99 char *netid; 100 struct netconfig *nconf = NULL; 101 SVCXPRT *transp; 102 int pmclose; 103 extern char *getenv(); 104 105 _rpcpmstart = 1; 106 openlog("rusers", LOG_PID, LOG_DAEMON); 107 if ((netid = getenv("NLSPROVIDER")) == NULL) { 108 #ifdef DEBUG 109 msgout("cannot get transport name"); 110 #endif 111 } else if ((nconf = getnetconfigent(netid)) == NULL) { 112 #ifdef DEBUG 113 msgout("cannot get transport info"); 114 #endif 115 } 116 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 117 msgout("cannot create server handle"); 118 exit(1); 119 } 120 if (nconf) 121 freenetconfigent(nconf); 122 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service, 123 0)) { 124 msgout("unable to register (RUSERSPROG, RUSERSVERS_3)."); 125 exit(1); 126 } 127 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE, 128 rusers_service, 0)) { 129 msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE)."); 130 exit(1); 131 } 132 (void) signal(SIGALRM, closedown); 133 (void) alarm(_RPCSVC_CLOSEDOWN); 134 svc_run(); 135 msgout("svc_run returned"); 136 exit(1); 137 /* NOTREACHED */ 138 } 139 #ifndef RPC_SVC_FG 140 pid = fork(); 141 if (pid < 0) { 142 perror("rpc.rusersd: cannot fork"); 143 exit(1); 144 } 145 if (pid) 146 exit(0); 147 for (i = 0; i < 20; i++) 148 (void) close(i); 149 setsid(); 150 openlog("rusers", LOG_PID, LOG_DAEMON); 151 #endif 152 if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")) { 153 msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath"); 154 exit(1); 155 } 156 if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE, 157 "netpath")) { 158 msgout( 159 "unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath"); 160 exit(1); 161 } 162 163 svc_run(); 164 msgout("svc_run returned"); 165 exit(1); 166 /* NOTREACHED */ 167 } 168 169 170 /* 171 * This routine gets the user information. 172 * "all" specifies whether all listings should be counted, or only those of 173 * type "USER_PROCESS". 174 * "version" is either RUSERSVERS_IDLE or RUSERSVERS_3. If anything else, 175 * just a count is returned. 176 * "limit" specifies the maximum number of entries to be processed. 177 * 178 * For both versions, the results are placed into an external variable. 179 * For RUSERSVERS_IDLE, this routine mallocs entries in a vector as it 180 * processed each utmpx entry. These malloc'd entries must be freed after the 181 * results are returned. 182 * For RUSERSVERS_3, this routine uses array entries that are malloc'd prior 183 * to this routine being called. "limit" is the number of elements available. 184 */ 185 int 186 getutmpx_3(all, version, limit) 187 int all; /* give all listings? */ 188 int version; /* version 2 or 3 */ 189 int limit; /* limits users returned, 0 means no limit */ 190 { 191 struct utmpx *utent; 192 struct utmpidle **q = utmpidlearr.uia_arr; 193 int minidle; 194 int cnt = 0; 195 time_t now; 196 extern char *s_malodup(); 197 198 time(&now); /* only one call to time() for this rpc call */ 199 setutxent(); /* reset the utmpx file */ 200 while ((utent = getutxent()) != NULL && (limit == 0 || cnt < limit)) { 201 if (utent->ut_line[0] == '\0' || utent->ut_user[0] == '\0') 202 continue; 203 /* 204 * List only user processes. 205 * XXX modified to exclude cmdtool style window entries. 206 */ 207 if ((all == REAL_USERS) && ((utent->ut_type != USER_PROCESS) || 208 nonuserx(*utent))) 209 continue; 210 211 if (version == RUSERSVERS_IDLE) { 212 /* 213 * need to free this; done after svc_sendreply. 214 */ 215 *q = (struct utmpidle *) 216 malloc(sizeof (struct utmpidle)); 217 (*q)->ui_idle = findidle(utent->ut_line, 218 sizeof (utent->ut_line), now); 219 if (strncmp(utent->ut_line, "console", 220 strlen("console")) == 0) { 221 (*q)->ui_idle = min((*q)->ui_idle, 222 console_idle(now)); 223 } 224 usys5to_ru(utent, &((*q)->ui_utmp)); 225 #ifdef DEBUG 226 printf("%-*s %-*s %s; idle %d", 227 sizeof (utent->ut_line), 228 utent->ut_line, 229 sizeof (utent->ut_name), 230 utent->ut_name, 231 ctime(&utent->ut_xtime), 232 (*q)->ui_idle); 233 #endif 234 q++; 235 } else if (version == RUSERSVERS_3) { 236 #define uav utmp_array_res.utmp_array_val 237 238 uav[cnt].ut_host = 239 s_malodup(utent->ut_host, utent->ut_syslen); 240 uav[cnt].ut_user = s_malodup(utent->ut_user, 241 sizeof (utent->ut_user)); 242 uav[cnt].ut_line = s_malodup(utent->ut_line, 243 sizeof (utent->ut_line)); 244 uav[cnt].ut_type = utent->ut_type; 245 uav[cnt].ut_time = utent->ut_xtime; 246 uav[cnt].ut_idle = findidle(utent->ut_line, 247 sizeof (utent->ut_line), now); 248 if (strncmp(utent->ut_line, "console", 249 strlen("console")) == 0) { 250 uav[cnt].ut_idle = 251 min(uav[cnt].ut_idle, 252 console_idle(now)); 253 } 254 #ifdef DEBUG 255 printf("user: %-10s line: %-10s %s; idle %d (%s)\n", 256 uav[cnt].ut_line, uav[cnt].ut_user, 257 ctime((time_t *)&uav[cnt].ut_time), 258 uav[cnt].ut_idle, uav[cnt].ut_host); 259 #endif 260 #undef uav 261 } 262 cnt++; 263 } 264 return (cnt); 265 } 266 267 /* 268 * "string" is a character array with maximum size "size". Return a 269 * malloc'd string that's a duplicate of the string. 270 */ 271 char * 272 s_malodup(string, size) 273 char *string; 274 int size; 275 { 276 char *tmp; 277 278 tmp = (char *)malloc(size+1); 279 if (tmp == NULL) { 280 msgout("rpc.rusersd: malloc failed (2)"); 281 return (NULL); 282 } 283 strncpy(tmp, string, size); 284 tmp[size] = '\0'; 285 return (tmp); 286 } 287 288 289 int 290 console_idle(now) 291 time_t now; 292 { 293 /* 294 * On the console, the user may be running a window system; if so, 295 * their activity will show up in the last-access times of 296 * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle 297 * times on those two devices and "/dev/console" and treat that as 298 * the idle time. 299 */ 300 return (min((unsigned)findidle("kbd", strlen("kbd"), now), 301 (unsigned)findidle("mouse", strlen("mouse"), now))); 302 } 303 304 static void 305 rusers_service(rqstp, transp) 306 register struct svc_req *rqstp; 307 register SVCXPRT *transp; 308 { 309 int i; 310 int cnt; 311 char *replyerr = "rpc.rusersd: error replying to request"; 312 313 _rpcsvcrecent = _rpcsvcdirty = 1; 314 switch (rqstp->rq_proc) { 315 case 0: 316 if (svc_sendreply(transp, xdr_void, 0) == FALSE) { 317 msgout(replyerr); 318 } 319 break; 320 case RUSERSPROC_NUM: 321 cnt = getutmpx_3(REAL_USERS, 0, 0); 322 if (!svc_sendreply(transp, xdr_u_long, (caddr_t)&cnt)) 323 msgout(replyerr); 324 break; 325 case RUSERSPROC_NAMES: 326 case RUSERSPROC_ALLNAMES: 327 if (rqstp->rq_vers == RUSERSVERS_IDLE) { 328 utmpidlearr.uia_arr = (struct utmpidle **) 329 malloc(MAXUSERS*sizeof (struct utmpidle *)); 330 utmpidlearr.uia_cnt = getutmpx_3(rqstp->rq_proc == 331 RUSERSPROC_ALLNAMES, 332 RUSERSVERS_IDLE, MAXUSERS); 333 if (!svc_sendreply(transp, xdr_utmpidlearr, 334 (caddr_t)&utmpidlearr)) 335 msgout(replyerr); 336 for (i = 0; i < utmpidlearr.uia_cnt; i++) { 337 free(utmpidlearr.uia_arr[i]); 338 } 339 free(utmpidlearr.uia_arr); 340 } else if (rqstp->rq_vers == RUSERSVERS_3) { 341 int entries, alloc_array_len; 342 343 /* 344 * Always free strings from previous results array 345 */ 346 for (i = 0; i < used_array_len; i++) { 347 free_ua_entry(&utmp_array_res.utmp_array_val[i]); 348 } 349 entries = (rqstp->rq_proc == RUSERSPROC_ALLNAMES); 350 cnt = getutmpx_3(entries, 0, 0); /* get cnt */ 351 if (cnt > utmp_array_res.utmp_array_len) { 352 free(utmp_array_res.utmp_array_val); 353 utmp_array_res.utmp_array_len = 0; 354 utmp_array_res.utmp_array_val = (rusers_utmp *) 355 malloc(cnt * sizeof (rusers_utmp)); 356 if (utmp_array_res.utmp_array_val == NULL) { 357 msgout("rpc.rusersd: malloc failed (1)"); 358 break; 359 } 360 alloc_array_len = cnt; 361 } else { 362 alloc_array_len = utmp_array_res.utmp_array_len; 363 } 364 cnt = getutmpx_3(entries, RUSERSVERS_3, cnt); 365 utmp_array_res.utmp_array_len = used_array_len = cnt; 366 if (!svc_sendreply(transp, xdr_utmp_array, 367 (caddr_t)&utmp_array_res)) 368 msgout(replyerr); 369 utmp_array_res.utmp_array_len = alloc_array_len; 370 } 371 break; 372 default: 373 svcerr_noproc(transp); 374 break; 375 } 376 _rpcsvcdirty = 0; 377 378 } 379 380 free_ua_entry(uap) 381 rusers_utmp *uap; 382 { 383 if (uap == NULL) 384 return; 385 if (uap->ut_user) 386 free(uap->ut_user); 387 if (uap->ut_line) 388 free(uap->ut_line); 389 if (uap->ut_host) 390 free(uap->ut_host); 391 } 392 393 394 395 /* find & return number of minutes current tty has been idle */ 396 findidle(name, ln, now) 397 char *name; 398 int ln; 399 time_t now; 400 { 401 struct stat stbuf; 402 long lastaction, diff; 403 char ttyname[32]; 404 405 strcpy(ttyname, "/dev/"); 406 strncat(ttyname, name, ln); 407 if (stat(ttyname, &stbuf) < 0) 408 return (INT_MAX); 409 lastaction = stbuf.st_atime; 410 diff = now - lastaction; 411 diff = DIV60(diff); 412 if (diff < 0) diff = 0; 413 return (diff); 414 } 415 416 static 417 usys5to_ru(s5, bss) 418 struct utmpx *s5; 419 struct ru_utmp *bss; 420 { 421 int i; 422 423 #ifdef DEBUG 424 printf("sizeof (bss->ut_host) == %d\n", sizeof (bss->ut_host)); 425 #endif 426 strncpy(bss->ut_name, s5->ut_name, sizeof (bss->ut_name)); 427 strncpy(bss->ut_line, s5->ut_line, sizeof (bss->ut_line)); 428 strncpy(bss->ut_host, s5->ut_host, sizeof (bss->ut_host)); 429 bss->ut_time = s5->ut_xtime; 430 } 431 432 static void 433 msgout(msg) 434 char *msg; 435 { 436 #ifdef RPC_SVC_FG 437 if (_rpcpmstart) 438 syslog(LOG_ERR, msg); 439 else 440 (void) fprintf(stderr, "%s\n", msg); 441 #else 442 syslog(LOG_ERR, msg); 443 #endif 444 } 445 446 static void 447 closedown(sig) 448 int sig; 449 { 450 if (_rpcsvcrecent) { 451 _rpcsvcrecent = 0; 452 } else { 453 if (_rpcsvcdirty == 0) { 454 int i, openfd; 455 struct t_info tinfo; 456 457 if (t_getinfo(0, &tinfo) || (tinfo.servtype == T_CLTS)) 458 exit(0); 459 460 for (i = 0, openfd = 0; 461 i < svc_max_pollfd && openfd < 2; 462 i++) { 463 if (svc_pollfd[i].fd >= 0) 464 openfd++; 465 } 466 467 if (openfd <= 1) 468 exit(0); 469 } 470 } 471 (void) signal(SIGALRM, closedown); 472 (void) alarm(_RPCSVC_CLOSEDOWN); 473 } 474 475 unsigned 476 min(a, b) 477 unsigned a; 478 unsigned b; 479 { 480 if (a < b) 481 return (a); 482 else 483 return (b); 484 } 485