1 /* $OpenBSD: rusers_proc.c,v 1.21 2004/11/04 20:09:18 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/param.h>
32 #include <sys/socket.h>
33 #include <sys/stat.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 <string.h>
42 #include <rpc/rpc.h>
43 #include <rpcsvc/rusers.h> /* New version */
44 #include <rpcsvc/rnusers.h> /* Old version */
45
46 __RCSID("$MirOS: src/libexec/rpc.rusersd/rusers_proc.c,v 1.2 2006/09/21 02:10:54 tg Exp $");
47
48 extern int utmp_fd;
49
50 typedef char ut_line_t[UT_LINESIZE+1];
51 typedef char ut_name_t[UT_NAMESIZE+1];
52 typedef char ut_host_t[UT_HOSTSIZE+1];
53
54 struct rusers_utmp utmps[MAXUSERS];
55 struct utmpidle *utmp_idlep[MAXUSERS];
56 struct utmpidle utmp_idle[MAXUSERS];
57 struct ru_utmp *ru_utmpp[MAXUSERS];
58 struct ru_utmp ru_utmp[MAXUSERS];
59 ut_line_t line[MAXUSERS];
60 ut_name_t name[MAXUSERS];
61 ut_host_t host[MAXUSERS];
62
63 int *rusers_num_svc(void *, struct svc_req *);
64 struct utmpidlearr *rusersproc_names_2_svc(void *, struct svc_req *);
65 struct utmpidlearr *rusersproc_allnames_2_svc(void *, struct svc_req *);
66 struct utmparr *rusersproc_names_1_svc(void *, struct svc_req *);
67 struct utmparr *rusersproc_allnames_1_svc(void *, struct svc_req *);
68 void rusers_service(struct svc_req *, SVCXPRT *);
69
70 extern int from_inetd;
71
72 FILE *ufp;
73
74 static long
getidle(char * tty)75 getidle(char *tty)
76 {
77 char devname[PATH_MAX];
78 struct stat st;
79 long idle;
80 time_t now;
81
82 idle = 0;
83 if (*tty == 'X') {
84 long kbd_idle, mouse_idle;
85 #if !defined(__i386__)
86 kbd_idle = getidle("kbd");
87 #else
88 /*
89 * XXX Icky i386 console hack.
90 */
91 kbd_idle = getidle("vga");
92 #endif
93 mouse_idle = getidle("mouse");
94 idle = (kbd_idle < mouse_idle) ? kbd_idle : mouse_idle;
95 } else {
96 snprintf(devname, sizeof devname, "%s/%.*s", _PATH_DEV,
97 (int)sizeof (tty), tty);
98 if (stat(devname, &st) < 0) {
99 #ifdef DEBUG
100 printf("%s: %m\n", devname);
101 #endif
102 return (0);
103 }
104 time(&now);
105 #ifdef DEBUG
106 printf("%s: now=%d atime=%d\n", devname, now, st.st_atime);
107 #endif
108 idle = now - st.st_atime;
109 idle = (idle + 30) / 60; /* secs->mins */
110 }
111 if (idle < 0)
112 idle = 0;
113
114 return (idle);
115 }
116
117 int *
rusers_num_svc(void * arg,struct svc_req * rqstp)118 rusers_num_svc(void *arg, struct svc_req *rqstp)
119 {
120 static int num_users = 0;
121 struct utmp usr;
122 int fd;
123
124 fd = dup(utmp_fd);
125 if (fd == -1) {
126 syslog(LOG_ERR, "%m");
127 return (0);
128 }
129 lseek(fd, (off_t)0, SEEK_SET);
130 ufp = fdopen(fd, "r");
131 if (!ufp) {
132 close(fd);
133 syslog(LOG_ERR, "%m");
134 return (0);
135 }
136
137 /* only entries with both name and line fields */
138 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
139 if (*usr.ut_name && *usr.ut_line)
140 num_users++;
141
142 fclose(ufp);
143 return (&num_users);
144 }
145
146 static utmp_array *
do_names_3(int all)147 do_names_3(int all)
148 {
149 static utmp_array ut;
150 struct utmp usr;
151 int fd, nusers = 0;
152
153 bzero((char *)&ut, sizeof(ut));
154 ut.utmp_array_val = &utmps[0];
155
156 fd = dup(utmp_fd);
157 if (fd == -1) {
158 syslog(LOG_ERR, "%m");
159 return (0);
160 }
161 lseek(fd, (off_t)0, SEEK_SET);
162 ufp = fdopen(fd, "r");
163 if (!ufp) {
164 close(fd);
165 syslog(LOG_ERR, "%m");
166 return (NULL);
167 }
168
169 /* only entries with both name and line fields */
170 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
171 nusers < MAXUSERS)
172 if (*usr.ut_name && *usr.ut_line) {
173 utmps[nusers].ut_type = RUSERS_USER_PROCESS;
174 utmps[nusers].ut_time = usr.ut_time;
175 utmps[nusers].ut_idle = getidle(usr.ut_line);
176 utmps[nusers].ut_line = line[nusers];
177 memset(line[nusers], 0, sizeof(line[nusers]));
178 memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
179 line[nusers][UT_LINESIZE] = '\0';
180 utmps[nusers].ut_user = name[nusers];
181 memset(name[nusers], 0, sizeof(name[nusers]));
182 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
183 name[nusers][UT_NAMESIZE] = '\0';
184 utmps[nusers].ut_host = host[nusers];
185 memset(host[nusers], 0, sizeof(host[nusers]));
186 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
187 host[nusers][UT_HOSTSIZE] = '\0';
188 nusers++;
189 }
190 ut.utmp_array_len = nusers;
191
192 fclose(ufp);
193 return (&ut);
194 }
195
196 utmp_array *
rusersproc_names_3_svc(void * arg,struct svc_req * rqstp)197 rusersproc_names_3_svc(void *arg, struct svc_req *rqstp)
198 {
199 return (do_names_3(0));
200 }
201
202 utmp_array *
rusersproc_allnames_3_svc(void * arg,struct svc_req * rqstp)203 rusersproc_allnames_3_svc(void *arg, struct svc_req *rqstp)
204 {
205 return (do_names_3(1));
206 }
207
208 static struct utmpidlearr *
do_names_2(int all)209 do_names_2(int all)
210 {
211 static struct utmpidlearr ut;
212 struct utmp usr;
213 int fd, nusers = 0;
214
215 bzero((char *)&ut, sizeof(ut));
216 ut.uia_arr = utmp_idlep;
217 ut.uia_cnt = 0;
218
219 fd = dup(utmp_fd);
220 if (fd == -1) {
221 syslog(LOG_ERR, "%m");
222 return (0);
223 }
224 lseek(fd, (off_t)0, SEEK_SET);
225 ufp = fdopen(fd, "r");
226 if (!ufp) {
227 close(fd);
228 syslog(LOG_ERR, "%m");
229 return (NULL);
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 utmp_idlep[nusers] = &utmp_idle[nusers];
237 utmp_idle[nusers].ui_utmp.ut_time = usr.ut_time;
238 utmp_idle[nusers].ui_idle = getidle(usr.ut_line);
239 utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
240 memset(line[nusers], 0, sizeof(line[nusers]));
241 memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
242 line[nusers][UT_LINESIZE] = '\0';
243 utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
244 memset(name[nusers], 0, sizeof(name[nusers]));
245 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
246 name[nusers][UT_NAMESIZE] = '\0';
247 utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
248 memset(host[nusers], 0, sizeof(host[nusers]));
249 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
250 host[nusers][UT_HOSTSIZE] = '\0';
251 nusers++;
252 }
253
254 ut.uia_cnt = nusers;
255 fclose(ufp);
256 return (&ut);
257 }
258
259 struct utmpidlearr *
rusersproc_names_2_svc(void * arg,struct svc_req * rqstp)260 rusersproc_names_2_svc(void *arg, struct svc_req *rqstp)
261 {
262 return (do_names_2(0));
263 }
264
265 struct utmpidlearr *
rusersproc_allnames_2_svc(void * arg,struct svc_req * rqstp)266 rusersproc_allnames_2_svc(void *arg, struct svc_req *rqstp)
267 {
268 return (do_names_2(1));
269 }
270
271 static struct utmparr *
do_names_1(int all)272 do_names_1(int all)
273 {
274 static struct utmparr ut;
275 struct utmp usr;
276 int fd, nusers = 0;
277
278 bzero((char *)&ut, sizeof(ut));
279 ut.uta_arr = ru_utmpp;
280 ut.uta_cnt = 0;
281
282 fd = dup(utmp_fd);
283 if (fd == -1) {
284 syslog(LOG_ERR, "%m");
285 return (0);
286 }
287 lseek(fd, (off_t)0, SEEK_SET);
288 ufp = fdopen(fd, "r");
289 if (!ufp) {
290 close(fd);
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 ru_utmpp[nusers] = &ru_utmp[nusers];
300 ru_utmp[nusers].ut_time = usr.ut_time;
301 ru_utmp[nusers].ut_line = line[nusers];
302 memcpy(line[nusers], usr.ut_line, UT_LINESIZE);
303 line[nusers][UT_LINESIZE] = '\0';
304 ru_utmp[nusers].ut_name = name[nusers];
305 memcpy(name[nusers], usr.ut_name, UT_NAMESIZE);
306 name[nusers][UT_NAMESIZE] = '\0';
307 ru_utmp[nusers].ut_host = host[nusers];
308 memcpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
309 host[nusers][UT_HOSTSIZE] = '\0';
310 nusers++;
311 }
312
313 ut.uta_cnt = nusers;
314 fclose(ufp);
315 return (&ut);
316 }
317
318 struct utmparr *
rusersproc_names_1_svc(void * arg,struct svc_req * rqstp)319 rusersproc_names_1_svc(void *arg, struct svc_req *rqstp)
320 {
321 return (do_names_1(0));
322 }
323
324 struct utmparr *
rusersproc_allnames_1_svc(void * arg,struct svc_req * rqstp)325 rusersproc_allnames_1_svc(void *arg, struct svc_req *rqstp)
326 {
327 return (do_names_1(1));
328 }
329
330 void
rusers_service(struct svc_req * rqstp,SVCXPRT * transp)331 rusers_service(struct svc_req *rqstp, SVCXPRT *transp)
332 {
333 char *(*local)(void *, struct svc_req *);
334 xdrproc_t xdr_argument, xdr_result;
335 union {
336 int fill;
337 } argument;
338 char *result;
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 = (xdrproc_t)xdr_void;
347 xdr_result = (xdrproc_t)xdr_int;
348 switch (rqstp->rq_vers) {
349 case RUSERSVERS_3:
350 case RUSERSVERS_IDLE:
351 case RUSERSVERS_ORIG:
352 local = (char *(*)(void *, struct svc_req *))
353 rusers_num_svc;
354 break;
355 default:
356 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
357 goto leave;
358 /*NOTREACHED*/
359 }
360 break;
361
362 case RUSERSPROC_NAMES:
363 xdr_argument = (xdrproc_t)xdr_void;
364 xdr_result = (xdrproc_t)xdr_utmp_array;
365 switch (rqstp->rq_vers) {
366 case RUSERSVERS_3:
367 local = (char *(*)(void *, struct svc_req *))
368 rusersproc_names_3_svc;
369 break;
370
371 case RUSERSVERS_IDLE:
372 xdr_result = (xdrproc_t)xdr_utmpidlearr;
373 local = (char *(*)(void *, struct svc_req *))
374 rusersproc_names_2_svc;
375 break;
376
377 case RUSERSVERS_ORIG:
378 xdr_result = (xdrproc_t)xdr_utmpidlearr;
379 local = (char *(*)(void *, struct svc_req *))
380 rusersproc_names_1_svc;
381 break;
382
383 default:
384 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
385 goto leave;
386 /*NOTREACHED*/
387 }
388 break;
389
390 case RUSERSPROC_ALLNAMES:
391 xdr_argument = (xdrproc_t)xdr_void;
392 xdr_result = (xdrproc_t)xdr_utmp_array;
393 switch (rqstp->rq_vers) {
394 case RUSERSVERS_3:
395 local = (char *(*)(void *, struct svc_req *))
396 rusersproc_allnames_3_svc;
397 break;
398
399 case RUSERSVERS_IDLE:
400 xdr_result = (xdrproc_t)xdr_utmpidlearr;
401 local = (char *(*)(void *, struct svc_req *))
402 rusersproc_allnames_2_svc;
403 break;
404
405 case RUSERSVERS_ORIG:
406 xdr_result = (xdrproc_t)xdr_utmpidlearr;
407 local = (char *(*)(void *, struct svc_req *))
408 rusersproc_allnames_1_svc;
409 break;
410
411 default:
412 svcerr_progvers(transp, RUSERSVERS_IDLE, RUSERSVERS_3);
413 goto leave;
414 /*NOTREACHED*/
415 }
416 break;
417
418 default:
419 svcerr_noproc(transp);
420 goto leave;
421 }
422 bzero((char *)&argument, sizeof(argument));
423 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
424 svcerr_decode(transp);
425 goto leave;
426 }
427 result = (*local)(&argument, rqstp);
428 if (result != NULL && !svc_sendreply(transp, xdr_result, result))
429 svcerr_systemerr(transp);
430
431 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
432 syslog(LOG_ERR, "unable to free arguments");
433 exit(1);
434 }
435 leave:
436 if (from_inetd)
437 exit(0);
438 }
439