xref: /openbsd-src/usr.sbin/tcpdump/print-radius.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: print-radius.c,v 1.4 2000/10/03 14:21:56 ho Exp $	*/
2 
3 #include <sys/types.h>
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6 
7 #include <stdio.h>
8 #include <string.h>
9 
10 /* RADIUS support for tcpdump, Thomas Ptacek <tqbf@enteract.com> */
11 
12 #include "interface.h"
13 #include "radius.h"
14 
15 static void r_print_att(int code, int len, const u_char *val);
16 static void r_print_int(int code, int len, const u_char *val);
17 static void r_print_address(int code, int len, const u_char *val);
18 static void r_print_string(int code, int len, const u_char *val);
19 static void r_print_hex(int code, int len, const u_char *val);
20 
21 /* --------------------------------------------------------------- */
22 
23 struct radius_ctable {
24 	int code;
25 	char *name;
26 };
27 
28 /* map opcodes to strings */
29 
30 #define DEFINED_OPCODES		11
31 
32 static struct radius_ctable radius_codes[] = {
33 	{ -1, 					NULL	},
34 	{ RADIUS_CODE_ACCESS_REQUEST,		"Axs?"	},
35 	{ RADIUS_CODE_ACCESS_ACCEPT,		"Axs+"	},
36 	{ RADIUS_CODE_ACCESS_REJECT,		"Axs-"	},
37 	{ RADIUS_CODE_ACCOUNT_REQUEST,		"Act?"	},
38 	{ RADIUS_CODE_ACCOUNT_RESPONSE,		"Act+"	},
39 	{ RADIUS_CODE_ACCOUNT_STATUS,		"ActSt"	},
40 	{ RADIUS_CODE_PASSCHG_REQUEST,		"Pchg?"	},
41 	{ RADIUS_CODE_PASSCHG_ACCEPT,		"Pchg+"	},
42 	{ RADIUS_CODE_PASSCHG_REJECT,		"Pchg-"	},
43 	{ RADIUS_CODE_ACCOUNT_MESSAGE,		"ActMg"	},
44 	{ RADIUS_CODE_ACCESS_CHALLENGE,		"Axs!"	},
45 	{ -1,					NULL	}
46 };
47 
48 /* --------------------------------------------------------------- */
49 
50 #define MAX_VALUES 20
51 
52 struct radius_atable {
53 	int code;
54 	int encoding;
55 	char *name;
56 	char *values[MAX_VALUES];
57 };
58 
59 /* map attributes to strings */
60 
61 /* the right way to do this is probably to read these values out
62  * of the actual RADIUS dictionary; this would require the machine
63  * running tcpdump to have that file installed, and it's not my
64  * program, so I'm not going to introduce new dependancies. Oh well.
65  */
66 
67 static struct radius_atable radius_atts[] = {
68 
69 { RADIUS_ATT_USER_NAME, 	RD_STRING, 	"Name", 	{ NULL } },
70 { RADIUS_ATT_PASSWORD, 		RD_HEX, 	"Pass", 	{ NULL } },
71 { RADIUS_ATT_CHAP_PASS, 	RD_HEX, 	"CPass",	{ NULL } },
72 { RADIUS_ATT_NAS_IP, 		RD_ADDRESS, 	"NAS-IP", 	{ NULL } },
73 { RADIUS_ATT_NAS_PORT, 		RD_INT, 	"NAS-Pt", 	{ NULL } },
74 
75 { RADIUS_ATT_USER_SERVICE, 	RD_INT, 	"USvc",
76 { "", "Login", "Framed", "DB-Lgn", "DB-Frm", "Out", "Shell", NULL } },
77 
78 { RADIUS_ATT_PROTOCOL, 		RD_INT, 	"FProt",
79 { "", "PPP", "SLIP", NULL } },
80 
81 { RADIUS_ATT_FRAMED_ADDRESS, 	RD_ADDRESS, 	"F-IP", 	{ NULL } },
82 { RADIUS_ATT_NETMASK, 		RD_ADDRESS, 	"F-Msk", 	{ NULL } },
83 { RADIUS_ATT_ROUTING, 		RD_INT, 	"F-Rtg", 	{ NULL } },
84 { RADIUS_ATT_FILTER, 		RD_STRING, 	"FltID", 	{ NULL } },
85 { RADIUS_ATT_MTU, 		RD_INT, 	"F-MTU", 	{ NULL } },
86 { RADIUS_ATT_COMPRESSION, 	RD_INT, 	"F-Comp", 	{ NULL } },
87 { RADIUS_ATT_LOGIN_HOST, 	RD_ADDRESS, 	"L-Hst", 	{ NULL } },
88 
89 { RADIUS_ATT_LOGIN_SERVICE, 	RD_INT, 	"L-Svc",
90 { "", "Telnt", "Rlog", "Clear", "PortM", NULL }				},
91 
92 { RADIUS_ATT_LOGIN_TCP_PORT, 	RD_INT, 	"L-Pt", 	{ NULL } },
93 { RADIUS_ATT_OLD_PASSWORD, 	RD_HEX, 	"OPass", 	{ NULL } },
94 { RADIUS_ATT_PORT_MESSAGE, 	RD_STRING, 	"PMsg", 	{ NULL } },
95 { RADIUS_ATT_DIALBACK_NO, 	RD_STRING, 	"DB#", 		{ NULL } },
96 { RADIUS_ATT_DIALBACK_NAME, 	RD_STRING, 	"DBNm", 	{ NULL } },
97 { RADIUS_ATT_EXPIRATION, 	RD_DATE, 	"PExp", 	{ NULL } },
98 { RADIUS_ATT_FRAMED_ROUTE, 	RD_STRING, 	"F-Rt", 	{ NULL } },
99 { RADIUS_ATT_FRAMED_IPX, 	RD_ADDRESS, 	"F-IPX", 	{ NULL } },
100 { RADIUS_ATT_CHALLENGE_STATE, 	RD_STRING, 	"CState", 	{ NULL } },
101 { RADIUS_ATT_CLASS, 		RD_STRING, 	"Class", 	{ NULL } },
102 { RADIUS_ATT_VENDOR_SPECIFIC, 	RD_HEX, 	"Vendor", 	{ NULL } },
103 { RADIUS_ATT_SESSION_TIMEOUT, 	RD_INT, 	"S-TO", 	{ NULL } },
104 { RADIUS_ATT_IDLE_TIMEOUT, 	RD_INT, 	"I-TO", 	{ NULL } },
105 { RADIUS_ATT_TERMINATE_ACTION, 	RD_INT, 	"TermAct", 	{ NULL } },
106 { RADIUS_ATT_CALLED_ID, 	RD_STRING, 	"Callee", 	{ NULL } },
107 { RADIUS_ATT_CALLER_ID, 	RD_STRING, 	"Caller", 	{ NULL } },
108 
109 { RADIUS_ATT_STATUS_TYPE, 	RD_INT, 	"Stat",
110 { "", "Start", "Stop", NULL }					},
111 
112 { -1,				-1,		NULL, 		{ NULL } }
113 
114 };
115 
116 typedef void (*aselector)(int code, int len, const u_char *data);
117 aselector atselector[] = {
118 	r_print_hex,
119 	r_print_int,
120 	r_print_int,
121 	r_print_address,
122 	r_print_string,
123 	r_print_hex
124 };
125 
126 static void r_print_att(int code, int len, const u_char *data) {
127 	struct radius_atable *atp;
128 	int i;
129 
130 	for(atp = radius_atts; atp->code != -1; atp++)
131 		if(atp->code == code)
132 			break;
133 
134 	if(atp->code == -1) {
135 		if(vflag > 1) {
136 			fprintf(stdout, " %d =", code);
137 			atselector[RD_HEX](code, len, data);
138 		} else
139 			fprintf(stdout, " %d", code);
140 
141 		return;
142 	}
143 
144 	fprintf(stdout, " %s =", atp->name);
145 
146 	if(atp->encoding == RD_INT && *atp->values) {
147 		int k = ntohl((*(int *)data));
148 
149 		for(i = 0; atp->values[i] != NULL; i++)
150 			/* SHOOT ME */ ;
151 
152 		if(k < i) {
153 			fprintf(stdout, " %s",
154 				atp->values[k]);
155 			return;
156 		}
157 	}
158 
159 	atselector[atp->encoding](code, len, data);
160 }
161 
162 static void r_print_int(int code, int len, const u_char *data) {
163 	if(len < 4) {
164 		fputs(" ?", stdout);
165 		return;
166 	}
167 
168 	fprintf(stdout, " %d", ntohl((*(int *)data)));
169 }
170 
171 static void r_print_address(int code, int len, const u_char *data) {
172 	if(len < 4) {
173 		fputs(" ?", stdout);
174 		return;
175 	}
176 
177 	fprintf(stdout, " %s", inet_ntoa((*(struct in_addr *)data)));
178 }
179 
180 static void r_print_string(int code, int len, const u_char *data) {
181 	char string[128];
182 
183 	if(!len) {
184 		fputs(" ?", stdout);
185 		return;
186 	}
187 
188 	if(len > 127)
189 		len = 127;
190 
191 	memset(string, 0, 128);
192 	memcpy(string, data, len);
193 
194 	fprintf(stdout, " %s", string);
195 }
196 
197 static void r_print_hex(int code, int len, const u_char *data) {
198 	int i;
199 
200 	/* excuse me */
201 
202 	fputs(" [", stdout);
203 
204 	for(i = 0; i < len; i++)
205 		fprintf(stdout, "%x", data[i]);
206 
207 	fputc(']', stdout);
208 }
209 
210 void radius_print(register const u_char *data, u_int len) {
211 	const struct radius_header *rhp;
212 	const u_char *pp;
213 	int i, l, ac, al;
214 
215 	if(len < sizeof(struct radius_header)) {
216 		fputs(" [|radius]", stdout);
217 		return;
218 	}
219 
220 	rhp = (struct radius_header *) data;
221 
222 	if(rhp->code > DEFINED_OPCODES ||
223 	   rhp->code < 1)
224 		fprintf(stdout, " Code:%d id:%x [%d]",
225 		rhp->code, rhp->id, ntohs(rhp->len));
226 	else
227 		fprintf(stdout, " %s id:%x [%d]",
228 			radius_codes[rhp->code].name,
229 			rhp->id, ntohs(rhp->len));
230 
231 	if(ntohs(rhp->len) > len) {
232 		fputs(" [|radius]", stdout);
233 		return;
234 	}
235 
236 	l = len - RADFIXEDSZ;
237 	if(!l)
238 		return;
239 	else
240 		pp = data + RADFIXEDSZ;
241 
242 	i = 0; /* XXX I don't see what 'i' is supposed to do here. */
243 	while(l) {
244 		if(!i) fputc(',', stdout); i = 0;
245 
246 		ac = *pp++;
247 		al = *pp++;
248 
249 		if(al > l || al < 2) {
250 			fputs(" [|radius]", stdout);
251 			return;
252 		}
253 
254 		al -= 2;
255 
256 		r_print_att(ac, al, pp);
257 
258 		pp += al; l -= al + 2;
259 	}
260 }
261