1 /*	$OpenBSD: eap2mschap_local.h,v 1.3 2024/09/15 05:49:05 jsg 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] */
35 enum 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 
45 struct eap {
46 	uint8_t		code;
47 	uint8_t		id;
48 	uint16_t	length;
49 	uint8_t		value[0];
50 } __packed;
51 
52 struct chap {
53 	uint8_t		code;
54 	uint8_t		id;
55 	uint16_t	length;
56 	int8_t		value[0];
57 } __packed;
58 
59 struct eap_chap {
60 	struct eap	eap;
61 	uint8_t		eap_type;
62 	struct chap	chap;
63 };
64 
65 struct 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;
73 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
74 static_assert(sizeof(struct eap_mschap_challenge) == 26, "");
75 static_assert(offsetof(struct eap_mschap_challenge, chap) == 5, "");
76 static_assert(offsetof(struct eap_mschap_challenge, chall) == 10, "");
77 #endif
78 
79 struct eap_mschap_response {
80 	struct eap	eap;
81 	uint8_t		eap_type;
82 	struct chap	chap;
83 	uint8_t		challsiz;
84 	uint8_t		peerchall[16];
85 	uint8_t		reserved[8];
86 	uint8_t		ntresponse[24];
87 	uint8_t		flags;
88 	uint8_t		chap_name[0];
89 } __packed;
90 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
91 static_assert(sizeof(struct eap_mschap_response) == 59, "");
92 static_assert(offsetof(struct eap_mschap_response, chap) == 5, "");
93 static_assert(offsetof(struct eap_mschap_response, peerchall) == 10, "");
94 #endif
95 
96 struct radius_ms_chap2_response {
97 	uint8_t		ident;
98 	uint8_t		flags;
99 	uint8_t		peerchall[16];
100 	uint8_t		reserved[8];
101 	uint8_t		ntresponse[24];
102 } __packed;
103 
104 
105 struct eap2mschap;
106 
107 struct access_req {
108 	struct eap2mschap	*eap2mschap;
109 	char			*username;
110 	u_int			 q_id;
111 	TAILQ_ENTRY(access_req)	 next;
112 	RB_ENTRY(access_req)	 tree;
113 	/* for EAP */
114 	enum eap_chap_status	 eap_chap_status;
115 	char			 state[16];
116 	unsigned char		 chap_id;
117 	unsigned char		 eap_id;
118 	time_t			 eap_time;
119 	char			 chall[16];
120 	RADIUS_PACKET		*pkt;
121 
122 };
123 TAILQ_HEAD(access_reqq, access_req);
124 RB_HEAD(access_reqt, access_req);
125 
126 #define CHAP_NAME_MAX			40
127 
128 struct eap2mschap {
129 	struct module_base	*base;
130 	char			*secret;
131 	char			 chap_name[CHAP_NAME_MAX + 1];
132 	struct access_reqq	 reqq;
133 	struct access_reqt	 eapt;
134 	struct event		 ev_eapt;
135 };
136 
137 /* Attributes copied from CHAP Access-Accept to EAP Access-Access-Accept */
138 struct preserve_attrs {
139 	uint8_t		type;
140 	uint32_t	vendor;
141 } preserve_attrs[] = {
142 	{ RADIUS_TYPE_FRAMED_PROTOCOL,		0},
143 	{ RADIUS_TYPE_FRAMED_IP_ADDRESS,	0},
144 	{ RADIUS_TYPE_FRAMED_IP_NETMASK,	0},
145 	{ RADIUS_TYPE_FRAMED_IPV6_ADDRESS,	0},
146 	{ RADIUS_TYPE_DNS_SERVER_IPV6_ADDRESS,	0},
147 	{ RADIUS_TYPE_FRAMED_ROUTING,		0},
148 	{ RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
149 	{ RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
150 	{ RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
151 	{ RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,RADIUS_VENDOR_MICROSOFT },
152 	{ RADIUS_VTYPE_MPPE_SEND_KEY,		RADIUS_VENDOR_MICROSOFT },
153 	{ RADIUS_VTYPE_MPPE_RECV_KEY, 		RADIUS_VENDOR_MICROSOFT }
154 };
155 
156 #ifndef EAP2MSCHAP_DEBUG
157 #define	EAP2MSCHAP_DBG(...)
158 #define	EAP2MSCHAP_ASSERT(_cond)
159 #else
160 #define	EAP2MSCHAP_DBG(...)	logit(LOG_DEBUG, __VA_ARGS__)
161 #define	EAP2MSCHAP_ASSERT(_cond)				\
162 	do {							\
163 		if (!(_cond)) {					\
164 			log_warnx(				\
165 			    "ASSERT(%s) failed in %s() at %s:%d",\
166 			    #_cond, __func__, __FILE__, __LINE__);\
167 			abort();				\
168 		}						\
169 	} while (0/* CONSTCOND */);
170 #endif
171 #ifndef nitems
172 #define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
173 #endif
174 
175 static void	 eap2mschap_init(struct eap2mschap *);
176 static void	 eap2mschap_start(void *);
177 static void	 eap2mschap_config_set(void *, const char *, int,
178 		    char * const *);
179 static void	 eap2mschap_stop(void *);
180 static void	 eap2mschap_access_request(void *, u_int, const u_char *,
181 		    size_t);
182 static void	 eap2mschap_next_response(void *, u_int, const u_char *,
183 		    size_t);
184 
185 static void	 eap2mschap_on_eapt (int, short, void *);
186 static void	 eap2mschap_reset_eaptimer (struct eap2mschap *);
187 
188 static struct access_req
189 		*access_request_new(struct eap2mschap *, u_int);
190 static void	 access_request_free(struct access_req *);
191 static int	 access_request_compar(struct access_req *,
192 		    struct access_req *);
193 
194 
195 static struct access_req
196 		*eap_recv(struct eap2mschap *, u_int, RADIUS_PACKET *);
197 static struct access_req
198 		*eap_recv_mschap(struct eap2mschap *, struct access_req *,
199 		    RADIUS_PACKET *, struct eap_chap *);
200 static void	 eap_resp_mschap(struct eap2mschap *, struct access_req *,
201 		    RADIUS_PACKET *);
202 static void	 eap_send_reject(struct access_req *, RADIUS_PACKET *, u_int);
203 static const char
204 		*eap_chap_status_string(enum eap_chap_status);
205 static const char
206 		*hex_string(const char *, size_t, char *, size_t);
207 static time_t	 monotime(void);
208 
209 RB_PROTOTYPE_STATIC(access_reqt, access_req, tree, access_request_compar);
210