Home | History | Annotate | Line # | Download | only in rpc.rusersd
rusers_proc.c revision 1.1
      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. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #include <signal.h>
     35 #include <sys/types.h>
     36 #include <sys/time.h>
     37 #include <utmp.h>
     38 #include <stdio.h>
     39 #include <syslog.h>
     40 #include <rpc/rpc.h>
     41 #include <sys/socket.h>
     42 #include <sys/param.h>
     43 #include <sys/stat.h>
     44 #ifdef XIDLE
     45 #include <X11/Xlib.h>
     46 #include <X11/extensions/xidle.h>
     47 #endif
     48 #define utmp rutmp
     49 #include <rpcsvc/rnusers.h>
     50 #undef utmp
     51 
     52 #define	IGNOREUSER	"sleeper"
     53 
     54 #ifdef OSF
     55 #define _PATH_UTMP UTMP_FILE
     56 #endif
     57 
     58 #ifndef _PATH_UTMP
     59 #define _PATH_UTMP "/etc/utmp"
     60 #endif
     61 
     62 #ifndef _PATH_DEV
     63 #define _PATH_DEV "/dev"
     64 #endif
     65 
     66 #ifndef UT_LINESIZE
     67 #define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line)
     68 #endif
     69 #ifndef UT_NAMESIZE
     70 #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
     71 #endif
     72 #ifndef UT_HOSTSIZE
     73 #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
     74 #endif
     75 
     76 typedef char ut_line_t[UT_LINESIZE];
     77 typedef char ut_name_t[UT_NAMESIZE];
     78 typedef char ut_host_t[UT_HOSTSIZE];
     79 
     80 utmpidle utmp_idle[MAXUSERS];
     81 rutmp old_utmp[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 = 0;
    144 
    145         /*
    146          * If this is an X terminal or console, then try the
    147          * XIdle extension
    148          */
    149 #ifdef XIDLE
    150         if (display && (idle = XqueryIdle(display)) >= 0)
    151                 return(idle);
    152 #endif
    153         if (*tty == 'X') {
    154                 u_long kbd_idle, mouse_idle;
    155                 kbd_idle = getidle("kbd", NULL);
    156                 mouse_idle = getidle("mouse", NULL);
    157                 idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
    158         }
    159         else {
    160                 sprintf(devname, "%s/%s", _PATH_DEV, tty);
    161                 if (stat(devname, &st) < 0) {
    162                         syslog(LOG_ERR, "%s: %m", devname);
    163                         return(-1);
    164                 }
    165                 time(&now);
    166 #ifdef DEBUG
    167                 printf("%s: now=%d atime=%d\n", devname, now,
    168                        st.st_atime);
    169 #endif
    170                 idle = now - st.st_atime;
    171                 idle = (idle + 30) / 60; /* secs->mins */
    172         }
    173         if (idle < 0) idle = 0;
    174 
    175         return(idle);
    176 }
    177 
    178 static utmpidlearr *
    179 do_names_2(int all)
    180 {
    181         static utmpidlearr ut;
    182 	struct utmp usr;
    183         int nusers = 0;
    184 
    185         bzero((char *)&ut, sizeof(ut));
    186         ut.utmpidlearr_val = &utmp_idle[0];
    187 
    188 	ufp = fopen(_PATH_UTMP, "r");
    189         if (!ufp) {
    190                 syslog(LOG_ERR, "%m");
    191                 return(&ut);
    192         }
    193 
    194         /* only entries with both name and line fields */
    195         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    196                nusers < MAXUSERS)
    197                 if (*usr.ut_name && *usr.ut_line &&
    198 		    strncmp(usr.ut_name, IGNOREUSER,
    199                             sizeof(usr.ut_name))
    200 #ifdef OSF
    201                     && usr.ut_type == USER_PROCESS
    202 #endif
    203                     ) {
    204                         utmp_idle[nusers].ui_utmp.ut_time =
    205                                 usr.ut_time;
    206                         utmp_idle[nusers].ui_idle =
    207                                 getidle(usr.ut_line, usr.ut_host);
    208                         utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
    209                         strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
    210                         utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
    211                         strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
    212                         utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
    213                         strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
    214                         nusers++;
    215                 }
    216 
    217         ut.utmpidlearr_len = nusers;
    218         fclose(ufp);
    219         return(&ut);
    220 }
    221 
    222 int *
    223 rusers_num()
    224 {
    225         int num_users = 0;
    226 	struct utmp usr;
    227 
    228         ufp = fopen(_PATH_UTMP, "r");
    229         if (!ufp) {
    230                 syslog(LOG_ERR, "%m");
    231                 return(0);
    232         }
    233 
    234         /* only entries with both name and line fields */
    235         while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
    236                 if (*usr.ut_name && *usr.ut_line &&
    237 		    strncmp(usr.ut_name, IGNOREUSER,
    238                             sizeof(usr.ut_name))
    239 #ifdef OSF
    240                     && usr.ut_type == USER_PROCESS
    241 #endif
    242                     ) {
    243                         num_users++;
    244                 }
    245 
    246         fclose(ufp);
    247         return(&num_users);
    248 }
    249 
    250 static utmparr *
    251 do_names_1(int all)
    252 {
    253         utmpidlearr *utidle;
    254         utmparr ut;
    255         int i;
    256 
    257         bzero((char *)&ut, sizeof(ut));
    258 
    259         utidle = do_names_2(all);
    260         if (utidle) {
    261                 ut.utmparr_len = utidle->utmpidlearr_len;
    262                 ut.utmparr_val = &old_utmp[0];
    263                 for (i = 0; i < ut.utmparr_len; i++)
    264                         bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
    265                               sizeof(old_utmp[0]));
    266 
    267         }
    268 
    269         return(&ut);
    270 }
    271 
    272 utmpidlearr *
    273 rusersproc_names_2()
    274 {
    275         return(do_names_2(0));
    276 }
    277 
    278 utmpidlearr *
    279 rusersproc_allnames_2()
    280 {
    281         return(do_names_2(1));
    282 }
    283 
    284 utmparr *
    285 rusersproc_names_1()
    286 {
    287         return(do_names_1(0));
    288 }
    289 
    290 utmparr *
    291 rusersproc_allnames_1()
    292 {
    293         return(do_names_1(1));
    294 }
    295 
    296 void
    297 rusers_service(rqstp, transp)
    298 	struct svc_req *rqstp;
    299 	SVCXPRT *transp;
    300 {
    301 	union {
    302 		int fill;
    303 	} argument;
    304 	char *result;
    305 	bool_t (*xdr_argument)(), (*xdr_result)();
    306 	char *(*local)();
    307 
    308 	switch (rqstp->rq_proc) {
    309 	case NULLPROC:
    310 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    311 		goto leave;
    312 
    313 	case RUSERSPROC_NUM:
    314 		xdr_argument = xdr_void;
    315 		xdr_result = xdr_int;
    316                 local = (char *(*)()) rusers_num;
    317 		break;
    318 
    319 	case RUSERSPROC_NAMES:
    320 		xdr_argument = xdr_void;
    321 		xdr_result = xdr_utmpidlearr;
    322                 switch (rqstp->rq_vers) {
    323                 case RUSERSVERS_ORIG:
    324                         local = (char *(*)()) rusersproc_names_1;
    325                         break;
    326                 case RUSERSVERS_IDLE:
    327                         local = (char *(*)()) rusersproc_names_2;
    328                         break;
    329                 default:
    330                         svcerr_progvers(transp);
    331                         goto leave;
    332                         /*NOTREACHED*/
    333                 }
    334 		break;
    335 
    336 	case RUSERSPROC_ALLNAMES:
    337 		xdr_argument = xdr_void;
    338 		xdr_result = xdr_utmpidlearr;
    339                 switch (rqstp->rq_vers) {
    340                 case RUSERSVERS_ORIG:
    341                         local = (char *(*)()) rusersproc_allnames_1;
    342                         break;
    343                 case RUSERSVERS_IDLE:
    344                         local = (char *(*)()) rusersproc_allnames_2;
    345                         break;
    346                 default:
    347                         svcerr_progvers(transp);
    348                         goto leave;
    349                         /*NOTREACHED*/
    350                 }
    351 		break;
    352 
    353 	default:
    354 		svcerr_noproc(transp);
    355 		goto leave;
    356 	}
    357 	bzero((char *)&argument, sizeof(argument));
    358 	if (!svc_getargs(transp, xdr_argument, &argument)) {
    359 		svcerr_decode(transp);
    360 		goto leave;
    361 	}
    362 	result = (*local)(&argument, rqstp);
    363 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    364 		svcerr_systemerr(transp);
    365 	}
    366 	if (!svc_freeargs(transp, xdr_argument, &argument)) {
    367 		(void)fprintf(stderr, "unable to free arguments\n");
    368 		exit(1);
    369 	}
    370 leave:
    371         if (from_inetd)
    372                 exit(0);
    373 }
    374