xref: /plan9/sys/src/cmd/ip/snoopy/eap.c (revision ed397113cdcf7aafea372b730bbcd17b05ee3f60)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 typedef struct Hdr	Hdr;
8 struct Hdr
9 {
10 	uchar	code;
11 	uchar	id;
12 	uchar	len[2];	/* length including this header */
13 
14 	uchar	tp;	/* optional, only for Request/Response */
15 };
16 
17 enum
18 {
19 	EAPHDR=	4,	/* sizeof(code)+sizeof(id)+sizeof(len) */
20 	TPHDR= 1,	/* sizeof(tp) */
21 
22 	/* eap types */
23 	Request = 1,
24 	Response,
25 	Success,
26 	Fail,
27 
28 	/* eap request/response sub-types */
29 	Identity = 1,		/* Identity */
30 	Notify,		/* Notification */
31 	Nak,			/* Nak (Response only) */
32 	Md5,		/* MD5-challenge */
33 	Otp,			/* one time password */
34 	Gtc,			/* generic token card */
35 	Ttls = 21,		/* tunneled TLS */
36 	Xpnd = 254,	/* expanded types */
37 	Xprm,		/* experimental use */
38 };
39 
40 enum
41 {
42 	Ot,
43 };
44 
45 static Mux p_mux[] =
46 {
47 	{ "eap_identity", Identity, },
48 	{ "eap_notify", Notify, },
49 	{ "eap_nak", Nak, },
50 	{ "eap_md5", Md5, },
51 	{ "eap_otp", Otp, },
52 	{ "eap_gtc", Gtc, },
53 	{ "ttls", Ttls, },
54 	{ "eap_xpnd", Xpnd, },
55 	{ "eap_xprm", Xprm, },
56 	{ 0 }
57 };
58 
59 static char *eapsubtype[256] =
60 {
61 [Identity]	"Identity",
62 [Notify]	"Notify",
63 [Nak]		"Nak",
64 [Md5]	"Md5",
65 [Otp]		"Otp",
66 [Gtc]		"Gtc",
67 [Ttls]		"Ttls",
68 [Xpnd]	"Xpnd",
69 [Xprm]	"Xprm",
70 };
71 
72 
73 static void
p_compile(Filter * f)74 p_compile(Filter *f)
75 {
76 	Mux *m;
77 
78 	for(m = p_mux; m->name != nil; m++)
79 		if(strcmp(f->s, m->name) == 0){
80 			f->pr = m->pr;
81 			f->ulv = m->val;
82 			f->subop = Ot;
83 			return;
84 		}
85 	sysfatal("unknown eap field or type: %s", f->s);
86 }
87 
88 static int
p_filter(Filter * f,Msg * m)89 p_filter(Filter *f, Msg *m)
90 {
91 	Hdr *h;
92 	int len;
93 
94 	if(f->subop != Ot)
95 		return 0;
96 
97 	if(m->pe - m->ps < EAPHDR)
98 		return -1;
99 
100 	h = (Hdr*)m->ps;
101 
102 	/* truncate the message if there's extra */
103 	/* len includes header */
104 	len = NetS(h->len);
105 	if(m->ps+len < m->pe)
106 		m->pe = m->ps+len;
107 	else if(m->ps+len > m->pe)
108 		return -1;
109 	m->ps += EAPHDR;
110 
111 	if(h->code != Request && h->code != Response)
112 		return 0;
113 	m->ps += TPHDR;
114 
115 	if(h->tp == f->ulv)
116 		return 1;
117 
118 	return 0;
119 }
120 
121 static char*
op(int i)122 op(int i)
123 {
124 	static char x[20];
125 
126 	switch(i){
127 	case Request:
128 		return "Request";
129 	case Response:
130 		return "Response";
131 	case Success:
132 		return "Success";
133 	case Fail:
134 		return "Fail";
135 	default:
136 		sprint(x, "%1d", i);
137 		return x;
138 	}
139 }
140 
141 static char*
subop(uchar val)142 subop(uchar val)
143 {
144 	static char x[20], *p;
145 
146 	p = eapsubtype[val];
147 	if(p != nil)
148 		return p;
149 	else {
150 		sprint(x, "%1d", val);
151 		return x;
152 	}
153 }
154 
155 static int
p_seprint(Msg * m)156 p_seprint(Msg *m)
157 {
158 	Hdr *h;
159 	int len;
160 	char *p, *e;
161 
162 	if(m->pe - m->ps < EAPHDR)
163 		return -1;
164 
165 	p = m->p;
166 	e = m->e;
167 	h = (Hdr*)m->ps;
168 
169 	/* resize packet (should already be done by eapol) */
170 	/* len includes header */
171 	len = NetS(h->len);
172 	if(m->ps+len < m->pe)
173 		m->pe = m->ps+len;
174 	else if(m->ps+len > m->pe)
175 		return -1;
176 	m->ps += EAPHDR;
177 
178 	p = seprint(p, e, "id=%1d code=%s", h->id, op(h->code));
179 	switch(h->code) {
180 	case Request:
181 	case Response:
182 		m->ps += TPHDR;
183 		p = seprint(p, e, " type=%s", subop(h->tp));
184 		/* special case needed to print eap_notify notification as unicode */
185 		demux(p_mux, h->tp, h->tp, m, &dump);
186 		break;
187 	default:
188 		demux(p_mux, 0, 0, m, &dump);
189 		break;
190 	}
191 	m->p = seprint(p, e, " len=%1d", len);
192 	return 0;
193 }
194 
195 static int
p_seprintidentity(Msg * m)196 p_seprintidentity(Msg *m)
197 {
198 	char *ps, *pe, *z;
199 	int len;
200 
201 	m->pr = nil;
202 	ps = (char*)m->ps;
203 	pe = (char*)m->pe;
204 
205 	/* we would like to do this depending on the 'context':
206 	 *  - one for eap_identity request and
207 	 *  - one for eap_identity response
208 	 * but we've lost the context, or haven't we?
209 	 * so we treat them the same, so we might erroneously
210 	 * print a response as if it was a request. too bad. - axel
211 	 */
212 	for (z=ps; *z != '\0' && z+1 < pe; z++)
213 		;
214 	if (*z == '\0' && z+1 < pe) {
215 		m->p = seprint(m->p, m->e, "prompt=(%s)", ps);
216 		len = pe - (z+1);
217 		m->p = seprint(m->p, m->e, " options=(%.*s)", len, z+1);
218 	} else {
219 		len = pe - ps;
220 		m->p = seprint(m->p, m->e, "%.*s", len, ps);
221 	}
222 	return 0;
223 }
224 
225 Proto eap =
226 {
227 	"eap",
228 	p_compile,
229 	p_filter,
230 	p_seprint,
231 	p_mux,
232 	"%lud",
233 	nil,
234 	defaultframer,
235 };
236 
237 Proto eap_identity =
238 {
239 	"eap_identity",
240 	p_compile,
241 	p_filter,
242 	p_seprintidentity,
243 	nil,
244 	nil,
245 	nil,
246 	defaultframer,
247 };
248