xref: /openbsd-src/usr.sbin/tcpdump/print-radius.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: print-radius.c,v 1.8 2006/05/23 21:57:15 stevesk 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, " %s", string);
222 }
223 
224 static void r_print_hex(int code, int len, const u_char *data) {
225 	int i;
226 
227 	/* excuse me */
228 
229 	fputs(" [", stdout);
230 
231 	for(i = 0; i < len; i++)
232 		fprintf(stdout, "%x", data[i]);
233 
234 	fputc(']', stdout);
235 }
236 
237 void radius_print(register const u_char *data, u_int len) {
238 	const struct radius_header *rhp;
239 	const u_char *pp;
240 	int first, l, ac, al;
241 
242 	if(len < sizeof(struct radius_header)) {
243 		fputs(" [|radius]", stdout);
244 		return;
245 	}
246 
247 	rhp = (struct radius_header *) data;
248 
249 	if(rhp->code > DEFINED_OPCODES ||
250 	   rhp->code < 1)
251 		fprintf(stdout, " Code:%d id:%x [%d]",
252 		rhp->code, rhp->id, ntohs(rhp->len));
253 	else
254 		fprintf(stdout, " %s id:%x [%d]",
255 			radius_codes[rhp->code].name,
256 			rhp->id, ntohs(rhp->len));
257 
258 	if(ntohs(rhp->len) > len) {
259 		fputs(" [|radius]", stdout);
260 		return;
261 	}
262 
263 	l = len - RADFIXEDSZ;
264 	if(!l)
265 		return;
266 	else
267 		pp = data + RADFIXEDSZ;
268 
269 	first = 1;
270 	while(l) {
271 		if(!first)
272 			fputc(',', stdout);
273 		else
274 			first = 0;
275 
276 		ac = *pp++;
277 		al = *pp++;
278 
279 		if(al > l || al < 2) {
280 			fputs(" [|radius]", stdout);
281 			return;
282 		}
283 
284 		al -= 2;
285 
286 		r_print_att(ac, al, pp);
287 
288 		pp += al; l -= al + 2;
289 	}
290 }
291