Home | History | Annotate | Line # | Download | only in rpc.rusersd
rusers_proc.c revision 1.6
      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.6 1993/11/21 18:56:35 brezak 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(__386BSD__)
    157                 kbd_idle = getidle("kbd", NULL);
    158 #else
    159                 kbd_idle = getidle("vga", NULL);
    160 #endif
    161                 mouse_idle = getidle("mouse", NULL);
    162                 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
    163         }
    164         else {
    165                 sprintf(devname, "%s/%s", _PATH_DEV, tty);
    166                 if (stat(devname, &st) < 0) {
    167 #ifdef DEBUG
    168                         printf("%s: %s\n", devname, strerror(errno));
    169 #endif
    170                         return(-1);
    171                 }
    172                 time(&now);
    173 #ifdef DEBUG
    174                 printf("%s: now=%d atime=%d\n", devname, now,
    175                        st.st_atime);
    176 #endif
    177                 idle = now - st.st_atime;
    178                 idle = (idle + 30) / 60; /* secs->mins */
    179         }
    180         if (idle < 0) idle = 0;
    181 
    182         return(idle);
    183 }
    184 
    185 int *
    186 rusers_num()
    187 {
    188         int num_users = 0;
    189 	struct utmp usr;
    190 
    191         ufp = fopen(_PATH_UTMP, "r");
    192         if (!ufp) {
    193                 syslog(LOG_ERR, "%m");
    194                 return(0);
    195         }
    196 
    197         /* only entries with both name and line fields */
    198         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
    199                 if (*usr.ut_name && *usr.ut_line &&
    200 		    strncmp(usr.ut_name, IGNOREUSER,
    201                             sizeof(usr.ut_name))
    202 #ifdef OSF
    203                     && usr.ut_type == USER_PROCESS
    204 #endif
    205                     ) {
    206                         num_users++;
    207                 }
    208 
    209         fclose(ufp);
    210         return(&num_users);
    211 }
    212 
    213 static utmp_array *
    214 do_names_3(int all)
    215 {
    216         static utmp_array ut;
    217 	struct utmp usr;
    218         int nusers = 0;
    219 
    220         bzero((char *)&ut, sizeof(ut));
    221         ut.utmp_array_val = &utmps[0];
    222 
    223 	ufp = fopen(_PATH_UTMP, "r");
    224         if (!ufp) {
    225                 syslog(LOG_ERR, "%m");
    226                 return(&ut);
    227         }
    228 
    229         /* only entries with both name and line fields */
    230         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    231                nusers < MAXUSERS)
    232                 if (*usr.ut_name && *usr.ut_line &&
    233 		    strncmp(usr.ut_name, IGNOREUSER,
    234                             sizeof(usr.ut_name))
    235 #ifdef OSF
    236                     && usr.ut_type == USER_PROCESS
    237 #endif
    238                     ) {
    239                         utmps[nusers].ut_type = RUSERS_USER_PROCESS;
    240                         utmps[nusers].ut_time =
    241                                 usr.ut_time;
    242                         utmps[nusers].ut_idle =
    243                                 getidle(usr.ut_line, usr.ut_host);
    244                         utmps[nusers].ut_line = line[nusers];
    245                         strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
    246                         utmps[nusers].ut_user = name[nusers];
    247                         strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
    248                         utmps[nusers].ut_host = host[nusers];
    249                         strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
    250                         nusers++;
    251                 }
    252         ut.utmp_array_len = nusers;
    253 
    254         fclose(ufp);
    255         return(&ut);
    256 }
    257 
    258 utmp_array *
    259 rusersproc_names_3()
    260 {
    261         return(do_names_3(0));
    262 }
    263 
    264 utmp_array *
    265 rusersproc_allnames_3()
    266 {
    267         return(do_names_3(1));
    268 }
    269 
    270 static struct utmpidlearr *
    271 do_names_2(int all)
    272 {
    273         static struct utmpidlearr ut;
    274 	struct utmp usr;
    275         int nusers = 0;
    276 
    277         bzero((char *)&ut, sizeof(ut));
    278         ut.uia_arr = utmp_idlep;
    279         ut.uia_cnt = 0;
    280 
    281 	ufp = fopen(_PATH_UTMP, "r");
    282         if (!ufp) {
    283                 syslog(LOG_ERR, "%m");
    284                 return(&ut);
    285         }
    286 
    287         /* only entries with both name and line fields */
    288         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    289                nusers < MAXUSERS)
    290                 if (*usr.ut_name && *usr.ut_line &&
    291 		    strncmp(usr.ut_name, IGNOREUSER,
    292                             sizeof(usr.ut_name))
    293 #ifdef OSF
    294                     && usr.ut_type == USER_PROCESS
    295 #endif
    296                     ) {
    297                         utmp_idlep[nusers] = &utmp_idle[nusers];
    298                         utmp_idle[nusers].ui_utmp.ut_time =
    299                                 usr.ut_time;
    300                         utmp_idle[nusers].ui_idle =
    301                                 getidle(usr.ut_line, usr.ut_host);
    302                         strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, sizeof(utmp_idle[nusers].ui_utmp.ut_line));
    303                         strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, sizeof(utmp_idle[nusers].ui_utmp.ut_name));
    304                         strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, sizeof(utmp_idle[nusers].ui_utmp.ut_host));
    305                         nusers++;
    306                 }
    307 
    308         ut.uia_cnt = nusers;
    309         fclose(ufp);
    310         return(&ut);
    311 }
    312 
    313 struct utmpidlearr *
    314 rusersproc_names_2()
    315 {
    316         return(do_names_2(0));
    317 }
    318 
    319 struct utmpidlearr *
    320 rusersproc_allnames_2()
    321 {
    322         return(do_names_2(1));
    323 }
    324 
    325 void
    326 rusers_service(rqstp, transp)
    327 	struct svc_req *rqstp;
    328 	SVCXPRT *transp;
    329 {
    330 	union {
    331 		int fill;
    332 	} argument;
    333 	char *result;
    334 	bool_t (*xdr_argument)(), (*xdr_result)();
    335 	char *(*local)();
    336 
    337 	switch (rqstp->rq_proc) {
    338 	case NULLPROC:
    339 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    340 		goto leave;
    341 
    342 	case RUSERSPROC_NUM:
    343 		xdr_argument = xdr_void;
    344 		xdr_result = xdr_int;
    345                 switch (rqstp->rq_vers) {
    346                 case RUSERSVERS_3:
    347                 case RUSERSVERS_IDLE:
    348                         local = (char *(*)()) rusers_num;
    349                         break;
    350                 default:
    351                         svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    352                         goto leave;
    353                         /*NOTREACHED*/
    354                 }
    355 		break;
    356 
    357 	case RUSERSPROC_NAMES:
    358 		xdr_argument = xdr_void;
    359 		xdr_result = xdr_utmp_array;
    360                 switch (rqstp->rq_vers) {
    361                 case RUSERSVERS_3:
    362                         local = (char *(*)()) rusersproc_names_3;
    363                         break;
    364 
    365                 case RUSERSVERS_IDLE:
    366                         xdr_result = xdr_utmpidlearr;
    367                         local = (char *(*)()) rusersproc_names_2;
    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 = xdr_void;
    379 		xdr_result = xdr_utmp_array;
    380                 switch (rqstp->rq_vers) {
    381                 case RUSERSVERS_3:
    382                         local = (char *(*)()) rusersproc_allnames_3;
    383                         break;
    384 
    385                 case RUSERSVERS_IDLE:
    386                         xdr_result = xdr_utmpidlearr;
    387                         local = (char *(*)()) rusersproc_allnames_2;
    388                         break;
    389 
    390                 default:
    391                         svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    392                         goto leave;
    393                         /*NOTREACHED*/
    394                 }
    395 		break;
    396 
    397 	default:
    398 		svcerr_noproc(transp);
    399 		goto leave;
    400 	}
    401 	bzero((char *)&argument, sizeof(argument));
    402 	if (!svc_getargs(transp, xdr_argument, &argument)) {
    403 		svcerr_decode(transp);
    404 		goto leave;
    405 	}
    406 	result = (*local)(&argument, rqstp);
    407 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    408 		svcerr_systemerr(transp);
    409 	}
    410 	if (!svc_freeargs(transp, xdr_argument, &argument)) {
    411 		(void)fprintf(stderr, "unable to free arguments\n");
    412 		exit(1);
    413 	}
    414 leave:
    415         if (from_inetd)
    416                 exit(0);
    417 }
    418