Annotation of embedaddon/mpd/src/eap.c, revision 1.1.1.4
1.1 misho 1: /*
2: * See ``COPYRIGHT.mpd''
3: *
1.1.1.4 ! misho 4: * $Id: eap.c 2371 2020-08-27 11:54:35Z dadv $
1.1 misho 5: *
6: */
7:
8: #include "ppp.h"
9: #include "radius.h"
10: #include "auth.h"
11: #include "ngfunc.h"
12:
13: /*
14: * INTERNAL FUNCTIONS
15: */
16:
17: static void EapSendRequest(Link l, u_char type);
18: static void EapSendNak(Link l, u_char id, u_char type);
19: static void EapSendIdentRequest(Link l);
20: static void EapIdentTimeout(void *ptr);
21: static char EapTypeSupported(u_char type);
22: static void EapRadiusProxy(Link l, AuthData auth, const u_char *pkt, u_short len);
23: static void EapRadiusProxyFinish(Link l, AuthData auth);
24: static void EapRadiusSendMsg(void *ptr);
25: static void EapRadiusSendMsgTimeout(void *ptr);
1.1.1.4 ! misho 26: static int EapSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
1.1 misho 27:
28: /* Set menu options */
29: enum {
30: SET_ACCEPT,
31: SET_DENY,
32: SET_ENABLE,
33: SET_DISABLE,
34: SET_YES,
35: SET_NO
36: };
37:
38: /*
39: * GLOBAL VARIABLES
40: */
41:
42: const struct cmdtab EapSetCmds[] = {
43: { "accept [opt ...]", "Accept option",
44: EapSetCommand, NULL, 2, (void *) SET_ACCEPT },
45: { "deny [opt ...]", "Deny option",
46: EapSetCommand, NULL, 2, (void *) SET_DENY },
47: { "enable [opt ...]", "Enable option",
48: EapSetCommand, NULL, 2, (void *) SET_ENABLE },
49: { "disable [opt ...]", "Disable option",
50: EapSetCommand, NULL, 2, (void *) SET_DISABLE },
51: { "yes [opt ...]", "Enable and accept option",
52: EapSetCommand, NULL, 2, (void *) SET_YES },
53: { "no [opt ...]", "Disable and deny option",
54: EapSetCommand, NULL, 2, (void *) SET_NO },
1.1.1.4 ! misho 55: { NULL, NULL, NULL, NULL, 0, NULL },
1.1 misho 56: };
57:
58: /*
59: * INTERNAL VARIABLES
60: */
61:
1.1.1.4 ! misho 62: static const struct confinfo gConfList[] = {
1.1 misho 63: { 0, EAP_CONF_RADIUS, "radius-proxy" },
64: { 1, EAP_CONF_MD5, "md5" },
65: { 0, 0, NULL },
66: };
67:
68:
69:
70: /*
71: * EapInit()
72: */
73:
74: void
75: EapInit(Link l)
76: {
77: EapInfo eap = &l->lcp.auth.eap;
78:
79: Disable(&eap->conf.options, EAP_CONF_MD5);
80: Accept(&eap->conf.options, EAP_CONF_MD5);
81: }
82:
83: /*
84: * EapStart()
85: */
86:
87: void
88: EapStart(Link l, int which)
89: {
90: Auth a = &l->lcp.auth;
91: EapInfo eap = &l->lcp.auth.eap;
92: int i;
93:
94: for (i = 0; i < EAP_NUM_TYPES; i++)
95: eap->peer_types[i] = eap->want_types[i] = 0;
96:
97: /* fill a list of requestable auth types */
98: if (Enabled(&eap->conf.options, EAP_CONF_MD5))
99: eap->want_types[0] = EAP_TYPE_MD5CHAL;
100:
101: /* fill a list of acceptable auth types */
102: if (Acceptable(&eap->conf.options, EAP_CONF_MD5))
103: eap->peer_types[0] = EAP_TYPE_MD5CHAL;
104:
105: if (l->originate == LINK_ORIGINATE_LOCAL)
106: a->params.msoft.chap_alg = a->self_to_peer_alg;
107: else
108: a->params.msoft.chap_alg = a->peer_to_self_alg;
109:
110: switch (which) {
111: case AUTH_PEER_TO_SELF:
112:
113: /* Initialize retry counter and timer */
114: eap->next_id = 1;
115: eap->retry = AUTH_RETRIES;
116:
117: TimerInit(&eap->reqTimer, "EapRadiusSendMsgTimer",
118: l->conf.retry_timeout * SECONDS, EapRadiusSendMsgTimeout, (void *) l);
119:
120: TimerInit(&eap->identTimer, "EapTimer",
121: l->conf.retry_timeout * SECONDS, EapIdentTimeout, (void *) l);
122: TimerStart(&eap->identTimer);
123:
124: /* Send first request
125: * Send the request even, if the Radius-Eap-Proxy feature is active,
126: * this saves on roundtrip.
127: */
128: EapSendIdentRequest(l);
129: break;
130:
131: case AUTH_SELF_TO_PEER: /* Just wait for authenitcaor's request */
132: break;
133:
134: default:
135: assert(0);
136: }
137: }
138:
139: /*
140: * EapStop()
141: */
142:
143: void
144: EapStop(EapInfo eap)
145: {
146: TimerStop(&eap->identTimer);
147: TimerStop(&eap->reqTimer);
148: }
149:
150: /*
151: * EapSendRequest()
152: *
153: * Send an EAP request to peer.
154: */
155:
156: static void
157: EapSendRequest(Link l, u_char type)
158: {
159: Auth const a = &l->lcp.auth;
160: EapInfo const eap = &a->eap;
161: ChapInfo const chap = &a->chap;
162: ChapParams const cp = &a->params.chap;
163: int i = 0;
164: u_char req_type = 0;
165:
166: if (type == 0) {
167: for (i = 0; i < EAP_NUM_TYPES; i++) {
168: if (eap->want_types[i] != 0) {
169: req_type = eap->want_types[i];
170: break;
171: }
172: }
173: } else {
174: req_type = type;
175: }
176:
177: if (req_type == 0) {
178: Log(LG_AUTH, ("[%s] EAP: ran out of EAP Types", l->name));
179: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
180: return;
181: }
182:
183: /* don't request this type again */
184: eap->want_types[i] = 0;
185:
186: switch (req_type) {
187: case EAP_TYPE_MD5CHAL:
188:
189: /* Invalidate any old challenge data */
190: cp->chal_len = 0;
191: /* Initialize retry counter and timer */
192: chap->next_id = 1;
193: chap->retry = AUTH_RETRIES;
194: chap->proto = PROTO_EAP;
195: a->peer_to_self_alg = CHAP_ALG_MD5;
196:
197: TimerInit(&chap->chalTimer, "ChalTimer",
198: l->conf.retry_timeout * SECONDS, ChapChalTimeout, l);
199: TimerStart(&chap->chalTimer);
200:
201: /* Send first challenge */
202: ChapSendChallenge(l);
203: break;
204:
205: default:
206: Log(LG_AUTH, ("[%s] EAP: Type %d is currently un-implemented",
207: l->name, eap->want_types[i]));
208: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
209: }
210:
211: return;
212: }
213:
214: /*
215: * EapSendNak()
216: *
217: * Send an EAP Nak to peer.
218: */
219:
220: static void
221: EapSendNak(Link l, u_char id, u_char type)
222: {
223: Auth const a = &l->lcp.auth;
224: EapInfo const eap = &a->eap;
225: int i = 0;
226: u_char nak_type = 0;
227:
1.1.1.4 ! misho 228: (void)type;
1.1 misho 229: for (i = 0; i < EAP_NUM_TYPES; i++) {
230: if (eap->peer_types[i] != 0) {
231: nak_type = eap->peer_types[i];
232: break;
233: }
234: }
235:
236: if (nak_type == 0) {
237: Log(LG_AUTH, ("[%s] EAP: ran out of EAP Types", l->name));
238: AuthFinish(l, AUTH_SELF_TO_PEER, FALSE);
239: return;
240: }
241:
242: /* don't nak this proto again */
243: eap->peer_types[i] = 0;
244:
245: AuthOutput(l, PROTO_EAP, EAP_RESPONSE, id, &nak_type, 1, 0, EAP_TYPE_NAK);
246: return;
247: }
248:
249: /*
250: * EapSendIdentRequest()
251: *
252: * Send an Ident Request to the peer.
253: */
254:
255: static void
256: EapSendIdentRequest(Link l)
257: {
258: EapInfo const eap = &l->lcp.auth.eap;
259:
260: /* Send the initial Identity request */
261: AuthOutput(l, PROTO_EAP, EAP_REQUEST, eap->next_id++, NULL, 0, 0, EAP_TYPE_IDENT);
262: }
263:
264: /*
265: * EapInput()
266: *
267: * Accept an incoming EAP packet
268: */
269:
270: void
271: EapInput(Link l, AuthData auth, const u_char *pkt, u_short len)
272: {
273: Auth const a = &l->lcp.auth;
274: EapInfo const eap = &a->eap;
275: int data_len = len - 1, i, acc_type;
1.1.1.4 ! misho 276: const u_char *data = NULL;
! 277: u_char type = 0;
1.1 misho 278:
279: if (pkt != NULL) {
1.1.1.4 ! misho 280: data = data_len > 0 ? &pkt[1] : NULL;
1.1 misho 281: type = pkt[0];
282: }
283:
284: if (Enabled(&eap->conf.options, EAP_CONF_RADIUS)) {
285: EapRadiusProxy(l, auth, pkt, len);
286: return;
287: }
288:
289: switch (auth->code) {
290: case EAP_REQUEST:
291: switch (type) {
292: case EAP_TYPE_IDENT:
293: AuthOutput(l, PROTO_EAP, EAP_RESPONSE, auth->id, (u_char *) auth->conf.authname,
294: strlen(auth->conf.authname), 0, EAP_TYPE_IDENT);
295: break;
296:
297: case EAP_TYPE_NAK:
298: case EAP_TYPE_NOTIF:
299: Log(LG_AUTH, ("[%s] EAP: Type %s is invalid in Request messages",
300: l->name, EapType(type)));
301: AuthFinish(l, AUTH_SELF_TO_PEER, FALSE);
302: break;
303:
304: /* deal with Auth Types */
305: default:
306: acc_type = 0;
307: if (EapTypeSupported(type)) {
308: for (i = 0; i < EAP_NUM_TYPES; i++) {
309: if (eap->peer_types[i] == type) {
310: acc_type = eap->peer_types[i];
311: break;
312: }
313: }
314:
315: if (acc_type == 0) {
316: Log(LG_AUTH, ("[%s] EAP: Type %s not acceptable", l->name,
317: EapType(type)));
318: EapSendNak(l, auth->id, type);
319: break;
320: }
321:
322: switch (type) {
323: case EAP_TYPE_MD5CHAL:
324: a->self_to_peer_alg = CHAP_ALG_MD5;
325: auth->code = CHAP_CHALLENGE;
326: ChapInput(l, auth, &pkt[1], len - 1);
327: return;
328:
329: default:
330: assert(0);
331: }
332: } else {
333: Log(LG_AUTH, ("[%s] EAP: Type %s not supported", l->name, EapType(type)));
334: EapSendNak(l, auth->id, type);
335: }
336: }
337: break;
338:
339: case EAP_RESPONSE:
340: switch (type) {
341: case EAP_TYPE_IDENT:
342: TimerStop(&eap->identTimer);
343: Log(LG_AUTH, ("[%s] EAP: Identity:%*.*s",
344: l->name, data_len, data_len, data));
345: EapSendRequest(l, 0);
346: break;
347:
348: case EAP_TYPE_NOTIF:
349: Log(LG_AUTH, ("[%s] EAP: Notify:%*.*s ", l->name,
350: data_len, data_len, data));
351: break;
352:
353: case EAP_TYPE_NAK:
354: Log(LG_AUTH, ("[%s] EAP: Nak desired Type %s ", l->name,
355: EapType(data[0])));
356: if (EapTypeSupported(data[0]))
357: EapSendRequest(l, data[0]);
358: else
359: EapSendRequest(l, 0);
360: break;
361:
362: case EAP_TYPE_MD5CHAL:
363: auth->code = CHAP_RESPONSE;
364: ChapInput(l, auth, &pkt[1], len - 1);
365: return;
366:
367: default:
368: Log(LG_AUTH, ("[%s] EAP: unknown type %d", l->name, type));
369: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
370: }
371: break;
372:
373: case EAP_SUCCESS:
374: AuthFinish(l, AUTH_SELF_TO_PEER, TRUE);
375: break;
376:
377: case EAP_FAILURE:
378: AuthFinish(l, AUTH_SELF_TO_PEER, FALSE);
379: break;
380:
381: default:
382: Log(LG_AUTH, ("[%s] EAP: unknown code %d", l->name, auth->code));
383: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
384: }
385: AuthDataDestroy(auth);
386: }
387:
388: /*
389: * EapRadiusProxy()
390: *
391: * Proxy EAP Requests from/to the RADIUS server
392: */
393:
394: static void
395: EapRadiusProxy(Link l, AuthData auth, const u_char *pkt, u_short len)
396: {
397: int data_len = len - 1;
1.1.1.4 ! misho 398: const u_char *data = NULL;
! 399: u_char type = 0;
1.1 misho 400: Auth const a = &l->lcp.auth;
401: EapInfo const eap = &a->eap;
402: struct fsmheader lh;
403:
404: Log(LG_AUTH, ("[%s] EAP: Proxying packet to RADIUS", l->name));
405:
406: if (pkt != NULL) {
1.1.1.4 ! misho 407: data = data_len > 0 ? &pkt[1] : NULL;
1.1 misho 408: type = pkt[0];
409: }
410:
411: if (auth->code == EAP_RESPONSE && type == EAP_TYPE_IDENT) {
412: TimerStop(&eap->identTimer);
413: if (data_len >= AUTH_MAX_AUTHNAME) {
414: Log(LG_AUTH, ("[%s] EAP: Identity to big (%d), truncating",
415: l->name, data_len));
416: data_len = AUTH_MAX_AUTHNAME - 1;
417: }
418: memset(eap->identity, 0, sizeof(eap->identity));
1.1.1.4 ! misho 419: strncpy(eap->identity, (const char *)data, data_len);
1.1 misho 420: Log(LG_AUTH, ("[%s] EAP: Identity: %s", l->name, eap->identity));
421: }
422:
423: TimerStop(&eap->reqTimer);
424:
425: /* prepare packet */
426: lh.code = auth->code;
427: lh.id = auth->id;
428: lh.length = htons(len + sizeof(lh));
429:
430: auth->params.eapmsg = Malloc(MB_AUTH, len + sizeof(lh));
431: memcpy(auth->params.eapmsg, &lh, sizeof(lh));
432: memcpy(&auth->params.eapmsg[sizeof(lh)], pkt, len);
433:
434: auth->params.eapmsg_len = len + sizeof(lh);
435: strlcpy(auth->params.authname, eap->identity, sizeof(auth->params.authname));
436:
437: auth->eap_radius = TRUE;
438:
439: auth->finish = EapRadiusProxyFinish;
440: AuthAsyncStart(l, auth);
441:
442: }
443:
444: /*
445: * RadiusEapProxyFinish()
446: *
447: * Return point from the asynch RADIUS EAP Proxy Handler.
448: *
449: */
450:
451: static void
452: EapRadiusProxyFinish(Link l, AuthData auth)
453: {
454: Auth const a = &l->lcp.auth;
455: EapInfo eap = &a->eap;
456:
457: Log(LG_AUTH, ("[%s] EAP: RADIUS return status: %s",
458: l->name, AuthStatusText(auth->status)));
459:
460: /* this shouldn't happen normally, however be liberal */
461: if (a->params.eapmsg == NULL) {
462: struct fsmheader lh;
463:
464: Log(LG_AUTH, ("[%s] EAP: Warning, rec'd empty EAP-Message",
465: l->name));
466: /* prepare packet */
467: lh.code = auth->status == AUTH_STATUS_SUCCESS ? EAP_SUCCESS : EAP_FAILURE;
468: lh.id = auth->id;
469: lh.length = htons(sizeof(lh));
470:
471: a->params.eapmsg = Mdup(MB_AUTH, &lh, sizeof(lh));
472: a->params.eapmsg_len = sizeof(lh);
473: }
474:
475: if (a->params.eapmsg != NULL) {
476: eap->retry = AUTH_RETRIES;
477:
478: EapRadiusSendMsg(l);
479: if (auth->status == AUTH_STATUS_UNDEF)
480: TimerStart(&eap->reqTimer);
481: }
482:
483: if (auth->status == AUTH_STATUS_FAIL) {
484: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
485: } else if (auth->status == AUTH_STATUS_SUCCESS) {
486: AuthFinish(l, AUTH_PEER_TO_SELF, TRUE);
487: }
488:
489: AuthDataDestroy(auth);
490: }
491:
492: /*
493: * EapRadiusSendMsg()
494: *
495: * Send an EAP Message to the peer
496: */
497:
498: static void
499: EapRadiusSendMsg(void *ptr)
500: {
501: Mbuf bp;
502: Link l = (Link)ptr;
503: Auth const a = &l->lcp.auth;
1.1.1.4 ! misho 504: FsmHeader const f = (FsmHeader)(void *)a->params.eapmsg;
1.1 misho 505: char buf[32];
506:
507: if (a->params.eapmsg_len > 4) {
508: Log(LG_AUTH, ("[%s] EAP: send %s #%d len: %d, type: %s",
509: l->name, EapCode(f->code, buf, sizeof(buf)), f->id, htons(f->length),
510: EapType(a->params.eapmsg[4])));
511: } else {
512: Log(LG_AUTH, ("[%s] EAP: send %s #%d len: %d",
513: l->name, EapCode(f->code, buf, sizeof(buf)), f->id, htons(f->length)));
514: }
515:
516: bp = mbcopyback(NULL, 0, a->params.eapmsg, a->params.eapmsg_len);
517: NgFuncWritePppFrameLink(l, PROTO_EAP, bp);
518: }
519:
520: /*
521: * EapRadiusSendMsgTimeout()
522: *
523: * Timer expired for reply to our request
524: */
525:
526: static void
527: EapRadiusSendMsgTimeout(void *ptr)
528: {
529: Link l = (Link)ptr;
530: EapInfo const eap = &l->lcp.auth.eap;
531:
532: if (--eap->retry > 0) {
533: TimerStart(&eap->reqTimer);
534: EapRadiusSendMsg(l);
535: }
536: }
537:
538: /*
539: * EapIdentTimeout()
540: *
541: * Timer expired for reply to our request
542: */
543:
544: static void
545: EapIdentTimeout(void *ptr)
546: {
547: Link l = (Link)ptr;
548: EapInfo const eap = &l->lcp.auth.eap;
549:
550: if (--eap->retry > 0) {
551: TimerStart(&eap->identTimer);
552: EapSendIdentRequest(l);
553: }
554: }
555:
556: /*
557: * EapStat()
558: */
559:
560: int
1.1.1.4 ! misho 561: EapStat(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 562: {
563: EapInfo const eap = &ctx->lnk->lcp.auth.eap;
564:
1.1.1.4 ! misho 565: (void)ac;
! 566: (void)av;
! 567: (void)arg;
! 568:
1.1 misho 569: Printf("\tIdentity : %s\r\n", eap->identity);
570: Printf("EAP options\r\n");
571: OptStat(ctx, &eap->conf.options, gConfList);
572:
573: return (0);
574: }
575:
576: /*
577: * EapCode()
578: */
579:
580: const char *
581: EapCode(u_char code, char *buf, size_t len)
582: {
583: switch (code) {
584: case EAP_REQUEST:
585: strlcpy(buf, "REQUEST", len);
586: break;
587: case EAP_RESPONSE:
588: strlcpy(buf, "RESPONSE", len);
589: break;
590: case EAP_SUCCESS:
591: strlcpy(buf, "SUCCESS", len);
592: break;
593: case EAP_FAILURE:
594: strlcpy(buf, "FAILURE", len);
595: break;
596: default:
597: snprintf(buf, len, "code%d", code);
598: }
599: return(buf);
600: }
601:
602: /*
603: * EapType()
604: */
605:
606: const char *
607: EapType(u_char type)
608: {
609: switch (type) {
610: case EAP_TYPE_IDENT:
611: return("Identity");
612: case EAP_TYPE_NOTIF:
613: return("Notification");
614: case EAP_TYPE_NAK:
615: return("Nak");
616: case EAP_TYPE_MD5CHAL:
617: return("MD5 Challenge");
618: case EAP_TYPE_OTP:
619: return("One Time Password");
620: case EAP_TYPE_GTC:
621: return("Generic Token Card");
622: case EAP_TYPE_EAP_TLS:
623: return("TLS");
624: case EAP_TYPE_MSCHAP_V2:
625: return("MS-CHAPv2");
626: case EAP_TYPE_EAP_TTLS:
627: return("TTLS");
628: default:
629: return("UNKNOWN");
630: }
631: }
632:
633: /*
634: * EapTypeSupported()
635: */
636:
637: static char
638: EapTypeSupported(u_char type)
639: {
640: switch (type) {
641: case EAP_TYPE_IDENT:
642: case EAP_TYPE_NOTIF:
643: case EAP_TYPE_NAK:
644: case EAP_TYPE_MD5CHAL:
645: return 1;
646:
647: default:
648: return 0;
649: }
650: }
651:
652: /*
653: * EapSetCommand()
654: */
655:
656: static int
1.1.1.4 ! misho 657: EapSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 658: {
659: EapInfo const eap = &ctx->lnk->lcp.auth.eap;
660:
661: if (ac == 0)
662: return(-1);
663:
664: switch ((intptr_t)arg) {
665:
666: case SET_ACCEPT:
667: AcceptCommand(ac, av, &eap->conf.options, gConfList);
668: break;
669:
670: case SET_DENY:
671: DenyCommand(ac, av, &eap->conf.options, gConfList);
672: break;
673:
674: case SET_ENABLE:
675: EnableCommand(ac, av, &eap->conf.options, gConfList);
676: break;
677:
678: case SET_DISABLE:
679: DisableCommand(ac, av, &eap->conf.options, gConfList);
680: break;
681:
682: case SET_YES:
683: YesCommand(ac, av, &eap->conf.options, gConfList);
684: break;
685:
686: case SET_NO:
687: NoCommand(ac, av, &eap->conf.options, gConfList);
688: break;
689:
690: default:
691: assert(0);
692: }
693:
694: return(0);
695: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>