1 /* $OpenBSD: print-radius.c,v 1.13 2020/01/24 22:46:37 procter Exp $ */
2
3 /*
4 * Copyright (c) 1997 Thomas H. Ptacek. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33
34 #include <stdio.h>
35 #include <string.h>
36
37 /* RADIUS support for tcpdump, Thomas Ptacek <tqbf@enteract.com> */
38
39 #include "interface.h"
40 #include "radius.h"
41
42 static void r_print_att(int code, int len, const u_char *val);
43 static void r_print_int(int code, int len, const u_char *val);
44 static void r_print_address(int code, int len, const u_char *val);
45 static void r_print_string(int code, int len, const u_char *val);
46 static void r_print_hex(int code, int len, const u_char *val);
47
48 /* --------------------------------------------------------------- */
49
50 struct radius_ctable {
51 int code;
52 char *name;
53 };
54
55 /* map opcodes to strings */
56
57 #define DEFINED_OPCODES 11
58
59 static struct radius_ctable radius_codes[] = {
60 { -1, NULL },
61 { RADIUS_CODE_ACCESS_REQUEST, "Axs?" },
62 { RADIUS_CODE_ACCESS_ACCEPT, "Axs+" },
63 { RADIUS_CODE_ACCESS_REJECT, "Axs-" },
64 { RADIUS_CODE_ACCOUNT_REQUEST, "Act?" },
65 { RADIUS_CODE_ACCOUNT_RESPONSE, "Act+" },
66 { RADIUS_CODE_ACCOUNT_STATUS, "ActSt" },
67 { RADIUS_CODE_PASSCHG_REQUEST, "Pchg?" },
68 { RADIUS_CODE_PASSCHG_ACCEPT, "Pchg+" },
69 { RADIUS_CODE_PASSCHG_REJECT, "Pchg-" },
70 { RADIUS_CODE_ACCOUNT_MESSAGE, "ActMg" },
71 { RADIUS_CODE_ACCESS_CHALLENGE, "Axs!" },
72 { -1, NULL }
73 };
74
75 /* --------------------------------------------------------------- */
76
77 #define MAX_VALUES 20
78
79 struct radius_atable {
80 int code;
81 int encoding;
82 char *name;
83 char *values[MAX_VALUES];
84 };
85
86 /* map attributes to strings */
87
88 /* the right way to do this is probably to read these values out
89 * of the actual RADIUS dictionary; this would require the machine
90 * running tcpdump to have that file installed, and it's not my
91 * program, so I'm not going to introduce new dependencies. Oh well.
92 */
93
94 static struct radius_atable radius_atts[] = {
95
96 { RADIUS_ATT_USER_NAME, RD_STRING, "Name", { NULL } },
97 { RADIUS_ATT_PASSWORD, RD_HEX, "Pass", { NULL } },
98 { RADIUS_ATT_CHAP_PASS, RD_HEX, "CPass", { NULL } },
99 { RADIUS_ATT_NAS_IP, RD_ADDRESS, "NAS-IP", { NULL } },
100 { RADIUS_ATT_NAS_PORT, RD_INT, "NAS-Pt", { NULL } },
101
102 { RADIUS_ATT_USER_SERVICE, RD_INT, "USvc",
103 { "", "Login", "Framed", "DB-Lgn", "DB-Frm", "Out", "Shell", NULL } },
104
105 { RADIUS_ATT_PROTOCOL, RD_INT, "FProt",
106 { "", "PPP", "SLIP", NULL } },
107
108 { RADIUS_ATT_FRAMED_ADDRESS, RD_ADDRESS, "F-IP", { NULL } },
109 { RADIUS_ATT_NETMASK, RD_ADDRESS, "F-Msk", { NULL } },
110 { RADIUS_ATT_ROUTING, RD_INT, "F-Rtg", { NULL } },
111 { RADIUS_ATT_FILTER, RD_STRING, "FltID", { NULL } },
112 { RADIUS_ATT_MTU, RD_INT, "F-MTU", { NULL } },
113 { RADIUS_ATT_COMPRESSION, RD_INT, "F-Comp", { NULL } },
114 { RADIUS_ATT_LOGIN_HOST, RD_ADDRESS, "L-Hst", { NULL } },
115
116 { RADIUS_ATT_LOGIN_SERVICE, RD_INT, "L-Svc",
117 { "", "Telnt", "Rlog", "Clear", "PortM", NULL } },
118
119 { RADIUS_ATT_LOGIN_TCP_PORT, RD_INT, "L-Pt", { NULL } },
120 { RADIUS_ATT_OLD_PASSWORD, RD_HEX, "OPass", { NULL } },
121 { RADIUS_ATT_PORT_MESSAGE, RD_STRING, "PMsg", { NULL } },
122 { RADIUS_ATT_DIALBACK_NO, RD_STRING, "DB#", { NULL } },
123 { RADIUS_ATT_DIALBACK_NAME, RD_STRING, "DBNm", { NULL } },
124 { RADIUS_ATT_EXPIRATION, RD_DATE, "PExp", { NULL } },
125 { RADIUS_ATT_FRAMED_ROUTE, RD_STRING, "F-Rt", { NULL } },
126 { RADIUS_ATT_FRAMED_IPX, RD_ADDRESS, "F-IPX", { NULL } },
127 { RADIUS_ATT_CHALLENGE_STATE, RD_STRING, "CState", { NULL } },
128 { RADIUS_ATT_CLASS, RD_STRING, "Class", { NULL } },
129 { RADIUS_ATT_VENDOR_SPECIFIC, RD_HEX, "Vendor", { NULL } },
130 { RADIUS_ATT_SESSION_TIMEOUT, RD_INT, "S-TO", { NULL } },
131 { RADIUS_ATT_IDLE_TIMEOUT, RD_INT, "I-TO", { NULL } },
132 { RADIUS_ATT_TERMINATE_ACTION, RD_INT, "TermAct", { NULL } },
133 { RADIUS_ATT_CALLED_ID, RD_STRING, "Callee", { NULL } },
134 { RADIUS_ATT_CALLER_ID, RD_STRING, "Caller", { NULL } },
135
136 { RADIUS_ATT_STATUS_TYPE, RD_INT, "Stat",
137 { "", "Start", "Stop", NULL } },
138
139 { -1, -1, NULL, { NULL } }
140
141 };
142
143 typedef void (*aselector)(int code, int len, const u_char *data);
144 aselector atselector[] = {
145 r_print_hex,
146 r_print_int,
147 r_print_int,
148 r_print_address,
149 r_print_string,
150 r_print_hex
151 };
152
r_print_att(int code,int len,const u_char * data)153 static void r_print_att(int code, int len, const u_char *data) {
154 struct radius_atable *atp;
155 int i;
156
157 for(atp = radius_atts; atp->code != -1; atp++)
158 if(atp->code == code)
159 break;
160
161 if(atp->code == -1) {
162 if(vflag > 1) {
163 printf(" %d =", code);
164 atselector[RD_HEX](code, len, data);
165 } else
166 printf(" %d", code);
167
168 return;
169 }
170
171 printf(" %s =", atp->name);
172
173 if(atp->encoding == RD_INT && *atp->values) {
174 u_int32_t k = ntohl((*(int *)data));
175
176 for(i = 0; atp->values[i] != NULL; i++)
177 /* SHOOT ME */ ;
178
179 if(k < i) {
180 printf(" %s",
181 atp->values[k]);
182 return;
183 }
184 }
185
186 atselector[atp->encoding](code, len, data);
187 }
188
r_print_int(int code,int len,const u_char * data)189 static void r_print_int(int code, int len, const u_char *data) {
190 if(len < 4) {
191 printf(" ?");
192 return;
193 }
194
195 printf(" %d", ntohl((*(int *)data)));
196 }
197
r_print_address(int code,int len,const u_char * data)198 static void r_print_address(int code, int len, const u_char *data) {
199 if(len < 4) {
200 printf(" ?");
201 return;
202 }
203
204 printf(" %s", inet_ntoa((*(struct in_addr *)data)));
205 }
206
r_print_string(int code,int len,const u_char * data)207 static void r_print_string(int code, int len, const u_char *data) {
208 char string[128];
209
210 if(!len) {
211 printf(" ?");
212 return;
213 }
214
215 if(len > 127)
216 len = 127;
217
218 memset(string, 0, 128);
219 memcpy(string, data, len);
220
221 printf(" ");
222 safeputs(string);
223 }
224
r_print_hex(int code,int len,const u_char * data)225 static void r_print_hex(int code, int len, const u_char *data) {
226 int i;
227
228 /* excuse me */
229
230 printf(" [");
231
232 for(i = 0; i < len; i++)
233 printf("%02x", data[i]);
234
235 fputc(']', stdout);
236 }
237
radius_print(const u_char * data,u_int len)238 void radius_print(const u_char *data, u_int len) {
239 const struct radius_header *rhp;
240 const u_char *pp;
241 int first, l, ac, al;
242
243 if(len < sizeof(struct radius_header)) {
244 printf("[|radius]");
245 return;
246 }
247
248 rhp = (struct radius_header *) data;
249
250 if(rhp->code > DEFINED_OPCODES ||
251 rhp->code < 1)
252 printf("Code:%d id:%x [%d]",
253 rhp->code, rhp->id, ntohs(rhp->len));
254 else
255 printf("%s id:%x [%d]",
256 radius_codes[rhp->code].name,
257 rhp->id, ntohs(rhp->len));
258
259 if(ntohs(rhp->len) > len) {
260 printf("[|radius]");
261 return;
262 }
263
264 l = len - RADFIXEDSZ;
265 if(!l)
266 return;
267 else
268 pp = data + RADFIXEDSZ;
269
270 first = 1;
271 while(l) {
272 if(!first)
273 fputc(',', stdout);
274 else
275 first = 0;
276
277 ac = *pp++;
278 al = *pp++;
279
280 if(al > l || al < 2) {
281 printf(" [|radius]");
282 return;
283 }
284
285 al -= 2;
286
287 r_print_att(ac, al, pp);
288
289 pp += al; l -= al + 2;
290 }
291 }
292