1 |
|
|
/* $OpenBSD: print-radius.c,v 1.11 2015/11/16 00:16:39 mmcc 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 |
|
|
|
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 |
|
|
fprintf(stdout, " %d =", code); |
164 |
|
|
atselector[RD_HEX](code, len, data); |
165 |
|
|
} else |
166 |
|
|
fprintf(stdout, " %d", code); |
167 |
|
|
|
168 |
|
|
return; |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
fprintf(stdout, " %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 |
|
|
fprintf(stdout, " %s", |
181 |
|
|
atp->values[k]); |
182 |
|
|
return; |
183 |
|
|
} |
184 |
|
|
} |
185 |
|
|
|
186 |
|
|
atselector[atp->encoding](code, len, data); |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
static void r_print_int(int code, int len, const u_char *data) { |
190 |
|
|
if(len < 4) { |
191 |
|
|
fputs(" ?", stdout); |
192 |
|
|
return; |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
fprintf(stdout, " %d", ntohl((*(int *)data))); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
static void r_print_address(int code, int len, const u_char *data) { |
199 |
|
|
if(len < 4) { |
200 |
|
|
fputs(" ?", stdout); |
201 |
|
|
return; |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
fprintf(stdout, " %s", inet_ntoa((*(struct in_addr *)data))); |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
static void r_print_string(int code, int len, const u_char *data) { |
208 |
|
|
char string[128]; |
209 |
|
|
|
210 |
|
|
if(!len) { |
211 |
|
|
fputs(" ?", stdout); |
212 |
|
|
return; |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
if(len > 127) |
216 |
|
|
len = 127; |
217 |
|
|
|
218 |
|
|
memset(string, 0, 128); |
219 |
|
|
memcpy(string, data, len); |
220 |
|
|
|
221 |
|
|
fprintf(stdout, " "); |
222 |
|
|
safeputs(string); |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
static void r_print_hex(int code, int len, const u_char *data) { |
226 |
|
|
int i; |
227 |
|
|
|
228 |
|
|
/* excuse me */ |
229 |
|
|
|
230 |
|
|
fputs(" [", stdout); |
231 |
|
|
|
232 |
|
|
for(i = 0; i < len; i++) |
233 |
|
|
fprintf(stdout, "%02x", data[i]); |
234 |
|
|
|
235 |
|
|
fputc(']', stdout); |
236 |
|
|
} |
237 |
|
|
|
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 |
|
|
fputs(" [|radius]", stdout); |
245 |
|
|
return; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
rhp = (struct radius_header *) data; |
249 |
|
|
|
250 |
|
|
if(rhp->code > DEFINED_OPCODES || |
251 |
|
|
rhp->code < 1) |
252 |
|
|
fprintf(stdout, " Code:%d id:%x [%d]", |
253 |
|
|
rhp->code, rhp->id, ntohs(rhp->len)); |
254 |
|
|
else |
255 |
|
|
fprintf(stdout, " %s id:%x [%d]", |
256 |
|
|
radius_codes[rhp->code].name, |
257 |
|
|
rhp->id, ntohs(rhp->len)); |
258 |
|
|
|
259 |
|
|
if(ntohs(rhp->len) > len) { |
260 |
|
|
fputs(" [|radius]", stdout); |
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 |
|
|
fputs(" [|radius]", stdout); |
282 |
|
|
return; |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
al -= 2; |
286 |
|
|
|
287 |
|
|
r_print_att(ac, al, pp); |
288 |
|
|
|
289 |
|
|
pp += al; l -= al + 2; |
290 |
|
|
} |
291 |
|
|
} |