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