Add version consistency checks between applications, libfreeradius-radius, libfreerad...
[freeradius.git] / src / main / radwho.c
1 /*@-skipposixheaders@*/
2 /*
3  * radwho.c     Show who is logged in on the terminal servers.
4  *
5  * Version:     $Id$
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@ox.org>
23  */
24
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/sysutmp.h>
29 #include <freeradius-devel/radutmp.h>
30
31 #ifdef HAVE_PWD_H
32 #include <pwd.h>
33 #endif
34
35 #include <sys/stat.h>
36
37 #include <ctype.h>
38
39 /*
40  *      Header above output and format.
41  */
42 static char const *hdr1 =
43 "Login      Name              What  TTY  When      From     Location";
44
45 static char const *hdr2 =
46 "Login      Port    What      When        From      Location";
47
48 static char const *eol = "\n";
49 static int showname = -1;
50 static int showptype = 0;
51 static int showcid = 0;
52 log_debug_t debug_flag = 0;
53 char const *progname = "radwho";
54 char const *radlog_dir = NULL;
55 char const *radutmp_file = NULL;
56 bool check_config = false;
57
58 char const *raddb_dir = NULL;
59 char const *radacct_dir = NULL;
60 char const *radlib_dir = NULL;
61 uint32_t myip = INADDR_ANY;
62 bool log_stripped_names;
63
64 /*
65  *      Global, for log.c to use.
66  */
67 struct main_config_t mainconfig;
68
69 #include <sys/wait.h>
70 pid_t rad_fork(void)
71 {
72         return fork();
73 }
74
75 #ifdef HAVE_PTHREAD_H
76 pid_t rad_waitpid(pid_t pid, int *status)
77 {
78         return waitpid(pid, status, 0);
79 }
80 #endif
81
82 struct radutmp_config_t {
83   char *radutmp_fn;
84 } radutmpconfig;
85
86 static const CONF_PARSER module_config[] = {
87   { "filename", PW_TYPE_FILE_INPUT, 0, &radutmpconfig.radutmp_fn,  RADUTMP },
88   { NULL, -1, 0, NULL, NULL }
89 };
90
91 /*
92  *      Get fullname of a user.
93  */
94 static char *fullname(char *username)
95 {
96 #ifdef HAVE_PWD_Hx
97         struct passwd *pwd;
98         char *s;
99
100         if ((pwd = getpwnam(username)) != NULL) {
101                 if ((s = strchr(pwd->pw_gecos, ',')) != NULL) *s = 0;
102                 return pwd->pw_gecos;
103         }
104 #endif
105
106         return username;
107 }
108
109 /*
110  *      Return protocol type.
111  */
112 static char const *proto(int id, int porttype)
113 {
114         static char buf[8];
115
116         if (showptype) {
117                 if (!strchr("ASITX", porttype))
118                         porttype = ' ';
119                 if (id == 'S')
120                         snprintf(buf, sizeof(buf), "SLP %c", porttype);
121                 else if (id == 'P')
122                         snprintf(buf, sizeof(buf), "PPP %c", porttype);
123                 else
124                         snprintf(buf, sizeof(buf), "shl %c", porttype);
125                 return buf;
126         }
127         if (id == 'S') return "SLIP";
128         if (id == 'P') return "PPP";
129         return "shell";
130 }
131
132 /*
133  *      Return a time in the form day hh:mm
134  */
135 static char *dotime(time_t t)
136 {
137         char *s = ctime(&t);
138
139         if (showname) {
140                 strlcpy(s + 4, s + 11, 6);
141                 s[9] = 0;
142         } else {
143                 strlcpy(s + 4, s + 8, 9);
144                 s[12] = 0;
145         }
146
147         return s;
148 }
149
150
151 /*
152  *      Print address of NAS.
153  */
154 static char const *hostname(char *buf, size_t buflen, uint32_t ipaddr)
155 {
156         /*
157          *      WTF is this code for?
158          */
159         if (ipaddr == 0 || ipaddr == (uint32_t)-1 || ipaddr == (uint32_t)-2)
160                 return "";
161
162         return inet_ntop(AF_INET, &ipaddr, buf, buflen);
163
164 }
165
166
167 /*
168  *      Print usage message and exit.
169  */
170 static void NEVER_RETURNS usage(int status)
171 {
172         FILE *output = status?stderr:stdout;
173
174         fprintf(output, "Usage: radwho [-d raddb] [-cfihnprRsSZ] [-N nas] [-P nas_port] [-u user] [-U user]\n");
175         fprintf(output, "  -c                   Show caller ID, if available.\n");
176         fprintf(output, "  -d                   Set the raddb directory (default is %s).\n", RADIUS_DIR);
177         fprintf(output, "  -F <file>            Use radutmp <file>.\n");
178         fprintf(output, "  -i                   Show session ID.\n");
179         fprintf(output, "  -n                   No full name.\n");
180         fprintf(output, "  -N <nas-ip-address>  Show entries matching the given NAS IP address.\n");
181         fprintf(output, "  -p                   Show port type.\n");
182         fprintf(output, "  -P <port>            Show entries matching the given nas port.\n");
183         fprintf(output, "  -r                   Print output as raw comma-delimited data.\n");
184         fprintf(output, "  -R                   Print output as RADIUS attributes and values.\n");
185         fprintf(output, "                       includes ALL information from the radutmp record.\n");
186         fprintf(output, "  -s                   Show full name.\n");
187         fprintf(output, "  -S                   Hide shell users from radius.\n");
188         fprintf(output, "  -u <user>            Show entries matching the given user.\n");
189         fprintf(output, "  -U <user>            Like -u, but case-sensitive.\n");
190         fprintf(output, "  -Z                   Include accounting stop information in radius output.  Requires -R.\n");
191         exit(status);
192 }
193
194
195 /*
196  *      Main program
197  */
198 int main(int argc, char **argv)
199 {
200         CONF_SECTION *maincs, *cs;
201         FILE *fp;
202         struct radutmp rt;
203         char othername[256];
204         char nasname[1024];
205         char session_id[sizeof(rt.session_id)+1];
206         int hideshell = 0;
207         int showsid = 0;
208         int rawoutput = 0;
209         int radiusoutput = 0;   /* Radius attributes */
210         char const *portind;
211         int c;
212         unsigned int portno;
213         char buffer[2048];
214         char const *user = NULL;
215         int user_cmp = 0;
216         time_t now = 0;
217         uint32_t nas_port = ~0;
218         uint32_t nas_ip_address = INADDR_NONE;
219         int zap = 0;
220
221         raddb_dir = RADIUS_DIR;
222
223         talloc_set_log_stderr();
224
225         while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
226                 case 'd':
227                         raddb_dir = optarg;
228                         break;
229                 case 'F':
230                         radutmp_file = optarg;
231                         break;
232                 case 'h':
233                         usage(0);
234                         break;
235                 case 'S':
236                         hideshell = 1;
237                         break;
238                 case 'n':
239                         showname = 0;
240                         break;
241                 case 'N':
242                         if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
243                                 usage(1);
244                         }
245                         break;
246                 case 's':
247                         showname = 1;
248                         break;
249                 case 'i':
250                         showsid = 1;
251                         break;
252                 case 'p':
253                         showptype = 1;
254                         break;
255                 case 'P':
256                         nas_port = atoi(optarg);
257                         break;
258                 case 'c':
259                         showcid = 1;
260                         showname = 1;
261                         break;
262                 case 'r':
263                         rawoutput = 1;
264                         break;
265                 case 'R':
266                         radiusoutput = 1;
267                         now = time(NULL);
268                         break;
269                 case 'u':
270                         user = optarg;
271                         user_cmp = 0;
272                         break;
273                 case 'U':
274                         user = optarg;
275                         user_cmp = 1;
276                         break;
277                 case 'Z':
278                         zap = 1;
279                         break;
280                 default:
281                         usage(1);
282                         break;
283         }
284
285         /*
286          *      Mismatch between the binary and the libraries it depends on
287          */
288         if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
289                 fr_perror("radwho");
290                 return 1;
291         }
292
293         /*
294          *      Be safe.
295          */
296         if (zap && !radiusoutput) zap = 0;
297
298         /*
299          *      zap EVERYONE, but only on this nas
300          */
301         if (zap && !user && (~nas_port == 0)) {
302                 /*
303                  *      We need to know which NAS to zap users in.
304                  */
305                 if (nas_ip_address == INADDR_NONE) usage(1);
306
307                 printf("Acct-Status-Type = Accounting-Off\n");
308                 printf("NAS-IP-Address = %s\n",
309                        hostname(buffer, sizeof(buffer), nas_ip_address));
310                 printf("Acct-Delay-Time = 0\n");
311                 exit(0);        /* don't bother printing anything else */
312         }
313
314         if (radutmp_file) goto have_radutmp;
315
316         /*
317          *      Initialize mainconfig
318          */
319         memset(&mainconfig, 0, sizeof(mainconfig));
320
321         /* Read radiusd.conf */
322         snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
323         maincs = cf_file_read(buffer);
324         if (!maincs) {
325                 fprintf(stderr, "%s: Error reading or parsing radiusd.conf.\n", argv[0]);
326                 exit(1);
327         }
328
329         /* Read the radutmp section of radiusd.conf */
330         cs = cf_section_find_name2(cf_section_sub_find(maincs, "modules"), "radutmp", NULL);
331         if(!cs) {
332                 fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n",
333                         argv[0]);
334                 exit(1);
335         }
336
337         cf_section_parse(cs, NULL, module_config);
338
339         /* Assign the correct path for the radutmp file */
340         radutmp_file = radutmpconfig.radutmp_fn;
341
342  have_radutmp:
343         if (showname < 0) showname = 1;
344
345         /*
346          *      Show the users logged in on the terminal server(s).
347          */
348         if ((fp = fopen(radutmp_file, "r")) == NULL) {
349                 fprintf(stderr, "%s: Error reading %s: %s\n",
350                         progname, radutmp_file, strerror(errno));
351                 return 0;
352         }
353
354         /*
355          *      Don't print the headers if raw or RADIUS
356          */
357         if (!rawoutput && !radiusoutput) {
358                 fputs(showname ? hdr1 : hdr2, stdout);
359                 fputs(eol, stdout);
360         }
361
362         /*
363          *      Read the file, printing out active entries.
364          */
365         while (fread(&rt, sizeof(rt), 1, fp) == 1) {
366                 char name[sizeof(rt.login) + 1];
367
368                 if (rt.type != P_LOGIN) continue; /* hide logout sessions */
369
370                 /*
371                  *      We don't show shell users if we are
372                  *      fingerd, as we have done that above.
373                  */
374                 if (hideshell && !strchr("PCS", rt.proto))
375                         continue;
376
377                 /*
378                  *      Print out sessions only for the given user.
379                  */
380                 if (user) {     /* only for a particular user */
381                         if (((user_cmp == 0) &&
382                              (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
383                             ((user_cmp == 1) &&
384                              (strncmp(rt.login, user, strlen(user)) != 0))) {
385                                 continue;
386                         }
387                 }
388
389                 /*
390                  *      Print out only for the given NAS port.
391                  */
392                 if (~nas_port != 0) {
393                         if (rt.nas_port != nas_port) continue;
394                 }
395
396                 /*
397                  *      Print out only for the given NAS IP address
398                  */
399                 if (nas_ip_address != INADDR_NONE) {
400                         if (rt.nas_address != nas_ip_address) continue;
401                 }
402
403                 memcpy(session_id, rt.session_id, sizeof(rt.session_id));
404                 session_id[sizeof(rt.session_id)] = 0;
405
406                 if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
407                         portind = ">";
408                         portno = (showname ? 999 : 99999);
409                 } else {
410                         portind = "S";
411                         portno = rt.nas_port;
412                 }
413
414                 /*
415                  *      Print output as RADIUS attributes
416                  */
417                 if (radiusoutput) {
418                         memcpy(nasname, rt.login, sizeof(rt.login));
419                         nasname[sizeof(rt.login)] = '\0';
420
421                         fr_print_string(nasname, 0, buffer,
422                                          sizeof(buffer));
423                         printf("User-Name = \"%s\"\n", buffer);
424
425                         fr_print_string(session_id, 0, buffer,
426                                          sizeof(buffer));
427                         printf("Acct-Session-Id = \"%s\"\n", buffer);
428
429                         if (zap) printf("Acct-Status-Type = Stop\n");
430
431                         printf("NAS-IP-Address = %s\n",
432                                hostname(buffer, sizeof(buffer),
433                                         rt.nas_address));
434                         printf("NAS-Port = %u\n", rt.nas_port);
435
436                         switch (rt.proto) {
437                                 case 'S':
438                                         printf("Service-Type = Framed-User\n");
439                                         printf("Framed-Protocol = SLIP\n");
440                                         break;
441                                 case 'P':
442                                         printf("Service-Type = Framed-User\n");
443                                         printf("Framed-Protocol = PPP\n");
444                                         break;
445                                 default:
446                                         printf("Service-type = Login-User\n");
447                                         break;
448                         }
449                         if (rt.framed_address != INADDR_NONE) {
450                                 printf("Framed-IP-Address = %s\n",
451                                        hostname(buffer, sizeof(buffer),
452                                                 rt.framed_address));
453                         }
454
455                         /*
456                          *      Some sanity checks on the time
457                          */
458                         if ((rt.time <= now) &&
459                             (now - rt.time) <= (86400 * 365)) {
460                                 printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time));
461                         }
462
463                         if (rt.caller_id[0] != '\0') {
464                                 memcpy(nasname, rt.caller_id,
465                                        sizeof(rt.caller_id));
466                                 nasname[sizeof(rt.caller_id)] = '\0';
467
468                                 fr_print_string(nasname, 0, buffer,
469                                                  sizeof(buffer));
470                                 printf("Calling-Station-Id = \"%s\"\n", buffer);
471                         }
472
473                         printf("\n"); /* separate entries with a blank line */
474                         continue;
475                 }
476
477                 /*
478                  *      Show the fill name, or not.
479                  */
480                 memcpy(name, rt.login, sizeof(rt.login));
481                 name[sizeof(rt.login)] = '\0';
482
483                 if (showname) {
484                         if (rawoutput == 0) {
485                                 printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s",
486                                        name,
487                                        showcid ? rt.caller_id :
488                                        (showsid? session_id : fullname(rt.login)),
489                                        proto(rt.proto, rt.porttype),
490                                        portind, portno,
491                                        dotime(rt.time),
492                                        hostname(nasname, sizeof(nasname), rt.nas_address),
493                                        hostname(othername, sizeof(othername), rt.framed_address), eol);
494                         } else {
495                                 printf("%s,%s,%s,%s%u,%s,%s,%s%s",
496                                        name,
497                                        showcid ? rt.caller_id :
498                                        (showsid? session_id : fullname(rt.login)),
499                                        proto(rt.proto, rt.porttype),
500                                        portind, portno,
501                                        dotime(rt.time),
502                                        hostname(nasname, sizeof(nasname), rt.nas_address),
503                                        hostname(othername, sizeof(othername), rt.framed_address), eol);
504                         }
505                 } else {
506                         if (rawoutput == 0) {
507                                 printf("%-10.10s %s%-5u  %-6.6s %-13.13s %-15.15s %-.28s%s",
508                                        name,
509                                        portind, portno,
510                                        proto(rt.proto, rt.porttype),
511                                        dotime(rt.time),
512                                        hostname(nasname, sizeof(nasname), rt.nas_address),
513                                        hostname(othername, sizeof(othername), rt.framed_address),
514                                        eol);
515                         } else {
516                                 printf("%s,%s%u,%s,%s,%s,%s%s",
517                                        name,
518                                        portind, portno,
519                                        proto(rt.proto, rt.porttype),
520                                        dotime(rt.time),
521                                        hostname(nasname, sizeof(nasname), rt.nas_address),
522                                        hostname(othername, sizeof(othername), rt.framed_address),
523                                        eol);
524                         }
525                 }
526         }
527         fclose(fp);
528
529         return 0;
530 }