eap2mschap_local.h revision 1.1
1/*	$OpenBSD: eap2mschap_local.h,v 1.1 2024/07/14 16:09:23 yasuoka Exp $	*/
2
3/*
4 * Copyright (c) 2024 Internet Initiative Japan Inc.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#define	EAP_CODE_REQUEST	1
20#define	EAP_CODE_RESPONSE	2
21#define	EAP_CODE_SUCCESS	3
22#define	EAP_CODE_FAILURE	4
23
24#define	EAP_TYPE_IDENTITY	1
25#define	EAP_TYPE_NOTIFICATION	2
26#define	EAP_TYPE_NAK		3
27#define	EAP_TYPE_MSCHAPV2	0x1a	/* [MS-CHAP] MS-EAP-Authentication */
28
29#define CHAP_CHALLENGE		1
30#define CHAP_RESPONSE		2
31#define CHAP_SUCCESS		3
32#define CHAP_FAILURE		4
33
34/* From [MS-CHAP] */
35enum eap_chap_status {
36	EAP_CHAP_NONE,
37	EAP_CHAP_CHALLENGE_SENT,
38	EAP_CHAP_SUCCESS_REQUEST_SENT,
39	EAP_CHAP_FAILURE_REQUEST_SENT,
40	EAP_CHAP_CHANGE_PASSWORD_SENT,
41	EAP_CHAP_FAILED,
42	EAP_CHAP_SUCCESS
43};
44
45struct eap {
46	uint8_t		code;
47	uint8_t		id;
48	uint16_t	length;
49	uint8_t		value[0];
50} __packed;
51
52struct chap {
53	uint8_t		code;
54	uint8_t		id;
55	uint16_t	length;
56	int8_t		value[0];
57} __packed;
58
59struct eap_chap {
60	struct eap	eap;
61	uint8_t		eap_type;
62	struct chap	chap;
63};
64
65struct eap_mschap_challenge {
66	struct eap	eap;
67	uint8_t		eap_type;
68	struct chap	chap;
69	uint8_t		challsiz;
70	uint8_t		chall[16];
71	char		chap_name[0];
72} __packed;
73static_assert(sizeof(struct eap_mschap_challenge) == 26, "");
74static_assert(offsetof(struct eap_mschap_challenge, chap) == 5, "");
75static_assert(offsetof(struct eap_mschap_challenge, chall) == 10, "");
76
77struct eap_mschap_response {
78	struct eap	eap;
79	uint8_t		eap_type;
80	struct chap	chap;
81	uint8_t		challsiz;
82	uint8_t		peerchall[16];
83	uint8_t		reserved[8];
84	uint8_t		ntresponse[24];
85	uint8_t		flags;
86	uint8_t		chap_name[0];
87} __packed;
88static_assert(sizeof(struct eap_mschap_response) == 59, "");
89static_assert(offsetof(struct eap_mschap_response, chap) == 5, "");
90static_assert(offsetof(struct eap_mschap_response, peerchall) == 10, "");
91
92struct radius_ms_chap2_response {
93	uint8_t		ident;
94	uint8_t		flags;
95	uint8_t		peerchall[16];
96	uint8_t		reserved[8];
97	uint8_t		ntresponse[24];
98} __packed;
99
100
101struct eap2mschap;
102
103struct access_req {
104	struct eap2mschap	*eap2mschap;
105	char			*username;
106	u_int			 q_id;
107	TAILQ_ENTRY(access_req)	 next;
108	RB_ENTRY(access_req)	 tree;
109	/* for EAP */
110	enum eap_chap_status	 eap_chap_status;
111	char			 state[16];
112	unsigned char		 chap_id;
113	unsigned char		 eap_id;
114	time_t			 eap_time;
115	char			 chall[16];
116	RADIUS_PACKET		*pkt;
117
118};
119TAILQ_HEAD(access_reqq, access_req);
120RB_HEAD(access_reqt, access_req);
121
122#define CHAP_NAME_MAX			40
123
124struct eap2mschap {
125	struct module_base	*base;
126	char			*secret;
127	char			 chap_name[CHAP_NAME_MAX + 1];
128	struct access_reqq	 reqq;
129	struct access_reqt	 eapt;
130	struct event		 ev_eapt;
131};
132
133/* Attributes copied from CHAP Access-Accept to EAP Access-Access-Accept */
134struct preserve_attrs {
135	uint8_t		type;
136	uint32_t	vendor;
137} preserve_attrs[] = {
138	{ RADIUS_TYPE_FRAMED_PROTOCOL,		0},
139	{ RADIUS_TYPE_FRAMED_IP_ADDRESS,	0},
140	{ RADIUS_TYPE_FRAMED_IP_NETMASK,	0},
141	{ RADIUS_TYPE_FRAMED_IPV6_ADDRESS,	0},
142	{ RADIUS_TYPE_DNS_SERVER_IPV6_ADDRESS,	0},
143	{ RADIUS_TYPE_FRAMED_ROUTING,		0},
144	{ RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
145	{ RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
146	{ RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
147	{ RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,RADIUS_VENDOR_MICROSOFT },
148	{ RADIUS_VTYPE_MPPE_SEND_KEY,		RADIUS_VENDOR_MICROSOFT },
149	{ RADIUS_VTYPE_MPPE_RECV_KEY, 		RADIUS_VENDOR_MICROSOFT }
150};
151
152#ifndef EAP2MSCHAP_DEBUG
153#define	EAP2MSCHAP_DBG(...)
154#define	EAP2MSCHAP_ASSERT(_cond)
155#else
156#define	EAP2MSCHAP_DBG(...)	logit(LOG_DEBUG, __VA_ARGS__)
157#define	EAP2MSCHAP_ASSERT(_cond)				\
158	do {							\
159		if (!(_cond)) {					\
160			log_warnx(				\
161			    "ASSERT(%s) failed in %s() at %s:%d",\
162			    #_cond, __func__, __FILE__, __LINE__);\
163			abort();				\
164		}						\
165	} while (0/* CONSTCOND */);
166#endif
167#ifndef nitems
168#define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
169#endif
170
171static void	 eap2mschap_init(struct eap2mschap *);
172static void	 eap2mschap_start(void *);
173static void	 eap2mschap_config_set(void *, const char *, int,
174		    char * const *);
175static void	 eap2mschap_stop(void *);
176static void	 eap2mschap_access_request(void *, u_int, const u_char *,
177		    size_t);
178static void	 eap2mschap_next_response(void *, u_int, const u_char *,
179		    size_t);
180
181static void	 eap2mschap_on_eapt (int, short, void *);
182static void	 eap2mschap_reset_eaptimer (struct eap2mschap *);
183
184static struct access_req
185		*access_request_new(struct eap2mschap *, u_int);
186static void	 access_request_free(struct access_req *);
187static int	 access_request_compar(struct access_req *,
188		    struct access_req *);
189
190
191static struct access_req
192		*eap_recv(struct eap2mschap *, u_int, RADIUS_PACKET *);
193static struct access_req
194		*eap_recv_mschap(struct eap2mschap *, struct access_req *,
195		    RADIUS_PACKET *, struct eap_chap *);
196static void	 eap_resp_mschap(struct eap2mschap *, struct access_req *,
197		    RADIUS_PACKET *);
198static void	 eap_send_reject(struct access_req *, RADIUS_PACKET *, u_int);
199static const char
200		*eap_chap_status_string(enum eap_chap_status);
201static const char
202		*hex_string(const char *, size_t, char *, size_t);
203static time_t	 monotime(void);
204
205RB_PROTOTYPE_STATIC(access_reqt, access_req, tree, access_request_compar);
206