diff options
Diffstat (limited to 'accel-pppd/ctrl/l2tp/l2tp.c')
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 113 |
1 files changed, 84 insertions, 29 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index eed750a9..a3e829e7 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -98,7 +98,7 @@ struct l2tp_conn_t uint16_t peer_tid; uint32_t framing_cap; uint16_t challenge_len; - l2tp_value_t challenge; + uint8_t *challenge; int retransmit; uint16_t Ns, Nr; @@ -126,6 +126,21 @@ static int l2tp_conn_read(struct triton_md_handler_t *); static void l2tp_tunnel_session_freed(void *data); +static inline void comp_chap_md5(uint8_t *md5, uint8_t ident, + const void *secret, size_t secret_len, + const void *chall, size_t chall_len) +{ + MD5_CTX md5_ctx; + + memset(md5, 0, MD5_DIGEST_LENGTH); + + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &ident, sizeof(ident)); + MD5_Update(&md5_ctx, secret, secret_len); + MD5_Update(&md5_ctx, chall, chall_len); + MD5_Final(md5, &md5_ctx); +} + static inline struct l2tp_conn_t *l2tp_tunnel_self(void) { return container_of(triton_context_self(), struct l2tp_conn_t, ctx); @@ -136,7 +151,8 @@ static inline struct l2tp_sess_t *l2tp_session_self(void) return container_of(triton_context_self(), struct l2tp_sess_t, sctx); } -static void l2tp_conn_log(void (*print)(const char *fmt, ...), struct l2tp_conn_t *conn) +static void l2tp_conn_log(void (*print)(const char *fmt, ...), + const struct l2tp_conn_t *conn) { char addr[17]; @@ -164,6 +180,52 @@ static struct l2tp_sess_t *l2tp_tunnel_get_session(struct l2tp_conn_t *conn, return (res) ? *res : NULL; } +static int l2tp_tunnel_storechall(struct l2tp_conn_t *conn, + const struct l2tp_attr_t *chall) +{ + void *ptr = NULL; + + if (chall == NULL) { + if (conn->challenge) { + _free(conn->challenge); + conn->challenge = NULL; + } + conn->challenge_len = 0; + return 0; + } + + if (conf_secret == NULL || strlen(conf_secret) == 0) { + l2tp_conn_log(log_error, conn); + log_error("l2tp: Authentication required by peer," + " but no secret has been set for this tunnel\n"); + goto err; + } + + if (conn->challenge_len != chall->length) { + ptr = realloc(conn->challenge, chall->length); + if (ptr == NULL) { + l2tp_conn_log(log_error, conn); + log_error("l2tp: Impossible to store received" + " challenge: Memory allocation failed\n"); + goto err; + } + conn->challenge = ptr; + conn->challenge_len = chall->length; + } + + memcpy(conn->challenge, chall->val.octets, chall->length); + + return 0; + +err: + if (conn->challenge) { + _free(conn->challenge); + conn->challenge = NULL; + } + conn->challenge_len = 0; + return -1; +} + static int l2tp_send_StopCCN(struct l2tp_conn_t *conn, uint16_t res, uint16_t err) { @@ -382,8 +444,8 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) l2tp_packet_free(pack); } - if (conn->challenge_len) - _free(conn->challenge.octets); + if (conn->challenge) + _free(conn->challenge); mempool_free(conn); } @@ -590,8 +652,7 @@ out_err: static struct l2tp_conn_t *l2tp_tunnel_alloc(struct l2tp_serv_t *serv, const struct sockaddr_in *peer, const struct sockaddr_in *host, - uint32_t framing_cap, - struct l2tp_attr_t *challenge) + uint32_t framing_cap) { struct l2tp_conn_t *conn; uint16_t tid; @@ -676,23 +737,6 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(struct l2tp_serv_t *serv, memcpy(&conn->lns_addr, host, sizeof(*host)); conn->framing_cap = framing_cap; - /* If challenge set in SCCRQ, we need to calculate response for SCCRP */ - if (challenge && challenge->length <= 16) { - char state = 2; /* SCCRP, TODO: define them in some .h? */ - MD5_CTX md5_ctx; - uint8_t md5[MD5_DIGEST_LENGTH]; - - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, &state, 1); - MD5_Update(&md5_ctx, conf_secret, strlen(conf_secret)); - MD5_Update(&md5_ctx, challenge->val.octets, challenge->length); - MD5_Final(md5, &md5_ctx); - - conn->challenge_len = MD5_DIGEST_LENGTH; - conn->challenge.octets = _malloc(MD5_DIGEST_LENGTH); - memcpy(conn->challenge.octets, &md5, MD5_DIGEST_LENGTH); - } - conn->ctx.before_switch = log_switch; conn->ctx.close = l2tp_conn_close; conn->hnd.read = l2tp_conn_read; @@ -957,6 +1001,7 @@ static void l2tp_send_HELLO(struct triton_timer_t *t) static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) { struct l2tp_packet_t *pack; + uint8_t chall_resp[MD5_DIGEST_LENGTH]; pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Reply, &conn->lac_addr); if (!pack) @@ -973,9 +1018,15 @@ static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) if (l2tp_packet_add_string(pack, Vendor_Name, "accel-ppp", 0)) goto out_err; /* If challenge response available */ - if (conn->challenge_len) { - if (l2tp_packet_add_octets(pack, Challenge_Response, conn->challenge.octets, 16, 1)) - goto out_err; + if (conn->challenge_len && conn->challenge) { + if (conf_secret == NULL || strlen(conf_secret) == 0) + goto out_err; + comp_chap_md5(chall_resp, Message_Type_Start_Ctrl_Conn_Reply, + conf_secret, strlen(conf_secret), + conn->challenge, conn->challenge_len); + if (l2tp_packet_add_octets(pack, Challenge_Response, + chall_resp, MD5_DIGEST_LENGTH, 1)) + goto out_err; } if (l2tp_send(conn, pack, 0)) @@ -1132,7 +1183,7 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, host_addr.sin_port = 0; conn = l2tp_tunnel_alloc(serv, &pack->addr, &host_addr, - framing_cap->val.uint32, challenge); + framing_cap->val.uint32); if (conn == NULL) return -1; @@ -1142,6 +1193,11 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, l2tp_packet_print(pack, log_ppp_info2); } + if (l2tp_tunnel_storechall(conn, challenge) < 0) { + l2tp_tunnel_free(conn); + return -1; + } + conn->peer_tid = assigned_tid->val.uint16; if (l2tp_tunnel_start(conn, (triton_event_func)l2tp_send_SCCRP, conn) < 0) { @@ -1158,10 +1214,9 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, return -1; } - if (conf_secret && !challenge) { + if (conf_secret && strlen(conf_secret) > 0 && conn->challenge == NULL) { if (conf_verbose) log_warn("l2tp: SCCRQ: no Challenge present in message\n"); - return -1; } return 0; |