summaryrefslogtreecommitdiff
path: root/usr.sbin/radiusd/eap2mschap_local.h
blob: 7db1e20ab5bb6f9e13529686e047f61400ba3640 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*	$OpenBSD: eap2mschap_local.h,v 1.3 2024/09/15 05:49:05 jsg Exp $	*/

/*
 * Copyright (c) 2024 Internet Initiative Japan Inc.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#define	EAP_CODE_REQUEST	1
#define	EAP_CODE_RESPONSE	2
#define	EAP_CODE_SUCCESS	3
#define	EAP_CODE_FAILURE	4

#define	EAP_TYPE_IDENTITY	1
#define	EAP_TYPE_NOTIFICATION	2
#define	EAP_TYPE_NAK		3
#define	EAP_TYPE_MSCHAPV2	0x1a	/* [MS-CHAP] MS-EAP-Authentication */

#define CHAP_CHALLENGE		1
#define CHAP_RESPONSE		2
#define CHAP_SUCCESS		3
#define CHAP_FAILURE		4

/* From [MS-CHAP] */
enum eap_chap_status {
	EAP_CHAP_NONE,
	EAP_CHAP_CHALLENGE_SENT,
	EAP_CHAP_SUCCESS_REQUEST_SENT,
	EAP_CHAP_FAILURE_REQUEST_SENT,
	EAP_CHAP_CHANGE_PASSWORD_SENT,
	EAP_CHAP_FAILED,
	EAP_CHAP_SUCCESS
};

struct eap {
	uint8_t		code;
	uint8_t		id;
	uint16_t	length;
	uint8_t		value[0];
} __packed;

struct chap {
	uint8_t		code;
	uint8_t		id;
	uint16_t	length;
	int8_t		value[0];
} __packed;

struct eap_chap {
	struct eap	eap;
	uint8_t		eap_type;
	struct chap	chap;
};

struct eap_mschap_challenge {
	struct eap	eap;
	uint8_t		eap_type;
	struct chap	chap;
	uint8_t		challsiz;
	uint8_t		chall[16];
	char		chap_name[0];
} __packed;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
static_assert(sizeof(struct eap_mschap_challenge) == 26, "");
static_assert(offsetof(struct eap_mschap_challenge, chap) == 5, "");
static_assert(offsetof(struct eap_mschap_challenge, chall) == 10, "");
#endif

struct eap_mschap_response {
	struct eap	eap;
	uint8_t		eap_type;
	struct chap	chap;
	uint8_t		challsiz;
	uint8_t		peerchall[16];
	uint8_t		reserved[8];
	uint8_t		ntresponse[24];
	uint8_t		flags;
	uint8_t		chap_name[0];
} __packed;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
static_assert(sizeof(struct eap_mschap_response) == 59, "");
static_assert(offsetof(struct eap_mschap_response, chap) == 5, "");
static_assert(offsetof(struct eap_mschap_response, peerchall) == 10, "");
#endif

struct radius_ms_chap2_response {
	uint8_t		ident;
	uint8_t		flags;
	uint8_t		peerchall[16];
	uint8_t		reserved[8];
	uint8_t		ntresponse[24];
} __packed;


struct eap2mschap;

struct access_req {
	struct eap2mschap	*eap2mschap;
	char			*username;
	u_int			 q_id;
	TAILQ_ENTRY(access_req)	 next;
	RB_ENTRY(access_req)	 tree;
	/* for EAP */
	enum eap_chap_status	 eap_chap_status;
	char			 state[16];
	unsigned char		 chap_id;
	unsigned char		 eap_id;
	time_t			 eap_time;
	char			 chall[16];
	RADIUS_PACKET		*pkt;

};
TAILQ_HEAD(access_reqq, access_req);
RB_HEAD(access_reqt, access_req);

#define CHAP_NAME_MAX			40

struct eap2mschap {
	struct module_base	*base;
	char			*secret;
	char			 chap_name[CHAP_NAME_MAX + 1];
	struct access_reqq	 reqq;
	struct access_reqt	 eapt;
	struct event		 ev_eapt;
};

/* Attributes copied from CHAP Access-Accept to EAP Access-Access-Accept */
struct preserve_attrs {
	uint8_t		type;
	uint32_t	vendor;
} preserve_attrs[] = {
	{ RADIUS_TYPE_FRAMED_PROTOCOL,		0},
	{ RADIUS_TYPE_FRAMED_IP_ADDRESS,	0},
	{ RADIUS_TYPE_FRAMED_IP_NETMASK,	0},
	{ RADIUS_TYPE_FRAMED_IPV6_ADDRESS,	0},
	{ RADIUS_TYPE_DNS_SERVER_IPV6_ADDRESS,	0},
	{ RADIUS_TYPE_FRAMED_ROUTING,		0},
	{ RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
	{ RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
	{ RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER,	RADIUS_VENDOR_MICROSOFT },
	{ RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,RADIUS_VENDOR_MICROSOFT },
	{ RADIUS_VTYPE_MPPE_SEND_KEY,		RADIUS_VENDOR_MICROSOFT },
	{ RADIUS_VTYPE_MPPE_RECV_KEY, 		RADIUS_VENDOR_MICROSOFT }
};

#ifndef EAP2MSCHAP_DEBUG
#define	EAP2MSCHAP_DBG(...)
#define	EAP2MSCHAP_ASSERT(_cond)
#else
#define	EAP2MSCHAP_DBG(...)	logit(LOG_DEBUG, __VA_ARGS__)
#define	EAP2MSCHAP_ASSERT(_cond)				\
	do {							\
		if (!(_cond)) {					\
			log_warnx(				\
			    "ASSERT(%s) failed in %s() at %s:%d",\
			    #_cond, __func__, __FILE__, __LINE__);\
			abort();				\
		}						\
	} while (0/* CONSTCOND */);
#endif
#ifndef nitems
#define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
#endif

static void	 eap2mschap_init(struct eap2mschap *);
static void	 eap2mschap_start(void *);
static void	 eap2mschap_config_set(void *, const char *, int,
		    char * const *);
static void	 eap2mschap_stop(void *);
static void	 eap2mschap_access_request(void *, u_int, const u_char *,
		    size_t);
static void	 eap2mschap_next_response(void *, u_int, const u_char *,
		    size_t);

static void	 eap2mschap_on_eapt (int, short, void *);
static void	 eap2mschap_reset_eaptimer (struct eap2mschap *);

static struct access_req
		*access_request_new(struct eap2mschap *, u_int);
static void	 access_request_free(struct access_req *);
static int	 access_request_compar(struct access_req *,
		    struct access_req *);


static struct access_req
		*eap_recv(struct eap2mschap *, u_int, RADIUS_PACKET *);
static struct access_req
		*eap_recv_mschap(struct eap2mschap *, struct access_req *,
		    RADIUS_PACKET *, struct eap_chap *);
static void	 eap_resp_mschap(struct eap2mschap *, struct access_req *,
		    RADIUS_PACKET *);
static void	 eap_send_reject(struct access_req *, RADIUS_PACKET *, u_int);
static const char
		*eap_chap_status_string(enum eap_chap_status);
static const char
		*hex_string(const char *, size_t, char *, size_t);
static time_t	 monotime(void);

RB_PROTOTYPE_STATIC(access_reqt, access_req, tree, access_request_compar);