1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28 * University Copyright- Copyright (c) 1982, 1986, 1988
29 * The Regents of the University of California
30 * All Rights Reserved
31 *
32 * University Acknowledgment- Portions of this document are derived from
33 * software developed by the University of California, Berkeley, and its
34 * contributors.
35 */
36
37 #pragma ident "%Z%%M% %I% %E% SMI"
38
39 #include <stdio.h>
40 #include <signal.h>
41 #include <sys/stat.h>
42 #include <rpc/rpc.h>
43 #include <memory.h>
44 #include <netconfig.h>
45 #include <stropts.h>
46 #include <syslog.h>
47 #include <utmpx.h>
48 #include <rpcsvc/rusers.h>
49 #include <sys/resource.h>
50 #include <limits.h>
51
52 #ifdef DEBUG
53 #define RPC_SVC_FG
54 #endif
55
56 #define _RPCSVC_CLOSEDOWN 120
57
58 static void rusers_service();
59 static void closedown();
60 static void msgout();
61 static unsigned min();
62
63 static int _rpcpmstart; /* Started by a port monitor ? */
64 static int _rpcfdtype; /* Whether Stream or Datagram ? */
65 static int _rpcsvcdirty; /* Still serving ? */
66 static int _rpcsvcrecent; /* set when we serivce a request; tested */
67 /* and cleared by closedown() routine */
68
69 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
70
71 #define ALL_ENTRIES 1
72 #define REAL_USERS 0
73
74 utmp_array utmp_array_res;
75 int used_array_len = 0;
76 struct utmpidlearr utmpidlearr;
77
78 static void free_ua_entry(rusers_utmp *uap);
79 static int findidle(char *name, int ln, time_t now);
80 static void usys5to_ru(struct utmpx *s5, struct ru_utmp *bss);
81
82 int
main(int argc,char * argv[])83 main(int argc, char *argv[])
84 {
85 pid_t pid;
86 int i;
87 int connmaxrec = RPC_MAXDATASIZE;
88
89 /*
90 * Set non-blocking mode and maximum record size for
91 * connection oriented RPC transports.
92 */
93 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
94 msgout("unable to set maximum RPC record size");
95 }
96
97 /*
98 * If stdin looks like a TLI endpoint, we assume
99 * that we were started by a port monitor. If
100 * t_getstate fails with TBADF, this is not a
101 * TLI endpoint.
102 */
103 if (t_getstate(0) != -1 || t_errno != TBADF) {
104 char *netid;
105 struct netconfig *nconf = NULL;
106 SVCXPRT *transp;
107 int pmclose;
108 extern char *getenv();
109
110 _rpcpmstart = 1;
111 openlog("rusers", LOG_PID, LOG_DAEMON);
112 if ((netid = getenv("NLSPROVIDER")) == NULL) {
113 #ifdef DEBUG
114 msgout("cannot get transport name");
115 #endif
116 } else if ((nconf = getnetconfigent(netid)) == NULL) {
117 #ifdef DEBUG
118 msgout("cannot get transport info");
119 #endif
120 }
121 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
122 msgout("cannot create server handle");
123 exit(1);
124 }
125 if (nconf)
126 freenetconfigent(nconf);
127 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service,
128 0)) {
129 msgout("unable to register (RUSERSPROG, RUSERSVERS_3).");
130 exit(1);
131 }
132 if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE,
133 rusers_service, 0)) {
134 msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE).");
135 exit(1);
136 }
137 (void) signal(SIGALRM, closedown);
138 (void) alarm(_RPCSVC_CLOSEDOWN);
139 svc_run();
140 msgout("svc_run returned");
141 exit(1);
142 /* NOTREACHED */
143 }
144 #ifndef RPC_SVC_FG
145 pid = fork();
146 if (pid < 0) {
147 perror("rpc.rusersd: cannot fork");
148 exit(1);
149 }
150 if (pid)
151 exit(0);
152 for (i = 0; i < 20; i++)
153 (void) close(i);
154 setsid();
155 openlog("rusers", LOG_PID, LOG_DAEMON);
156 #endif
157 if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")) {
158 msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath");
159 exit(1);
160 }
161 if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE,
162 "netpath")) {
163 msgout(
164 "unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath");
165 exit(1);
166 }
167
168 svc_run();
169 msgout("svc_run returned");
170 return (1);
171 }
172
173
174 /*
175 * This routine gets the user information.
176 * "all" specifies whether all listings should be counted, or only those of
177 * type "USER_PROCESS".
178 * "version" is either RUSERSVERS_IDLE or RUSERSVERS_3. If anything else,
179 * just a count is returned.
180 * "limit" specifies the maximum number of entries to be processed.
181 *
182 * For both versions, the results are placed into an external variable.
183 * For RUSERSVERS_IDLE, this routine mallocs entries in a vector as it
184 * processed each utmpx entry. These malloc'd entries must be freed after the
185 * results are returned.
186 * For RUSERSVERS_3, this routine uses array entries that are malloc'd prior
187 * to this routine being called. "limit" is the number of elements available.
188 */
189 int
getutmpx_3(all,version,limit)190 getutmpx_3(all, version, limit)
191 int all; /* give all listings? */
192 int version; /* version 2 or 3 */
193 int limit; /* limits users returned, 0 means no limit */
194 {
195 struct utmpx *utent;
196 struct utmpidle **q = utmpidlearr.uia_arr;
197 int minidle;
198 int cnt = 0;
199 time_t now;
200 extern char *s_malodup();
201
202 time(&now); /* only one call to time() for this rpc call */
203 setutxent(); /* reset the utmpx file */
204 while ((utent = getutxent()) != NULL && (limit == 0 || cnt < limit)) {
205 if (utent->ut_line[0] == '\0' || utent->ut_user[0] == '\0')
206 continue;
207 /*
208 * List only user processes.
209 * XXX modified to exclude cmdtool style window entries.
210 */
211 if ((all == REAL_USERS) && ((utent->ut_type != USER_PROCESS) ||
212 nonuserx(*utent)))
213 continue;
214
215 if (version == RUSERSVERS_IDLE) {
216 /*
217 * need to free this; done after svc_sendreply.
218 */
219 *q = (struct utmpidle *)
220 malloc(sizeof (struct utmpidle));
221 (*q)->ui_idle = findidle(utent->ut_line,
222 sizeof (utent->ut_line), now);
223 if (strncmp(utent->ut_line, "console",
224 strlen("console")) == 0) {
225 (*q)->ui_idle = min((*q)->ui_idle,
226 console_idle(now));
227 }
228 usys5to_ru(utent, &((*q)->ui_utmp));
229 #ifdef DEBUG
230 printf("%-*s %-*s %s; idle %d",
231 sizeof (utent->ut_line),
232 utent->ut_line,
233 sizeof (utent->ut_name),
234 utent->ut_name,
235 ctime(&utent->ut_xtime),
236 (*q)->ui_idle);
237 #endif
238 q++;
239 } else if (version == RUSERSVERS_3) {
240 #define uav utmp_array_res.utmp_array_val
241
242 uav[cnt].ut_host =
243 s_malodup(utent->ut_host, utent->ut_syslen);
244 uav[cnt].ut_user = s_malodup(utent->ut_user,
245 sizeof (utent->ut_user));
246 uav[cnt].ut_line = s_malodup(utent->ut_line,
247 sizeof (utent->ut_line));
248 uav[cnt].ut_type = utent->ut_type;
249 uav[cnt].ut_time = utent->ut_xtime;
250 uav[cnt].ut_idle = findidle(utent->ut_line,
251 sizeof (utent->ut_line), now);
252 if (strncmp(utent->ut_line, "console",
253 strlen("console")) == 0) {
254 uav[cnt].ut_idle =
255 min(uav[cnt].ut_idle,
256 console_idle(now));
257 }
258 #ifdef DEBUG
259 printf("user: %-10s line: %-10s %s; idle %d (%s)\n",
260 uav[cnt].ut_line, uav[cnt].ut_user,
261 ctime((time_t *)&uav[cnt].ut_time),
262 uav[cnt].ut_idle, uav[cnt].ut_host);
263 #endif
264 #undef uav
265 }
266 cnt++;
267 }
268 return (cnt);
269 }
270
271 /*
272 * "string" is a character array with maximum size "size". Return a
273 * malloc'd string that's a duplicate of the string.
274 */
275 char *
s_malodup(string,size)276 s_malodup(string, size)
277 char *string;
278 int size;
279 {
280 char *tmp;
281
282 tmp = (char *)malloc(size+1);
283 if (tmp == NULL) {
284 msgout("rpc.rusersd: malloc failed (2)");
285 return (NULL);
286 }
287 strncpy(tmp, string, size);
288 tmp[size] = '\0';
289 return (tmp);
290 }
291
292
293 int
console_idle(now)294 console_idle(now)
295 time_t now;
296 {
297 /*
298 * On the console, the user may be running a window system; if so,
299 * their activity will show up in the last-access times of
300 * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle
301 * times on those two devices and "/dev/console" and treat that as
302 * the idle time.
303 */
304 return (min((unsigned)findidle("kbd", strlen("kbd"), now),
305 (unsigned)findidle("mouse", strlen("mouse"), now)));
306 }
307
308 static void
rusers_service(rqstp,transp)309 rusers_service(rqstp, transp)
310 register struct svc_req *rqstp;
311 register SVCXPRT *transp;
312 {
313 int i;
314 int cnt;
315 char *replyerr = "rpc.rusersd: error replying to request";
316
317 _rpcsvcrecent = _rpcsvcdirty = 1;
318 switch (rqstp->rq_proc) {
319 case 0:
320 if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
321 msgout(replyerr);
322 }
323 break;
324 case RUSERSPROC_NUM:
325 cnt = getutmpx_3(REAL_USERS, 0, 0);
326 if (!svc_sendreply(transp, xdr_u_long, (caddr_t)&cnt))
327 msgout(replyerr);
328 break;
329 case RUSERSPROC_NAMES:
330 case RUSERSPROC_ALLNAMES:
331 if (rqstp->rq_vers == RUSERSVERS_IDLE) {
332 utmpidlearr.uia_arr = (struct utmpidle **)
333 malloc(MAXUSERS*sizeof (struct utmpidle *));
334 utmpidlearr.uia_cnt = getutmpx_3(rqstp->rq_proc ==
335 RUSERSPROC_ALLNAMES,
336 RUSERSVERS_IDLE, MAXUSERS);
337 if (!svc_sendreply(transp, xdr_utmpidlearr,
338 (caddr_t)&utmpidlearr))
339 msgout(replyerr);
340 for (i = 0; i < utmpidlearr.uia_cnt; i++) {
341 free(utmpidlearr.uia_arr[i]);
342 }
343 free(utmpidlearr.uia_arr);
344 } else if (rqstp->rq_vers == RUSERSVERS_3) {
345 int entries, alloc_array_len;
346
347 /*
348 * Always free strings from previous results array
349 */
350 for (i = 0; i < used_array_len; i++) {
351 free_ua_entry(&utmp_array_res.utmp_array_val[i]);
352 }
353 entries = (rqstp->rq_proc == RUSERSPROC_ALLNAMES);
354 cnt = getutmpx_3(entries, 0, 0); /* get cnt */
355 if (cnt > utmp_array_res.utmp_array_len) {
356 free(utmp_array_res.utmp_array_val);
357 utmp_array_res.utmp_array_len = 0;
358 utmp_array_res.utmp_array_val = (rusers_utmp *)
359 malloc(cnt * sizeof (rusers_utmp));
360 if (utmp_array_res.utmp_array_val == NULL) {
361 msgout("rpc.rusersd: malloc failed (1)");
362 break;
363 }
364 alloc_array_len = cnt;
365 } else {
366 alloc_array_len = utmp_array_res.utmp_array_len;
367 }
368 cnt = getutmpx_3(entries, RUSERSVERS_3, cnt);
369 utmp_array_res.utmp_array_len = used_array_len = cnt;
370 if (!svc_sendreply(transp, xdr_utmp_array,
371 (caddr_t)&utmp_array_res))
372 msgout(replyerr);
373 utmp_array_res.utmp_array_len = alloc_array_len;
374 }
375 break;
376 default:
377 svcerr_noproc(transp);
378 break;
379 }
380 _rpcsvcdirty = 0;
381
382 }
383
384 static void
free_ua_entry(rusers_utmp * uap)385 free_ua_entry(rusers_utmp *uap)
386 {
387 if (uap == NULL)
388 return;
389 if (uap->ut_user)
390 free(uap->ut_user);
391 if (uap->ut_line)
392 free(uap->ut_line);
393 if (uap->ut_host)
394 free(uap->ut_host);
395 }
396
397
398
399 /* find & return number of minutes current tty has been idle */
400 static int
findidle(char * name,int ln,time_t now)401 findidle(char *name, int ln, time_t now)
402 {
403 struct stat stbuf;
404 long lastaction, diff;
405 char ttyname[32];
406
407 strcpy(ttyname, "/dev/");
408 strncat(ttyname, name, ln);
409 if (stat(ttyname, &stbuf) < 0)
410 return (INT_MAX);
411 lastaction = stbuf.st_atime;
412 diff = now - lastaction;
413 diff = DIV60(diff);
414 if (diff < 0) diff = 0;
415 return (diff);
416 }
417
418 static void
usys5to_ru(struct utmpx * s5,struct ru_utmp * bss)419 usys5to_ru(struct utmpx *s5, struct ru_utmp *bss)
420 {
421 int i;
422
423 #ifdef DEBUG
424 printf("sizeof (bss->ut_host) == %d\n", sizeof (bss->ut_host));
425 #endif
426 strncpy(bss->ut_name, s5->ut_name, sizeof (bss->ut_name));
427 strncpy(bss->ut_line, s5->ut_line, sizeof (bss->ut_line));
428 strncpy(bss->ut_host, s5->ut_host, sizeof (bss->ut_host));
429 bss->ut_time = s5->ut_xtime;
430 }
431
432 static void
msgout(msg)433 msgout(msg)
434 char *msg;
435 {
436 #ifdef RPC_SVC_FG
437 if (_rpcpmstart)
438 syslog(LOG_ERR, msg);
439 else
440 (void) fprintf(stderr, "%s\n", msg);
441 #else
442 syslog(LOG_ERR, msg);
443 #endif
444 }
445
446 static void
closedown(sig)447 closedown(sig)
448 int sig;
449 {
450 if (_rpcsvcrecent) {
451 _rpcsvcrecent = 0;
452 } else {
453 if (_rpcsvcdirty == 0) {
454 int i, openfd;
455 struct t_info tinfo;
456
457 if (t_getinfo(0, &tinfo) || (tinfo.servtype == T_CLTS))
458 exit(0);
459
460 for (i = 0, openfd = 0;
461 i < svc_max_pollfd && openfd < 2;
462 i++) {
463 if (svc_pollfd[i].fd >= 0)
464 openfd++;
465 }
466
467 if (openfd <= 1)
468 exit(0);
469 }
470 }
471 (void) signal(SIGALRM, closedown);
472 (void) alarm(_RPCSVC_CLOSEDOWN);
473 }
474
475 unsigned
min(a,b)476 min(a, b)
477 unsigned a;
478 unsigned b;
479 {
480 if (a < b)
481 return (a);
482 else
483 return (b);
484 }
485