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