Home | History | Annotate | Line # | Download | only in rpc.rusersd
rusers_proc.c revision 1.11
      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.11 1995/07/09 00:30:15 pk 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 sigjmp_buf openAbort;
     94 
     95 static void
     96 abortOpen()
     97 {
     98 	siglongjmp(openAbort, 1);
     99 }
    100 
    101 XqueryIdle(display)
    102 	char *display;
    103 {
    104 	int first_event, first_error;
    105 	Time IdleTime;
    106 
    107 	(void) signal(SIGALRM, abortOpen);
    108 	(void) alarm(10);
    109 	if (!sigsetjmp(openAbort)) {
    110 		if ((dpy = XOpenDisplay(display)) == NULL) {
    111 			syslog(LOG_ERR, "cannot open display %s", display);
    112 			return (-1);
    113 		}
    114 		if (XidleQueryExtension(dpy, &first_event, &first_error)) {
    115 			if (!XGetIdleTime(dpy, &IdleTime)) {
    116 				syslog(LOG_ERR, "%s: unable to get idle time", display);
    117 				return (-1);
    118 			}
    119 		} else {
    120 			syslog(LOG_ERR, "%s: Xidle extension not loaded", display);
    121 			return (-1);
    122 		}
    123 		XCloseDisplay(dpy);
    124 	} else {
    125 		syslog(LOG_ERR, "%s: server grabbed for over 10 seconds", display);
    126 		return (-1);
    127 	}
    128 	(void) alarm(0);
    129 	(void) signal(SIGALRM, SIG_DFL);
    130 
    131 	IdleTime /= 1000;
    132 	return ((IdleTime + 30) / 60);
    133 }
    134 #endif
    135 
    136 static u_int
    137 getidle(tty, display)
    138 	char *tty, *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 	} else {
    167 		sprintf(devname, "%s/%s", _PATH_DEV, tty);
    168 		if (stat(devname, &st) < 0) {
    169 #ifdef DEBUG
    170 			printf("%s: %m\n", devname);
    171 #endif
    172 			return (-1);
    173 		}
    174 		time(&now);
    175 #ifdef DEBUG
    176 		printf("%s: now=%d atime=%d\n", devname, now, st.st_atime);
    177 #endif
    178 		idle = now - st.st_atime;
    179 		idle = (idle + 30) / 60; /* secs->mins */
    180 	}
    181 	if (idle < 0)
    182 		idle = 0;
    183 
    184 	return (idle);
    185 }
    186 
    187 int *
    188 rusers_num_svc(arg, rqstp)
    189 	void *arg;
    190 	struct svc_req *rqstp;
    191 {
    192 	static int num_users = 0;
    193 	struct utmp usr;
    194 
    195 	ufp = fopen(_PATH_UTMP, "r");
    196 	if (!ufp) {
    197 		syslog(LOG_ERR, "%m");
    198 		return (0);
    199 	}
    200 
    201 	/* only entries with both name and line fields */
    202 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
    203 		if (*usr.ut_name && *usr.ut_line &&
    204 		    strncmp(usr.ut_name, IGNOREUSER,
    205 			    sizeof(usr.ut_name))
    206 #ifdef OSF
    207 		    && usr.ut_type == USER_PROCESS
    208 #endif
    209 		    ) {
    210 			num_users++;
    211 		}
    212 
    213 	fclose(ufp);
    214 	return (&num_users);
    215 }
    216 
    217 static utmp_array *
    218 do_names_3(int all)
    219 {
    220 	static utmp_array ut;
    221 	struct utmp usr;
    222 	int nusers = 0;
    223 
    224 	bzero((char *)&ut, sizeof(ut));
    225 	ut.utmp_array_val = &utmps[0];
    226 
    227 	ufp = fopen(_PATH_UTMP, "r");
    228 	if (!ufp) {
    229 		syslog(LOG_ERR, "%m");
    230 		return (NULL);
    231 	}
    232 
    233 	/* only entries with both name and line fields */
    234 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    235 	       nusers < MAXUSERS)
    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 			utmps[nusers].ut_type = RUSERS_USER_PROCESS;
    244 			utmps[nusers].ut_time =
    245 				usr.ut_time;
    246 			utmps[nusers].ut_idle =
    247 				getidle(usr.ut_line, usr.ut_host);
    248 			utmps[nusers].ut_line = line[nusers];
    249 			strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
    250 			utmps[nusers].ut_user = name[nusers];
    251 			strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
    252 			utmps[nusers].ut_host = host[nusers];
    253 			strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
    254 			nusers++;
    255 		}
    256 	ut.utmp_array_len = nusers;
    257 
    258 	fclose(ufp);
    259 	return (&ut);
    260 }
    261 
    262 utmp_array *
    263 rusersproc_names_3_svc(arg, rqstp)
    264 	void *arg;
    265 	struct svc_req *rqstp;
    266 {
    267 	return (do_names_3(0));
    268 }
    269 
    270 utmp_array *
    271 rusersproc_allnames_3_svc(arg, rqstp)
    272 	void *arg;
    273 	struct svc_req *rqstp;
    274 {
    275 	return (do_names_3(1));
    276 }
    277 
    278 static struct utmpidlearr *
    279 do_names_2(int all)
    280 {
    281 	static struct utmpidlearr ut;
    282 	struct utmp usr;
    283 	int nusers = 0;
    284 
    285 	bzero((char *)&ut, sizeof(ut));
    286 	ut.uia_arr = utmp_idlep;
    287 	ut.uia_cnt = 0;
    288 
    289 	ufp = fopen(_PATH_UTMP, "r");
    290 	if (!ufp) {
    291 		syslog(LOG_ERR, "%m");
    292 		return (NULL);
    293 	}
    294 
    295 	/* only entries with both name and line fields */
    296 	while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
    297 	       nusers < MAXUSERS)
    298 		if (*usr.ut_name && *usr.ut_line &&
    299 		    strncmp(usr.ut_name, IGNOREUSER,
    300 			    sizeof(usr.ut_name))
    301 #ifdef OSF
    302 		    && usr.ut_type == USER_PROCESS
    303 #endif
    304 		    ) {
    305 			utmp_idlep[nusers] = &utmp_idle[nusers];
    306 			utmp_idle[nusers].ui_utmp.ut_time =
    307 				usr.ut_time;
    308 			utmp_idle[nusers].ui_idle =
    309 				getidle(usr.ut_line, usr.ut_host);
    310 			strncpy(utmp_idle[nusers].ui_utmp.ut_line, usr.ut_line, sizeof(utmp_idle[nusers].ui_utmp.ut_line));
    311 			strncpy(utmp_idle[nusers].ui_utmp.ut_name, usr.ut_name, sizeof(utmp_idle[nusers].ui_utmp.ut_name));
    312 			strncpy(utmp_idle[nusers].ui_utmp.ut_host, usr.ut_host, sizeof(utmp_idle[nusers].ui_utmp.ut_host));
    313 			nusers++;
    314 		}
    315 
    316 	ut.uia_cnt = nusers;
    317 	fclose(ufp);
    318 	return (&ut);
    319 }
    320 
    321 struct utmpidlearr *
    322 rusersproc_names_2_svc(arg, rqstp)
    323 	void *arg;
    324 	struct svc_req *rqstp;
    325 {
    326 	return (do_names_2(0));
    327 }
    328 
    329 struct utmpidlearr *
    330 rusersproc_allnames_2_svc(arg, rqstp)
    331 	void *arg;
    332 	struct svc_req *rqstp;
    333 {
    334 	return (do_names_2(1));
    335 }
    336 
    337 void
    338 rusers_service(rqstp, transp)
    339 	struct svc_req *rqstp;
    340 	SVCXPRT *transp;
    341 {
    342 	union {
    343 		int fill;
    344 	} argument;
    345 	char *result;
    346 	xdrproc_t xdr_argument, xdr_result;
    347 	char *(*local) __P((void *, struct svc_req *));
    348 
    349 	switch (rqstp->rq_proc) {
    350 	case NULLPROC:
    351 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    352 		goto leave;
    353 
    354 	case RUSERSPROC_NUM:
    355 		xdr_argument = (xdrproc_t)xdr_void;
    356 		xdr_result = (xdrproc_t)xdr_int;
    357 		switch (rqstp->rq_vers) {
    358 		case RUSERSVERS_3:
    359 		case RUSERSVERS_IDLE:
    360 			local = (char *(*) __P((void *, struct svc_req *)))
    361 					rusers_num_svc;
    362 			break;
    363 		default:
    364 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    365 			goto leave;
    366 			/*NOTREACHED*/
    367 		}
    368 		break;
    369 
    370 	case RUSERSPROC_NAMES:
    371 		xdr_argument = (xdrproc_t)xdr_void;
    372 		xdr_result = (xdrproc_t)xdr_utmp_array;
    373 		switch (rqstp->rq_vers) {
    374 		case RUSERSVERS_3:
    375 			local = (char *(*) __P((void *, struct svc_req *)))
    376 					rusersproc_names_3_svc;
    377 			break;
    378 
    379 		case RUSERSVERS_IDLE:
    380 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
    381 			local = (char *(*) __P((void *, struct svc_req *)))
    382 					rusersproc_names_2_svc;
    383 			break;
    384 
    385 		default:
    386 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    387 			goto leave;
    388 			/*NOTREACHED*/
    389 		}
    390 		break;
    391 
    392 	case RUSERSPROC_ALLNAMES:
    393 		xdr_argument = (xdrproc_t)xdr_void;
    394 		xdr_result = (xdrproc_t)xdr_utmp_array;
    395 		switch (rqstp->rq_vers) {
    396 		case RUSERSVERS_3:
    397 			local = (char *(*) __P((void *, struct svc_req *)))
    398 					rusersproc_allnames_3_svc;
    399 			break;
    400 
    401 		case RUSERSVERS_IDLE:
    402 			xdr_result = (xdrproc_t)xdr_utmpidlearr;
    403 			local = (char *(*) __P((void *, struct svc_req *)))
    404 					rusersproc_allnames_2_svc;
    405 			break;
    406 
    407 		default:
    408 			svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
    409 			goto leave;
    410 			/*NOTREACHED*/
    411 		}
    412 		break;
    413 
    414 	default:
    415 		svcerr_noproc(transp);
    416 		goto leave;
    417 	}
    418 	bzero((char *)&argument, sizeof(argument));
    419 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
    420 		svcerr_decode(transp);
    421 		goto leave;
    422 	}
    423 	result = (*local)(&argument, rqstp);
    424 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    425 		svcerr_systemerr(transp);
    426 	}
    427 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
    428 		(void)fprintf(stderr, "unable to free arguments\n");
    429 		exit(1);
    430 	}
    431 leave:
    432 	if (from_inetd)
    433 		exit(0);
    434 }
    435