Home | History | Annotate | Line # | Download | only in rpc.rusersd
rusers_proc.c revision 1.8
      1 /*-
      2  *  Copyright (c) 1993 John Brezak
      3  *  All rights reserved.
      4  *
      5  *  Redistribution and use in source and binary forms, with or without
      6  *  modification, are permitted provided that the following conditions
      7  *  are met:
      8  *  1. Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #ifndef lint
     30 static char rcsid[] = "$Id: rusers_proc.c,v 1.8 1994/12/23 14:29:42 cgd Exp $";
     31 #endif /* not lint */
     32 
     33 #include <signal.h>
     34 #include <sys/types.h>
     35 #include <sys/time.h>
     36 #include <utmp.h>
     37 #include <stdio.h>
     38 #include <syslog.h>
     39 #include <rpc/rpc.h>
     40 #include <sys/socket.h>
     41 #include <sys/param.h>
     42 #include <sys/stat.h>
     43 #ifdef XIDLE
     44 #include <setjmp.h>
     45 #include <X11/Xlib.h>
     46 #include <X11/extensions/xidle.h>
     47 #endif
     48 #include <rpcsvc/rusers.h>	/* New version */
     49 #include <rpcsvc/rnusers.h>	/* Old version */
     50 
     51 #define	IGNOREUSER	"sleeper"
     52 
     53 #ifdef OSF
     54 #define _PATH_UTMP UTMP_FILE
     55 #endif
     56 
     57 #ifndef _PATH_UTMP
     58 #define _PATH_UTMP "/etc/utmp"
     59 #endif
     60 
     61 #ifndef _PATH_DEV
     62 #define _PATH_DEV "/dev"
     63 #endif
     64 
     65 #ifndef UT_LINESIZE
     66 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line)
     67 #endif
     68 #ifndef UT_NAMESIZE
     69 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
     70 #endif
     71 #ifndef UT_HOSTSIZE
     72 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
     73 #endif
     74 
     75 typedef char ut_line_t[UT_LINESIZE];
     76 typedef char ut_name_t[UT_NAMESIZE];
     77 typedef char ut_host_t[UT_HOSTSIZE];
     78 
     79 struct rusers_utmp utmps[MAXUSERS];
     80 struct utmpidle *utmp_idlep[MAXUSERS];
     81 struct utmpidle utmp_idle[MAXUSERS];
     82 ut_line_t line[MAXUSERS];
     83 ut_name_t name[MAXUSERS];
     84 ut_host_t host[MAXUSERS];
     85 
     86 extern int from_inetd;
     87 
     88 FILE *ufp;
     89 
     90 #ifdef XIDLE
     91 Display *dpy;
     92 
     93 static jmp_buf openAbort;
     94 
     95 static void
     96 abortOpen ()
     97 {
     98     longjmp (openAbort, 1);
     99 }
    100 
    101 XqueryIdle(char *display)
    102 {
    103         int first_event, first_error;
    104         Time IdleTime;
    105 
    106         (void) signal (SIGALRM, abortOpen);
    107         (void) alarm ((unsigned) 10);
    108         if (!setjmp (openAbort)) {
    109                 if (!(dpy= XOpenDisplay(display))) {
    110                         syslog(LOG_ERR, "Cannot open display %s", display);
    111                         return(-1);
    112                 }
    113                 if (XidleQueryExtension(dpy, &first_event, &first_error)) {
    114                         if (!XGetIdleTime(dpy, &IdleTime)) {
    115                                 syslog(LOG_ERR, "%s: Unable to get idle time.", display);
    116                                 return(-1);
    117                         }
    118                 }
    119                 else {
    120                         syslog(LOG_ERR, "%s: Xidle extension not loaded.", display);
    121                         return(-1);
    122                 }
    123                 XCloseDisplay(dpy);
    124         }
    125         else {
    126                 syslog(LOG_ERR, "%s: Server grabbed for over 10 seconds.", display);
    127                 return(-1);
    128         }
    129         (void) signal (SIGALRM, SIG_DFL);
    130         (void) alarm ((unsigned) 0);
    131 
    132         IdleTime /= 1000;
    133         return((IdleTime + 30) / 60);
    134 }
    135 #endif
    136 
    137 static u_int
    138 getidle(char *tty, char *display)
    139 {
    140         struct stat st;
    141         char devname[PATH_MAX];
    142         time_t now;
    143         u_long idle;
    144 
    145         /*
    146          * If this is an X terminal or console, then try the
    147          * XIdle extension
    148          */
    149 #ifdef XIDLE
    150         if (display && *display && (idle = XqueryIdle(display)) >= 0)
    151                 return(idle);
    152 #endif
    153         idle = 0;
    154         if (*tty == 'X') {
    155                 u_long kbd_idle, mouse_idle;
    156 #if	!defined(i386)
    157                 kbd_idle = getidle("kbd", NULL);
    158 #else
    159 #if (__GNUC__ >= 2)
    160 #warning i386 console hack here
    161 #endif
    162                 kbd_idle = getidle("vga", NULL);
    163 #endif
    164                 mouse_idle = getidle("mouse", NULL);
    165                 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
    166         }
    167         else {
    168                 sprintf(devname, "%s/%s", _PATH_DEV, tty);
    169                 if (stat(devname, &st) < 0) {
    170 #ifdef DEBUG
    171                         printf("%s: %s\n", devname, strerror(errno));
    172 #endif
    173                         return(-1);
    174                 }
    175                 time(&now);
    176 #ifdef DEBUG
    177                 printf("%s: now=%d atime=%d\n", devname, now,
    178                        st.st_atime);
    179 #endif
    180                 idle = now - st.st_atime;
    181                 idle = (idle + 30) / 60; /* secs->mins */
    182         }
    183         if (idle < 0) idle = 0;
    184 
    185         return(idle);
    186 }
    187 
    188 int *
    189 rusers_num()
    190 {
    191         static int num_users = 0;
    192 	struct utmp usr;
    193 
    194         ufp = fopen(_PATH_UTMP, "r");
    195         if (!ufp) {
    196                 syslog(LOG_ERR, "%m");
    197                 return(0);
    198         }
    199 
    200         /* only entries with both name and line fields */
    201         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
    202                 if (*usr.ut_name && *usr.ut_line &&
    203 		    strncmp(usr.ut_name, IGNOREUSER,
    204                             sizeof(usr.ut_name))
    205 #ifdef OSF
    206                     && usr.ut_type == USER_PROCESS
    207 #endif
    208                     ) {
    209                         num_users++;
    210                 }
    211 
    212         fclose(ufp);
    213         return(&num_users);
    214 }
    215 
    216 static utmp_array *
    217 do_names_3(int all)
    218 {
    219         static utmp_array ut;
    220 	struct utmp usr;
    221         int nusers = 0;
    222 
    223         bzero((char *)&ut, sizeof(ut));
    224         ut.utmp_array_val = &utmps[0];
    225 
    226 	ufp = fopen(_PATH_UTMP, "r");
    227         if (!ufp) {
    228                 syslog(LOG_ERR, "%m");
    229                 return(&ut);
    230         }
    231 
    232         /* only entries with both name and line fields */
    233         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    234                nusers < MAXUSERS)
    235                 if (*usr.ut_name && *usr.ut_line &&
    236 		    strncmp(usr.ut_name, IGNOREUSER,
    237                             sizeof(usr.ut_name))
    238 #ifdef OSF
    239                     && usr.ut_type == USER_PROCESS
    240 #endif
    241                     ) {
    242                         utmps[nusers].ut_type = RUSERS_USER_PROCESS;
    243                         utmps[nusers].ut_time =
    244                                 usr.ut_time;
    245                         utmps[nusers].ut_idle =
    246                                 getidle(usr.ut_line, usr.ut_host);
    247                         utmps[nusers].ut_line = line[nusers];
    248                         strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
    249                         utmps[nusers].ut_user = name[nusers];
    250                         strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
    251                         utmps[nusers].ut_host = host[nusers];
    252                         strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
    253                         nusers++;
    254                 }
    255         ut.utmp_array_len = nusers;
    256 
    257         fclose(ufp);
    258         return(&ut);
    259 }
    260 
    261 utmp_array *
    262 rusersproc_names_3()
    263 {
    264         return(do_names_3(0));
    265 }
    266 
    267 utmp_array *
    268 rusersproc_allnames_3()
    269 {
    270         return(do_names_3(1));
    271 }
    272 
    273 static struct utmpidlearr *
    274 do_names_2(int all)
    275 {
    276         static struct utmpidlearr ut;
    277 	struct utmp usr;
    278         int nusers = 0;
    279 
    280         bzero((char *)&ut, sizeof(ut));
    281         ut.uia_arr = utmp_idlep;
    282         ut.uia_cnt = 0;
    283 
    284 	ufp = fopen(_PATH_UTMP, "r");
    285         if (!ufp) {
    286                 syslog(LOG_ERR, "%m");
    287                 return(&ut);
    288         }
    289 
    290         /* only entries with both name and line fields */
    291         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    292                nusers < MAXUSERS)
    293                 if (*usr.ut_name && *usr.ut_line &&
    294 		    strncmp(usr.ut_name, IGNOREUSER,
    295                             sizeof(usr.ut_name))
    296 #ifdef OSF
    297                     && usr.ut_type == USER_PROCESS
    298 #endif
    299                     ) {
    300                         utmp_idlep[nusers] = &utmp_idle[nusers];
    301                         utmp_idle[nusers].ui_utmp.ut_time =
    302                                 usr.ut_time;
    303                         utmp_idle[nusers].ui_idle =
    304                                 getidle(usr.ut_line, usr.ut_host);
    305                         strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, sizeof(utmp_idle[nusers].ui_utmp.ut_line));
    306                         strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, sizeof(utmp_idle[nusers].ui_utmp.ut_name));
    307                         strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, sizeof(utmp_idle[nusers].ui_utmp.ut_host));
    308                         nusers++;
    309                 }
    310 
    311         ut.uia_cnt = nusers;
    312         fclose(ufp);
    313         return(&ut);
    314 }
    315 
    316 struct utmpidlearr *
    317 rusersproc_names_2()
    318 {
    319         return(do_names_2(0));
    320 }
    321 
    322 struct utmpidlearr *
    323 rusersproc_allnames_2()
    324 {
    325         return(do_names_2(1));
    326 }
    327 
    328 void
    329 rusers_service(rqstp, transp)
    330 	struct svc_req *rqstp;
    331 	SVCXPRT *transp;
    332 {
    333 	union {
    334 		int fill;
    335 	} argument;
    336 	char *result;
    337 	bool_t (*xdr_argument)(), (*xdr_result)();
    338 	char *(*local)();
    339 
    340 	switch (rqstp->rq_proc) {
    341 	case NULLPROC:
    342 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    343 		goto leave;
    344 
    345 	case RUSERSPROC_NUM:
    346 		xdr_argument = xdr_void;
    347 		xdr_result = xdr_int;
    348                 switch (rqstp->rq_vers) {
    349                 case RUSERSVERS_3:
    350                 case RUSERSVERS_IDLE:
    351                         local = (char *(*)()) rusers_num;
    352                         break;
    353                 default:
    354                         svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    355                         goto leave;
    356                         /*NOTREACHED*/
    357                 }
    358 		break;
    359 
    360 	case RUSERSPROC_NAMES:
    361 		xdr_argument = xdr_void;
    362 		xdr_result = xdr_utmp_array;
    363                 switch (rqstp->rq_vers) {
    364                 case RUSERSVERS_3:
    365                         local = (char *(*)()) rusersproc_names_3;
    366                         break;
    367 
    368                 case RUSERSVERS_IDLE:
    369                         xdr_result = xdr_utmpidlearr;
    370                         local = (char *(*)()) rusersproc_names_2;
    371                         break;
    372 
    373                 default:
    374                         svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    375                         goto leave;
    376                         /*NOTREACHED*/
    377                 }
    378 		break;
    379 
    380 	case RUSERSPROC_ALLNAMES:
    381 		xdr_argument = xdr_void;
    382 		xdr_result = xdr_utmp_array;
    383                 switch (rqstp->rq_vers) {
    384                 case RUSERSVERS_3:
    385                         local = (char *(*)()) rusersproc_allnames_3;
    386                         break;
    387 
    388                 case RUSERSVERS_IDLE:
    389                         xdr_result = xdr_utmpidlearr;
    390                         local = (char *(*)()) rusersproc_allnames_2;
    391                         break;
    392 
    393                 default:
    394                         svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    395                         goto leave;
    396                         /*NOTREACHED*/
    397                 }
    398 		break;
    399 
    400 	default:
    401 		svcerr_noproc(transp);
    402 		goto leave;
    403 	}
    404 	bzero((char *)&argument, sizeof(argument));
    405 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
    406 		svcerr_decode(transp);
    407 		goto leave;
    408 	}
    409 	result = (*local)(&argument, rqstp);
    410 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    411 		svcerr_systemerr(transp);
    412 	}
    413 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
    414 		(void)fprintf(stderr, "unable to free arguments\n");
    415 		exit(1);
    416 	}
    417 leave:
    418         if (from_inetd)
    419                 exit(0);
    420 }
    421