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