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);
|