1 |
|
|
/* $OpenBSD: rusers_proc.c,v 1.26 2017/04/27 21:28:00 millert 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, int 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, 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(&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(&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, 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(&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(&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, 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(&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(&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, 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(&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 |
|
|
} |