xref: /openbsd/usr.sbin/tcpdump/print-radius.c (revision f96bb33f)
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