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 2005 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 static void free_ua_entry(rusers_utmp *uap);
  79 static int findidle(char *name, int ln, time_t  now);
  80 static void usys5to_ru(struct utmpx *s5, struct ru_utmp *bss);
  81 
  82 int
  83 main(int argc, char *argv[])
  84 {
  85         pid_t pid;
  86         int i;
  87         int connmaxrec = RPC_MAXDATASIZE;
  88 
  89         /*
  90          * Set non-blocking mode and maximum record size for
  91          * connection oriented RPC transports.
  92          */
  93         if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
  94                 msgout("unable to set maximum RPC record size");
  95         }
  96 
  97         /*
  98          * If stdin looks like a TLI endpoint, we assume
  99          * that we were started by a port monitor. If
 100          * t_getstate fails with TBADF, this is not a
 101          * TLI endpoint.
 102          */
 103         if (t_getstate(0) != -1 || t_errno != TBADF) {
 104                 char *netid;
 105                 struct netconfig *nconf = NULL;
 106                 SVCXPRT *transp;
 107                 int pmclose;
 108                 extern char *getenv();
 109 
 110                 _rpcpmstart = 1;
 111                 openlog("rusers", LOG_PID, LOG_DAEMON);
 112                 if ((netid = getenv("NLSPROVIDER")) == NULL) {
 113 #ifdef DEBUG
 114                         msgout("cannot get transport name");
 115 #endif
 116                 } else if ((nconf = getnetconfigent(netid)) == NULL) {
 117 #ifdef DEBUG
 118                         msgout("cannot get transport info");
 119 #endif
 120                 }
 121                 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
 122                         msgout("cannot create server handle");
 123                         exit(1);
 124                 }
 125                 if (nconf)
 126                         freenetconfigent(nconf);
 127                 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service,
 128                                 0)) {
 129         msgout("unable to register (RUSERSPROG, RUSERSVERS_3).");
 130                         exit(1);
 131                 }
 132                 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE,
 133                                 rusers_service, 0)) {
 134         msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE).");
 135                         exit(1);
 136                 }
 137                 (void) signal(SIGALRM, closedown);
 138                 (void) alarm(_RPCSVC_CLOSEDOWN);
 139                 svc_run();
 140                 msgout("svc_run returned");
 141                 exit(1);
 142                 /* NOTREACHED */
 143         }
 144 #ifndef RPC_SVC_FG
 145         pid = fork();
 146         if (pid < 0) {
 147                 perror("rpc.rusersd: cannot fork");
 148                 exit(1);
 149         }
 150         if (pid)
 151                 exit(0);
 152         for (i = 0; i < 20; i++)
 153                 (void) close(i);
 154         setsid();
 155         openlog("rusers", LOG_PID, LOG_DAEMON);
 156 #endif
 157         if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")) {
 158             msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath");
 159                 exit(1);
 160         }
 161         if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE,
 162                         "netpath")) {
 163             msgout(
 164                 "unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath");
 165                 exit(1);
 166         }
 167 
 168         svc_run();
 169         msgout("svc_run returned");
 170         return (1);
 171 }
 172 
 173 
 174 /*
 175  * This routine gets the user information.
 176  * "all" specifies whether all listings should be counted, or only those of
 177  *      type "USER_PROCESS".
 178  * "version" is either RUSERSVERS_IDLE or RUSERSVERS_3.  If anything else,
 179  *      just a count is returned.
 180  * "limit" specifies the maximum number of entries to be processed.
 181  *
 182  * For both versions, the results are placed into an external variable.
 183  * For RUSERSVERS_IDLE, this routine mallocs entries in a vector as it
 184  * processed each utmpx entry.  These malloc'd entries must be freed after the
 185  * results are returned.
 186  * For RUSERSVERS_3, this routine uses array entries that are malloc'd prior
 187  * to this routine being called. "limit" is the number of elements available.
 188  */
 189 int
 190 getutmpx_3(all, version, limit)
 191         int all;                /* give all listings? */
 192         int version;            /* version 2 or 3 */
 193         int limit;              /* limits users returned, 0 means no limit */
 194 {
 195         struct utmpx *utent;
 196         struct utmpidle **q = utmpidlearr.uia_arr;
 197         int minidle;
 198         int cnt = 0;
 199         time_t now;
 200         extern char *s_malodup();
 201 
 202         time(&now);         /* only one call to time() for this rpc call */
 203         setutxent();            /* reset the utmpx file */
 204         while ((utent = getutxent()) != NULL && (limit == 0 || cnt < limit)) {
 205                 if (utent->ut_line[0] == '\0' || utent->ut_user[0] == '\0')
 206                         continue;
 207                 /*
 208                  * List only user processes.
 209                  * XXX modified to exclude cmdtool style window entries.
 210                  */
 211                 if ((all == REAL_USERS) && ((utent->ut_type != USER_PROCESS) ||
 212                     nonuserx(*utent)))
 213                         continue;
 214 
 215                 if (version == RUSERSVERS_IDLE) {
 216                         /*
 217                          * need to free this; done after svc_sendreply.
 218                          */
 219                         *q = (struct utmpidle *)
 220                                 malloc(sizeof (struct utmpidle));
 221                         (*q)->ui_idle = findidle(utent->ut_line,
 222                                                 sizeof (utent->ut_line), now);
 223                         if (strncmp(utent->ut_line, "console",
 224                                 strlen("console")) == 0) {
 225                                 (*q)->ui_idle = min((*q)->ui_idle,
 226                                         console_idle(now));
 227                         }
 228                         usys5to_ru(utent, &((*q)->ui_utmp));
 229 #ifdef DEBUG
 230                         printf("%-*s %-*s  %s; idle %d",
 231                             sizeof (utent->ut_line),
 232                             utent->ut_line,
 233                             sizeof (utent->ut_name),
 234                             utent->ut_name,
 235                             ctime(&utent->ut_xtime),
 236                             (*q)->ui_idle);
 237 #endif
 238                         q++;
 239                 } else if (version == RUSERSVERS_3) {
 240 #define uav     utmp_array_res.utmp_array_val
 241 
 242                         uav[cnt].ut_host =
 243                                 s_malodup(utent->ut_host, utent->ut_syslen);
 244                         uav[cnt].ut_user = s_malodup(utent->ut_user,
 245                                 sizeof (utent->ut_user));
 246                         uav[cnt].ut_line = s_malodup(utent->ut_line,
 247                                 sizeof (utent->ut_line));
 248                         uav[cnt].ut_type = utent->ut_type;
 249                         uav[cnt].ut_time = utent->ut_xtime;
 250                         uav[cnt].ut_idle = findidle(utent->ut_line,
 251                                                 sizeof (utent->ut_line), now);
 252                         if (strncmp(utent->ut_line, "console",
 253                                 strlen("console")) == 0) {
 254                                 uav[cnt].ut_idle =
 255                                         min(uav[cnt].ut_idle,
 256                                                         console_idle(now));
 257                         }
 258 #ifdef DEBUG
 259                         printf("user: %-10s line: %-10s  %s; idle %d (%s)\n",
 260                                         uav[cnt].ut_line, uav[cnt].ut_user,
 261                                         ctime((time_t *)&uav[cnt].ut_time),
 262                                         uav[cnt].ut_idle, uav[cnt].ut_host);
 263 #endif
 264 #undef  uav
 265                 }
 266                 cnt++;
 267         }
 268         return (cnt);
 269 }
 270 
 271 /*
 272  * "string" is a character array with maximum size "size".  Return a
 273  * malloc'd string that's a duplicate of the string.
 274  */
 275 char *
 276 s_malodup(string, size)
 277 char *string;
 278 int size;
 279 {
 280         char *tmp;
 281 
 282         tmp = (char *)malloc(size+1);
 283         if (tmp == NULL) {
 284                 msgout("rpc.rusersd: malloc failed (2)");
 285                 return (NULL);
 286         }
 287         strncpy(tmp, string, size);
 288         tmp[size] = '\0';
 289         return (tmp);
 290 }
 291 
 292 
 293 int
 294 console_idle(now)
 295         time_t now;
 296 {
 297         /*
 298          * On the console, the user may be running a window system; if so,
 299          * their activity will show up in the last-access times of
 300          * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle
 301          * times on those two devices and "/dev/console" and treat that as
 302          * the idle time.
 303          */
 304         return (min((unsigned)findidle("kbd", strlen("kbd"), now),
 305                 (unsigned)findidle("mouse", strlen("mouse"), now)));
 306 }
 307 
 308 static void
 309 rusers_service(rqstp, transp)
 310         register struct svc_req *rqstp;
 311         register SVCXPRT *transp;
 312 {
 313         int i;
 314         int cnt;
 315         char *replyerr = "rpc.rusersd: error replying to request";
 316 
 317         _rpcsvcrecent = _rpcsvcdirty = 1;
 318         switch (rqstp->rq_proc) {
 319         case 0:
 320                 if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
 321                         msgout(replyerr);
 322                 }
 323                 break;
 324         case RUSERSPROC_NUM:
 325                 cnt = getutmpx_3(REAL_USERS, 0, 0);
 326                 if (!svc_sendreply(transp, xdr_u_long, (caddr_t)&cnt))
 327                         msgout(replyerr);
 328                 break;
 329         case RUSERSPROC_NAMES:
 330         case RUSERSPROC_ALLNAMES:
 331                 if (rqstp->rq_vers == RUSERSVERS_IDLE) {
 332                         utmpidlearr.uia_arr = (struct utmpidle **)
 333                                 malloc(MAXUSERS*sizeof (struct utmpidle *));
 334                         utmpidlearr.uia_cnt = getutmpx_3(rqstp->rq_proc ==
 335                                 RUSERSPROC_ALLNAMES,
 336                                 RUSERSVERS_IDLE, MAXUSERS);
 337                         if (!svc_sendreply(transp, xdr_utmpidlearr,
 338                                         (caddr_t)&utmpidlearr))
 339                                 msgout(replyerr);
 340                         for (i = 0; i < utmpidlearr.uia_cnt; i++) {
 341                                 free(utmpidlearr.uia_arr[i]);
 342                         }
 343                         free(utmpidlearr.uia_arr);
 344                 } else if (rqstp->rq_vers == RUSERSVERS_3) {
 345                         int entries, alloc_array_len;
 346 
 347                         /*
 348                          * Always free strings from previous results array
 349                          */
 350                         for (i = 0; i < used_array_len; i++) {
 351                         free_ua_entry(&utmp_array_res.utmp_array_val[i]);
 352                         }
 353                         entries = (rqstp->rq_proc == RUSERSPROC_ALLNAMES);
 354                         cnt = getutmpx_3(entries, 0, 0);        /* get cnt */
 355                         if (cnt > utmp_array_res.utmp_array_len) {
 356                                 free(utmp_array_res.utmp_array_val);
 357                                 utmp_array_res.utmp_array_len = 0;
 358                                 utmp_array_res.utmp_array_val = (rusers_utmp *)
 359                                         malloc(cnt * sizeof (rusers_utmp));
 360                                 if (utmp_array_res.utmp_array_val == NULL) {
 361                                     msgout("rpc.rusersd: malloc failed (1)");
 362                                     break;
 363                                 }
 364                                 alloc_array_len = cnt;
 365                         } else {
 366                                 alloc_array_len = utmp_array_res.utmp_array_len;
 367                         }
 368                         cnt = getutmpx_3(entries, RUSERSVERS_3, cnt);
 369                         utmp_array_res.utmp_array_len = used_array_len = cnt;
 370                         if (!svc_sendreply(transp, xdr_utmp_array,
 371                                         (caddr_t)&utmp_array_res))
 372                                 msgout(replyerr);
 373                         utmp_array_res.utmp_array_len = alloc_array_len;
 374                 }
 375                 break;
 376         default:
 377                 svcerr_noproc(transp);
 378                 break;
 379         }
 380         _rpcsvcdirty = 0;
 381 
 382 }
 383 
 384 static void
 385 free_ua_entry(rusers_utmp *uap)
 386 {
 387         if (uap == NULL)
 388                 return;
 389         if (uap->ut_user)
 390                 free(uap->ut_user);
 391         if (uap->ut_line)
 392                 free(uap->ut_line);
 393         if (uap->ut_host)
 394                 free(uap->ut_host);
 395 }
 396 
 397 
 398 
 399 /* find & return number of minutes current tty has been idle */
 400 static int
 401 findidle(char *name, int ln, time_t     now)
 402 {
 403         struct stat stbuf;
 404         long lastaction, diff;
 405         char ttyname[32];
 406 
 407         strcpy(ttyname, "/dev/");
 408         strncat(ttyname, name, ln);
 409         if (stat(ttyname, &stbuf) < 0)
 410                 return (INT_MAX);
 411         lastaction = stbuf.st_atime;
 412         diff = now - lastaction;
 413         diff = DIV60(diff);
 414         if (diff < 0) diff = 0;
 415         return (diff);
 416 }
 417 
 418 static void
 419 usys5to_ru(struct utmpx *s5, 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 }