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