The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radwho.c
Go to the documentation of this file.
1/*@-skipposixheaders@*/
2/*
3 * radwho.c Show who is logged in on the terminal servers.
4 *
5 * Version: $Id: d52e7bf28a84139b6a990018cd2c45aedef358e3 $
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * @copyright 2000,2006 The FreeRADIUS server project
22 * @copyright 2000 Alan DeKok (aland@freeradius.org)
23 */
24
25RCSID("$Id: d52e7bf28a84139b6a990018cd2c45aedef358e3 $")
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/cf_parse.h>
29#include <freeradius-devel/server/radutmp.h>
30#include <freeradius-devel/server/sysutmp.h>
31
32#include <freeradius-devel/util/conf.h>
33
34#include <pwd.h>
35#include <sys/stat.h>
36#include <ctype.h>
37
38/*
39 * Header above output and format.
40 */
41static char const *hdr1 =
42"Login Name What TTY When From Location";
43
44static char const *hdr2 =
45"Login Port What When From Location";
46
47static char const *eol = "\n";
48static int showname = -1;
49static int showptype = 0;
50static int showcid = 0;
51static char const *progname = "radwho";
52
53static char const *radutmp_file = NULL;
54
55static struct radutmp_config_t {
56 char const *radutmp_fn;
58
63
64/*
65 * Get fullname of a user.
66 */
67static char *fullname(char *username)
68{
69#ifdef HAVE_PWD_H
70 struct passwd *pwd;
71 char *s;
72
73 if ((pwd = getpwnam(username)) != NULL) {
74 if ((s = strchr(pwd->pw_gecos, ',')) != NULL) *s = 0;
75 return pwd->pw_gecos;
76 }
77#endif
78
79 return username;
80}
81
82/*
83 * Return protocol type.
84 */
85static char const *proto(int id, int porttype)
86{
87 static char buf[8];
88
89 if (showptype) {
90 if (!strchr("ASITX", porttype))
91 porttype = ' ';
92 if (id == 'S')
93 snprintf(buf, sizeof(buf), "SLP %c", porttype);
94 else if (id == 'P')
95 snprintf(buf, sizeof(buf), "PPP %c", porttype);
96 else
97 snprintf(buf, sizeof(buf), "shl %c", porttype);
98 return buf;
99 }
100 if (id == 'S') return "SLIP";
101 if (id == 'P') return "PPP";
102 return "shell";
103}
104
105/*
106 * Return a time in the form day hh:mm
107 */
108static char *dotime(time_t t)
109{
110 /*
111 * man 3 ctime
112 * The caller must provide the output buffer buf
113 * (which must be at least 26 characters long)
114 */
115 static char buff[26];
116 char *s = ctime_r(&t, buff);
117
118 if (showname) {
119 strlcpy(s + 4, s + 11, 6);
120 s[9] = 0;
121 } else {
122 strlcpy(s + 4, s + 8, 9);
123 s[12] = 0;
124 }
125
126 return s;
127}
128
129
130/*
131 * Print address of NAS.
132 */
133static char const *hostname(char *buf, size_t buflen, uint32_t ipaddr)
134{
135 /*
136 * WTF is this code for?
137 */
138 if (ipaddr == 0 || ipaddr == (uint32_t)-1 || ipaddr == (uint32_t)-2)
139 return "";
140
141 return inet_ntop(AF_INET, &ipaddr, buf, buflen);
142
143}
144
145
146/*
147 * Print usage message and exit.
148 */
149static NEVER_RETURNS void usage(int status)
150{
151 FILE *output = status?stderr:stdout;
152
153 fprintf(output, "Usage: radwho [-d raddb] [-cfihnprRsSZ] [-N nas] [-P nas_port] [-u user] [-U user]\n");
154 fprintf(output, " -c Show caller ID, if available.\n");
155 fprintf(output, " -d Set the raddb directory (default is %s).\n", RADIUS_DIR);
156 fprintf(output, " -F <file> Use radutmp <file>.\n");
157 fprintf(output, " -i Show session ID.\n");
158 fprintf(output, " -n No full name.\n");
159 fprintf(output, " -N <nas-ip-address> Show entries matching the given NAS IP address.\n");
160 fprintf(output, " -p Show port type.\n");
161 fprintf(output, " -P <port> Show entries matching the given nas port.\n");
162 fprintf(output, " -r Print output as raw comma-delimited data.\n");
163 fprintf(output, " -R Print output as RADIUS attributes and values.\n");
164 fprintf(output, " includes ALL information from the radutmp record.\n");
165 fprintf(output, " -s Show full name.\n");
166 fprintf(output, " -S Hide shell users from radius.\n");
167 fprintf(output, " -u <user> Show entries matching the given user.\n");
168 fprintf(output, " -U <user> Like -u, but case-sensitive.\n");
169 fprintf(output, " -Z Include accounting stop information in radius output. Requires -R.\n");
170 fr_exit_now(status);
171}
172
173/**
174 *
175 * @hidecallgraph
176 */
177int main(int argc, char **argv)
178{
179 CONF_SECTION *maincs, *cs;
180 FILE *fp;
181 struct radutmp rt;
182 char othername[256];
183 char nasname[1024];
184 char session_id[sizeof(rt.session_id)+1];
185 int hideshell = 0;
186 int showsid = 0;
187 int rawoutput = 0;
188 int radiusoutput = 0; /* Radius attributes */
189 char const *portind;
190 int c;
191 unsigned int portno;
192 char buffer[2048];
193 char const *user = NULL;
194 int user_cmp = 0;
195 time_t now = 0;
196 uint32_t nas_port = ~0;
197 uint32_t nas_ip_address = INADDR_NONE;
198 int zap = 0;
199 fr_dict_t *dict = NULL;
200 TALLOC_CTX *autofree;
201
202 char const *p;
204 int ret = EXIT_SUCCESS;
205
206 /*
207 * Must be called first, so the handler is called last
208 */
210
212
213#ifndef NDEBUG
214 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
215 fr_perror("%s", main_config->name);
216 fr_exit_now(EXIT_FAILURE);
217 }
218#endif
219
220 talloc_set_log_stderr();
221
222 /*
223 * Allocate the main config structure.
224 * It's allocating so we can hang talloced buffers off it.
225 */
227 if (!config) {
228 fr_perror("Failed allocating main config");
229 fr_exit_now(EXIT_FAILURE);
230 }
231
232 p = strrchr(argv[0], FR_DIR_SEP);
233 if (!p) {
234 main_config_name_set_default(config, argv[0], false);
235 } else {
237 }
238
239 while((c = getopt(argc, argv, "d:D:fF:hnN:sSipP:crRu:U:Z")) != -1) switch (c) {
240 case 'd':
242 break;
243 case 'D':
245 break;
246 case 'F':
247 radutmp_file = optarg;
248 break;
249 case 'h':
250 usage(EXIT_SUCCESS); /* never returns */
251 case 'S':
252 hideshell = 1;
253 break;
254 case 'n':
255 showname = 0;
256 break;
257 case 'N':
258 if (inet_pton(AF_INET, optarg, &nas_ip_address) <= 0) {
259 usage(EXIT_FAILURE);
260 }
261 break;
262 case 's':
263 showname = 1;
264 break;
265 case 'i':
266 showsid = 1;
267 break;
268 case 'p':
269 showptype = 1;
270 break;
271 case 'P':
272 nas_port = atoi(optarg);
273 break;
274 case 'c':
275 showcid = 1;
276 showname = 1;
277 break;
278 case 'r':
279 rawoutput = 1;
280 break;
281 case 'R':
282 radiusoutput = 1;
283 now = time(NULL);
284 break;
285 case 'u':
286 user = optarg;
287 user_cmp = 0;
288 break;
289 case 'U':
290 user = optarg;
291 user_cmp = 1;
292 break;
293 case 'Z':
294 zap = 1;
295 break;
296
297 default:
298 usage(1); /* never returns */
299 }
300
301 /*
302 * Mismatch between the binary and the libraries it depends on
303 */
305 fr_perror("%s", main_config->name);
306 return 1;
307 }
308
309 if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
310 fr_perror("%s", main_config->name);
311 fr_exit_now(EXIT_FAILURE);
312 }
313
314
316 fr_perror("%s", config->name);
317 fr_exit_now(EXIT_FAILURE);
318 }
319
320 if (fr_dict_read(dict, config->raddb_dir, FR_DICTIONARY_FILE) == -1) {
321 PERROR("Failed to initialize the dictionaries");
322 return 1;
323 }
324 fr_strerror_clear(); /* Clear the error buffer */
325
326 /*
327 * Be safe.
328 */
329 if (zap && !radiusoutput) zap = 0;
330
331 /*
332 * zap EVERYONE, but only on this nas
333 */
334 if (zap && !user && (~nas_port == 0)) {
335 /*
336 * We need to know which NAS to zap users in.
337 */
338 if (nas_ip_address == INADDR_NONE) usage(1);
339
340 printf("Acct-Status-Type = Accounting-Off\n");
341 printf("NAS-IP-Address = %s\n",
342 hostname(buffer, sizeof(buffer), nas_ip_address));
343 printf("Acct-Delay-Time = 0\n");
344 fr_exit_now(0); /* don't bother printing anything else */
345 }
346
347 if (radutmp_file) goto have_radutmp;
348
349 /* Read radiusd.conf */
350 maincs = cf_section_alloc(NULL, NULL, "main", NULL);
351 if (!maincs) fr_exit_now(EXIT_FAILURE);
352
353 snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", config->raddb_dir);
354 if ((cf_file_read(maincs, buffer) < 0) || (cf_section_pass2(maincs) < 0)) {
355 fr_perror("%s: Error reading or parsing radiusd.conf\n", argv[0]);
356 talloc_free(maincs);
357 fr_exit_now(EXIT_FAILURE);
358 }
359
360 cs = cf_section_find(maincs, "modules", NULL);
361 if (!cs) {
362 fr_perror("%s: No modules section found in radiusd.conf\n", argv[0]);
363 fr_exit_now(EXIT_FAILURE);
364 }
365 /* Read the radutmp section of radiusd.conf */
366 cs = cf_section_find(cs, "radutmp", NULL);
367 if (!cs) {
368 fr_perror("%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]);
369 fr_exit_now(EXIT_FAILURE);
370 }
371
372 if (cf_section_rules_push(cs, module_config) < 0) fr_exit_now(EXIT_FAILURE);
373 cf_section_parse(maincs, NULL, cs);
374
375 /* Assign the correct path for the radutmp file */
377
378 have_radutmp:
379 if (showname < 0) showname = 1;
380
381 /*
382 * Show the users logged in on the terminal server(s).
383 */
384 if ((fp = fopen(radutmp_file, "r")) == NULL) {
385 fr_perror("%s: Error reading %s: %s\n",
387 return 0;
388 }
389
390 /*
391 * Don't print the headers if raw or RADIUS
392 */
393 if (!rawoutput && !radiusoutput) {
394 fputs(showname ? hdr1 : hdr2, stdout);
395 fputs(eol, stdout);
396 }
397
398 /*
399 * Read the file, printing out active entries.
400 */
401 while (fread(&rt, sizeof(rt), 1, fp) == 1) {
402 char name[sizeof(rt.login) + 1];
403
404 if (rt.type != P_LOGIN) continue; /* hide logout sessions */
405
406 /*
407 * We don't show shell users if we are
408 * fingerd, as we have done that above.
409 */
410 if (hideshell && !strchr("PCS", rt.proto))
411 continue;
412
413 /*
414 * Print out sessions only for the given user.
415 */
416 if (user) { /* only for a particular user */
417 if (((user_cmp == 0) &&
418 (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
419 ((user_cmp == 1) &&
420 (strncmp(rt.login, user, strlen(user)) != 0))) {
421 continue;
422 }
423 }
424
425 /*
426 * Print out only for the given NAS port.
427 */
428 if (~nas_port != 0) {
429 if (rt.nas_port != nas_port) continue;
430 }
431
432 /*
433 * Print out only for the given NAS IP address
434 */
435 if (nas_ip_address != INADDR_NONE) {
436 if (rt.nas_address != nas_ip_address) continue;
437 }
438
439 memcpy(session_id, rt.session_id, sizeof(rt.session_id));
440 session_id[sizeof(rt.session_id)] = 0;
441
442 if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
443 portind = ">";
444 portno = (showname ? 999 : 99999);
445 } else {
446 portind = "S";
447 portno = rt.nas_port;
448 }
449
450 /*
451 * Print output as RADIUS attributes
452 */
453 if (radiusoutput) {
454 memcpy(nasname, rt.login, sizeof(rt.login));
455 nasname[sizeof(rt.login)] = '\0';
456
457 fr_snprint(buffer, sizeof(buffer), nasname, -1, '"');
458 printf("User-Name = \"%s\"\n", buffer);
459
460 fr_snprint(buffer, sizeof(buffer), session_id, -1, '"');
461 printf("Acct-Session-Id = \"%s\"\n", buffer);
462
463 if (zap) printf("Acct-Status-Type = Stop\n");
464
465 printf("NAS-IP-Address = %s\n",
466 hostname(buffer, sizeof(buffer),
467 rt.nas_address));
468 printf("NAS-Port = %u\n", rt.nas_port);
469
470 switch (rt.proto) {
471 case 'S':
472 printf("Service-Type = Framed-User\n");
473 printf("Framed-Protocol = SLIP\n");
474 break;
475
476 case 'P':
477 printf("Service-Type = Framed-User\n");
478 printf("Framed-Protocol = PPP\n");
479 break;
480
481 default:
482 printf("Service-type = Login-User\n");
483 break;
484 }
485 if (rt.framed_address != INADDR_NONE) {
486 printf("Framed-IP-Address = %s\n",
487 hostname(buffer, sizeof(buffer),
488 rt.framed_address));
489 }
490
491 /*
492 * Some sanity checks on the time
493 */
494 if ((rt.time <= now) &&
495 (now - rt.time) <= (86400 * 365)) {
496 printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time));
497 }
498
499 if (rt.caller_id[0] != '\0') {
500 memcpy(nasname, rt.caller_id,
501 sizeof(rt.caller_id));
502 nasname[sizeof(rt.caller_id)] = '\0';
503
504 fr_snprint(buffer, sizeof(buffer), nasname, -1, '"');
505 printf("Calling-Station-Id = \"%s\"\n", buffer);
506 }
507
508 printf("\n"); /* separate entries with a blank line */
509 continue;
510 }
511
512 /*
513 * Show the fill name, or not.
514 */
515 memcpy(name, rt.login, sizeof(rt.login));
516 name[sizeof(rt.login)] = '\0';
517
518 if (showname) {
519 if (rawoutput == 0) {
520 printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s",
521 name,
522 showcid ? rt.caller_id :
523 (showsid? session_id : fullname(rt.login)),
524 proto(rt.proto, rt.porttype),
525 portind, portno,
526 dotime(rt.time),
527 hostname(nasname, sizeof(nasname), rt.nas_address),
528 hostname(othername, sizeof(othername), rt.framed_address), eol);
529 } else {
530 printf("%s,%s,%s,%s%u,%s,%s,%s%s",
531 name,
532 showcid ? rt.caller_id :
533 (showsid? session_id : fullname(rt.login)),
534 proto(rt.proto, rt.porttype),
535 portind, portno,
536 dotime(rt.time),
537 hostname(nasname, sizeof(nasname), rt.nas_address),
538 hostname(othername, sizeof(othername), rt.framed_address), eol);
539 }
540 } else {
541 if (rawoutput == 0) {
542 printf("%-10.10s %s%-5u %-6.6s %-13.13s %-15.15s %-.28s%s",
543 name,
544 portind, portno,
545 proto(rt.proto, rt.porttype),
546 dotime(rt.time),
547 hostname(nasname, sizeof(nasname), rt.nas_address),
548 hostname(othername, sizeof(othername), rt.framed_address),
549 eol);
550 } else {
551 printf("%s,%s%u,%s,%s,%s,%s%s",
552 name,
553 portind, portno,
554 proto(rt.proto, rt.porttype),
555 dotime(rt.time),
556 hostname(nasname, sizeof(nasname), rt.nas_address),
557 hostname(othername, sizeof(othername), rt.framed_address),
558 eol);
559 }
560 }
561 }
562 fclose(fp);
563
565
566 fr_dict_free(&dict, __FILE__);
567
568 /*
569 * Ensure our atexit handlers run before any other
570 * atexit handlers registered by third party libraries.
571 */
573
574 return ret;
575}
static int const char char buffer[256]
Definition acutest.h:576
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:160
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:286
#define RCSID(id)
Definition build.h:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
int cf_file_read(CONF_SECTION *cs, char const *filename)
Definition cf_file.c:3423
int cf_section_pass2(CONF_SECTION *cs)
Definition cf_file.c:755
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1124
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:674
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:323
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition cf_parse.h:424
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1028
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:140
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1242
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:114
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Definition dict_util.c:4392
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name, char const *dependent)
(Re-)Initialize the special internal dictionary
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4024
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
#define PERROR(_fmt,...)
Definition log.h:228
talloc_free(reap)
int main_config_free(main_config_t **config)
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
void main_config_raddb_dir_set(main_config_t *config, char const *name)
Set the global radius config directory.
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
main_config_t const * main_config
Main server configuration.
Definition main_config.c:69
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
char const * name
Name of the daemon, usually 'radiusd'.
Definition main_config.h:52
Main server configuration.
Definition main_config.h:51
@ FR_TYPE_STRING
String of printable characters.
unsigned int uint32_t
int inet_pton(int af, char const *src, void *dst)
Definition missing.c:427
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:443
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:36
char * ctime_r(time_t const *l_clock, char *l_buf)
Definition missing.c:182
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition print.c:227
static const conf_parser_t config[]
Definition base.c:183
static TALLOC_CTX * autofree
unsigned int framed_address
Definition radutmp.h:60
char porttype
Definition radutmp.h:65
time_t time
Definition radutmp.h:62
char login[32]
Definition radutmp.h:54
int type
Definition radutmp.h:64
unsigned int nas_address
Definition radutmp.h:59
char session_id[8]
Definition radutmp.h:57
char caller_id[16]
Definition radutmp.h:67
#define P_LOGIN
Definition radutmp.h:51
unsigned int nas_port
Definition radutmp.h:56
int proto
Definition radutmp.h:61
static char const * radutmp_file
Definition radwho.c:53
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition radwho.c:133
static char * fullname(char *username)
Definition radwho.c:67
static char const * hdr2
Definition radwho.c:44
static char const * eol
Definition radwho.c:47
int main(int argc, char **argv)
Definition radwho.c:177
static struct radutmp_config_t radutmpconfig
static char const * proto(int id, int porttype)
Definition radwho.c:85
static int showcid
Definition radwho.c:50
static int showname
Definition radwho.c:48
static char const * progname
Definition radwho.c:51
static char * dotime(time_t t)
Definition radwho.c:108
static int showptype
Definition radwho.c:49
static char const * hdr1
Definition radwho.c:41
char const * radutmp_fn
Definition radwho.c:56
static const conf_parser_t module_config[]
Definition radwho.c:59
static char const * name
username
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:51
#define FR_DICTIONARY_FILE
Definition conf.h:7
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:8
#define RADIUS_DIR
Definition conf.h:3
#define RADUTMP
Definition conf.h:13
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81