diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2011-01-05 15:18:59 +0300 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2011-01-05 15:18:59 +0300 |
commit | f28cb1b0a926f1ea98700b7871537ad1793511fd (patch) | |
tree | baf35570bc6b38b6fab5b6524e8f19f58f71e57f /accel-pppd/auth | |
parent | 2fdf3586c13a72c36f9530084962e29d57dc0329 (diff) | |
download | accel-ppp-f28cb1b0a926f1ea98700b7871537ad1793511fd.tar.gz accel-ppp-f28cb1b0a926f1ea98700b7871537ad1793511fd.zip |
rename accel-pptp to accel-ppp
Diffstat (limited to 'accel-pppd/auth')
-rw-r--r-- | accel-pppd/auth/CMakeLists.txt | 13 | ||||
-rw-r--r-- | accel-pppd/auth/auth_chap_md5.c | 427 | ||||
-rw-r--r-- | accel-pppd/auth/auth_mschap_v1.c | 517 | ||||
-rw-r--r-- | accel-pppd/auth/auth_mschap_v2.c | 639 | ||||
-rw-r--r-- | accel-pppd/auth/auth_pap.c | 273 |
5 files changed, 1869 insertions, 0 deletions
diff --git a/accel-pppd/auth/CMakeLists.txt b/accel-pppd/auth/CMakeLists.txt new file mode 100644 index 00000000..ef9478aa --- /dev/null +++ b/accel-pppd/auth/CMakeLists.txt @@ -0,0 +1,13 @@ +ADD_LIBRARY(auth_pap SHARED auth_pap.c) +ADD_LIBRARY(auth_chap_md5 SHARED auth_chap_md5.c) +ADD_LIBRARY(auth_mschap_v1 SHARED auth_mschap_v1.c) +ADD_LIBRARY(auth_mschap_v2 SHARED auth_mschap_v2.c) + +TARGET_LINK_LIBRARIES(auth_chap_md5 crypto) +TARGET_LINK_LIBRARIES(auth_mschap_v1 crypto) +TARGET_LINK_LIBRARIES(auth_mschap_v2 crypto) + +INSTALL(TARGETS auth_pap auth_chap_md5 auth_mschap_v1 auth_mschap_v2 + LIBRARY DESTINATION lib/accel-ppp +) + diff --git a/accel-pppd/auth/auth_chap_md5.c b/accel-pppd/auth/auth_chap_md5.c new file mode 100644 index 00000000..d19634a5 --- /dev/null +++ b/accel-pppd/auth/auth_chap_md5.c @@ -0,0 +1,427 @@ +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <arpa/inet.h> + +#include <openssl/md5.h> + +#include "log.h" +#include "ppp.h" +#include "ppp_auth.h" +#include "ppp_lcp.h" +#include "pwdb.h" + +#include "memdebug.h" + +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +#define CHAP_MD5 5 + +#define VALUE_SIZE 16 + +#define MSG_FAILURE "Authentication failed" +#define MSG_SUCCESS "Authentication successed" + +#define HDR_LEN (sizeof(struct chap_hdr_t)-2) + +static int conf_timeout = 5; +static int conf_interval = 0; +static int conf_max_failure = 3; +static int conf_any_login = 0; + +static int urandom_fd; + +struct chap_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); + +struct chap_challenge_t +{ + struct chap_hdr_t hdr; + uint8_t val_size; + uint8_t val[VALUE_SIZE]; + char name[0]; +} __attribute__((packed)); + +struct chap_failure_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_FAILURE)]; +} __attribute__((packed)); + +struct chap_success_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_SUCCESS)]; +} __attribute__((packed)); + + +struct chap_auth_data_t +{ + struct auth_data_t auth; + struct ppp_handler_t h; + struct ppp_t *ppp; + int id; + uint8_t val[VALUE_SIZE]; + struct triton_timer_t timeout; + struct triton_timer_t interval; + int failure; + int started:1; +}; + +static void chap_send_challenge(struct chap_auth_data_t *ad); +static void chap_recv(struct ppp_handler_t *h); +static void chap_timeout_timer(struct triton_timer_t *t); +static void chap_restart_timer(struct triton_timer_t *t); + +static void print_buf(const uint8_t *buf, int size) +{ + int i; + for (i=0; i < size; i++) + log_ppp_info2("%x", buf[i]); +} +static void print_str(const char *buf, int size) +{ + int i; + for (i = 0; i < size; i++) + log_ppp_info2("%c", buf[i]); +} + +static struct auth_data_t* auth_data_init(struct ppp_t *ppp) +{ + struct chap_auth_data_t *d = _malloc(sizeof(*d)); + + memset(d, 0, sizeof(*d)); + d->auth.proto = PPP_CHAP; + d->ppp = ppp; + + return &d->auth; +} + +static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + _free(d); +} + +static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + d->h.proto = PPP_CHAP; + d->h.recv = chap_recv; + d->timeout.expire = chap_timeout_timer; + d->timeout.period = conf_timeout * 1000; + d->interval.expire = chap_restart_timer; + d->interval.period = conf_interval * 1000; + + ppp_register_chan_handler(ppp, &d->h); + + chap_send_challenge(d); + + return 0; +} + +static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + ppp_unregister_handler(ppp, &d->h); + + return 0; +} + +static void chap_timeout_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + + if (conf_ppp_verbose) + log_ppp_warn("chap-md5: timeout\n"); + + if (++d->failure == conf_max_failure) { + if (d->started) + ppp_terminate(d->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(d->ppp, NULL); + } else { + --d->id; + chap_send_challenge(d); + } +} + +static void chap_restart_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + + chap_send_challenge(d); +} + +static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + *ptr = CHAP_MD5; + return 1; +} + +static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + if (*ptr == CHAP_MD5) + return LCP_OPT_ACK; + return LCP_OPT_NAK; +} + +static void chap_send_failure(struct chap_auth_data_t *ad) +{ + struct chap_failure_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_FAILURE, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg) - 1 - 2), + .message = MSG_FAILURE, + }; + + if (conf_ppp_verbose) + log_ppp_info2("send [CHAP Failure id=%x \"%s\"]\n", msg.hdr.id, MSG_FAILURE); + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); +} + +static void chap_send_success(struct chap_auth_data_t *ad) +{ + struct chap_success_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_SUCCESS, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg)-1-2), + .message = MSG_SUCCESS, + }; + + if (conf_ppp_verbose) + log_ppp_info2("send [CHAP Success id=%x \"%s\"]\n", msg.hdr.id, MSG_SUCCESS); + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); +} + +static void chap_send_challenge(struct chap_auth_data_t *ad) +{ + struct chap_challenge_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_CHALLENGE, + .hdr.id = ++ad->id, + .hdr.len = htons(sizeof(msg) - 2), + .val_size = VALUE_SIZE, + }; + + read(urandom_fd, ad->val, VALUE_SIZE); + memcpy(msg.val, ad->val, VALUE_SIZE); + + if (conf_ppp_verbose) { + log_ppp_info2("send [CHAP Challenge id=%x <", msg.hdr.id); + print_buf(msg.val, VALUE_SIZE); + log_ppp_info2(">]\n"); + } + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); + + if (conf_timeout && !ad->timeout.tpd) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->timeout, 0); +} + +static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +{ + MD5_CTX md5_ctx; + uint8_t md5[MD5_DIGEST_LENGTH]; + char *passwd; + char *name; + int r; + struct chap_challenge_t *msg = (struct chap_challenge_t*)hdr; + + if (ad->timeout.tpd) + triton_timer_del(&ad->timeout); + + if (conf_ppp_verbose) { + log_ppp_info2("recv [CHAP Response id=%x <", msg->hdr.id); + print_buf(msg->val, msg->val_size); + log_ppp_info2(">, name=\""); + print_str(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); + log_ppp_info2("\"]\n"); + } + + if (msg->hdr.id != ad->id) { + if (conf_ppp_verbose) + log_ppp_error("chap-md5: id mismatch\n"); + chap_send_failure(ad); + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + } + + if (msg->val_size != VALUE_SIZE) { + log_ppp_error("chap-md5: incorrect value-size (%i)\n", msg->val_size); + chap_send_failure(ad); + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + } + + name = _strndup(msg->name,ntohs(msg->hdr.len) - sizeof(*msg) + 2); + + if (conf_any_login) { + chap_send_success(ad); + ad->started = 1; + ppp_auth_successed(ad->ppp, name); + return; + } + + r = pwdb_check(ad->ppp, name, PPP_CHAP, CHAP_MD5, ad->id, ad->val, VALUE_SIZE, msg->val); + + if (r == PWDB_NO_IMPL) { + passwd = pwdb_get_passwd(ad->ppp,name); + if (!passwd) + { + _free(name); + if (conf_ppp_verbose) + log_ppp_warn("chap-md5: user not found\n"); + chap_send_failure(ad); + return; + } + + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx,&msg->hdr.id,1); + MD5_Update(&md5_ctx,passwd,strlen(passwd)); + MD5_Update(&md5_ctx,ad->val,VALUE_SIZE); + MD5_Final(md5,&md5_ctx); + + if (memcmp(md5,msg->val,sizeof(md5))) + { + if (conf_ppp_verbose) + log_ppp_warn("chap-md5: challenge response mismatch\n"); + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + _free(name); + } else { + chap_send_success(ad); + if (!ad->started) { + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); + ppp_auth_successed(ad->ppp, name); + } else + _free(name); + } + _free(passwd); + } else if (r == PWDB_DENIED) { + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + _free(name); + } else { + chap_send_success(ad); + if (!ad->started) { + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); + ppp_auth_successed(ad->ppp, name); + } else + _free(name); + } +} + +static int chap_check(uint8_t *ptr) +{ + return *ptr == CHAP_MD5; +} + +static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + chap_send_challenge(d); + + return 0; +} + +static struct ppp_auth_handler_t chap= +{ + .name = "CHAP-md5", + .init = auth_data_init, + .free = auth_data_free, + .send_conf_req = lcp_send_conf_req, + .recv_conf_req = lcp_recv_conf_req, + .start = chap_start, + .finish = chap_finish, + .check = chap_check, + .restart = chap_restart, +}; + +static void chap_recv(struct ppp_handler_t *h) +{ + struct chap_auth_data_t *d = container_of(h, typeof(*d), h); + struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->chan_buf; + + if (d->ppp->chan_buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->chan_buf_size - 2) { + log_ppp_warn("chap-md5: short packet received\n"); + return; + } + + if (hdr->code == CHAP_RESPONSE) + chap_recv_response(d, hdr); + else + log_ppp_warn("chap-md5: unknown code received %x\n", hdr->code); +} + +static void __init auth_chap_md5_init() +{ + char *opt; + + opt = conf_get_opt("auth", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); + + opt = conf_get_opt("auth", "interval"); + if (opt && atoi(opt) > 0) + conf_interval = atoi(opt); + + opt = conf_get_opt("auth", "max-failure"); + if (opt && atoi(opt) > 0) + conf_max_failure = atoi(opt); + + opt = conf_get_opt("auth", "any-login"); + if (opt && atoi(opt) > 0) + conf_any_login = 1; + + urandom_fd=open("/dev/urandom", O_RDONLY); + + if (urandom_fd < 0) { + log_emerg("chap-md5: failed to open /dev/urandom: %s\n", strerror(errno)); + return; + } + + if (ppp_auth_register_handler(&chap)) + log_emerg("chap-md5: failed to register handler\n"); +} + diff --git a/accel-pppd/auth/auth_mschap_v1.c b/accel-pppd/auth/auth_mschap_v1.c new file mode 100644 index 00000000..5b38db54 --- /dev/null +++ b/accel-pppd/auth/auth_mschap_v1.c @@ -0,0 +1,517 @@ +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <byteswap.h> +#include <arpa/inet.h> + +#include <openssl/md4.h> +#include <openssl/des.h> +#include <openssl/sha.h> + +#include "log.h" +#include "ppp.h" +#include "events.h" +#include "ppp_auth.h" +#include "ppp_lcp.h" +#include "pwdb.h" + +#include "memdebug.h" + +#define MSCHAP_V1 0x80 + +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +#define VALUE_SIZE 8 +#define RESPONSE_VALUE_SIZE (24+24+1) + +#define MSG_FAILURE "E=691 R=0" +#define MSG_SUCCESS "Authentication successed" + +#define HDR_LEN (sizeof(struct chap_hdr_t)-2) + +static int conf_timeout = 5; +static int conf_interval = 0; +static int conf_max_failure = 3; +static int conf_any_login = 0; + +static int urandom_fd; + +struct chap_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); + +struct chap_challenge_t +{ + struct chap_hdr_t hdr; + uint8_t val_size; + uint8_t val[VALUE_SIZE]; + char name[0]; +} __attribute__((packed)); + +struct chap_response_t +{ + struct chap_hdr_t hdr; + uint8_t val_size; + uint8_t lm_hash[24]; + uint8_t nt_hash[24]; + uint8_t flags; + char name[0]; +} __attribute__((packed)); + +struct chap_failure_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_FAILURE)]; +} __attribute__((packed)); + +struct chap_success_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_SUCCESS)]; +} __attribute__((packed)); + + +struct chap_auth_data_t +{ + struct auth_data_t auth; + struct ppp_handler_t h; + struct ppp_t *ppp; + int id; + uint8_t val[VALUE_SIZE]; + struct triton_timer_t timeout; + struct triton_timer_t interval; + int failure; + int started:1; +}; + +static void chap_send_challenge(struct chap_auth_data_t *ad); +static void chap_recv(struct ppp_handler_t *h); +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *res, const char *name); +static void chap_timeout_timer(struct triton_timer_t *t); +static void chap_restart_timer(struct triton_timer_t *t); +static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash); + +static void print_buf(const uint8_t *buf,int size) +{ + int i; + for (i = 0; i < size; i++) + log_ppp_info2("%x", buf[i]); +} +static void print_str(const char *buf, int size) +{ + int i; + for(i = 0; i < size; i++) + log_ppp_info2("%c", buf[i]); +} + +static struct auth_data_t* auth_data_init(struct ppp_t *ppp) +{ + struct chap_auth_data_t *d = _malloc(sizeof(*d)); + + memset(d, 0, sizeof(*d)); + d->auth.proto = PPP_CHAP; + d->ppp = ppp; + + return &d->auth; +} + +static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + _free(d); +} + +static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + d->h.proto = PPP_CHAP; + d->h.recv = chap_recv; + d->timeout.expire = chap_timeout_timer; + d->timeout.period = conf_timeout * 1000; + d->interval.expire = chap_restart_timer; + d->interval.period = conf_interval * 1000; + + ppp_register_chan_handler(ppp, &d->h); + + chap_send_challenge(d); + + return 0; +} + +static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + ppp_unregister_handler(ppp, &d->h); + + return 0; +} + +static void chap_timeout_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + + if (conf_ppp_verbose) + log_ppp_warn("mschap-v1: timeout\n"); + + if (++d->failure == conf_max_failure) { + if (d->started) + ppp_terminate(d->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(d->ppp, NULL); + } else { + --d->id; + chap_send_challenge(d); + } +} + +static void chap_restart_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + + chap_send_challenge(d); +} + +static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + *ptr = MSCHAP_V1; + return 1; +} + +static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + if (*ptr == MSCHAP_V1) + return LCP_OPT_ACK; + return LCP_OPT_NAK; +} + +static void chap_send_failure(struct chap_auth_data_t *ad) +{ + struct chap_failure_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_FAILURE, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg)-1-2), + .message = MSG_FAILURE, + }; + + if (conf_ppp_verbose) + log_ppp_info2("send [MSCHAP-v1 Failure id=%x \"%s\"]\n", msg.hdr.id, MSG_FAILURE); + + ppp_chan_send(ad->ppp,&msg,ntohs(msg.hdr.len)+2); +} + +static void chap_send_success(struct chap_auth_data_t *ad) +{ + struct chap_success_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_SUCCESS, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg)-1-2), + .message = MSG_SUCCESS, + }; + + if (conf_ppp_verbose) + log_ppp_info2("send [MSCHAP-v1 Success id=%x \"%s\"]\n", msg.hdr.id, MSG_SUCCESS); + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); +} + +static void chap_send_challenge(struct chap_auth_data_t *ad) +{ + struct chap_challenge_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_CHALLENGE, + .hdr.id = ++ad->id, + .hdr.len = htons(sizeof(msg) - 2), + .val_size = VALUE_SIZE, + }; + + read(urandom_fd, ad->val, VALUE_SIZE); + memcpy(msg.val, ad->val, VALUE_SIZE); + + if (conf_ppp_verbose) { + log_ppp_info2("send [MSCHAP-v1 Challenge id=%x <", msg.hdr.id); + print_buf(msg.val, VALUE_SIZE); + log_ppp_info2(">]\n"); + } + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); + + if (conf_timeout && !ad->timeout.tpd) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->timeout, 0); +} + +static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +{ + struct chap_response_t *msg = (struct chap_response_t*)hdr; + char *name; + int r; + + if (ad->timeout.tpd) + triton_timer_del(&ad->timeout); + + if (conf_ppp_verbose) { + log_ppp_info2("recv [MSCHAP-v1 Response id=%x <", msg->hdr.id); + print_buf(msg->lm_hash, 24); + log_ppp_info2(">, <"); + print_buf(msg->nt_hash, 24); + log_ppp_info2(">, F=%i, name=\"", msg->flags); + print_str(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); + log_ppp_info2("\"]\n"); + } + + if (msg->hdr.id != ad->id) { + if (conf_ppp_verbose) + log_ppp_error("mschap-v1: id mismatch\n"); + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + } + + if (msg->val_size != RESPONSE_VALUE_SIZE) { + log_ppp_error("mschap-v1: incorrect value-size (%i)\n", msg->val_size); + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + } + + name = _strndup(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); + if (!name) { + log_emerg("mschap-v1: out of memory\n"); + if (ad->started) + ppp_terminate(ad->ppp, TERM_NAS_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + return; + } + + if (conf_any_login) { + chap_send_success(ad); + ad->started = 1; + ppp_auth_successed(ad->ppp, name); + return; + } + + r = pwdb_check(ad->ppp, name, PPP_CHAP, MSCHAP_V1, ad->id, ad->val, VALUE_SIZE, msg->lm_hash, msg->nt_hash, msg->flags); + if (r == PWDB_NO_IMPL) + if (chap_check_response(ad, msg, name)) + r = PWDB_DENIED; + + if (r == PWDB_DENIED) { + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + _free(name); + } else { + chap_send_success(ad); + if (!ad->started) { + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); + ppp_auth_successed(ad->ppp, name); + } else + _free(name); + } +} + +static void des_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *output) +{ + int i, j, parity; + union + { + uint64_t u64; + uint8_t buf[8]; + } p_key; + DES_cblock cb; + DES_cblock res; + DES_key_schedule ks; + + memcpy(p_key.buf, key, 7); + p_key.u64 = bswap_64(p_key.u64); + + for (i = 0; i < 8; i++) { + cb[i] = (((p_key.u64 << (7 * i)) >> 56) & 0xfe); + for( j = 0, parity = 0; j < 7; j++) + if ((cb[i] >> (j + 1)) & 1) + parity++; + cb[i] |= (~parity) & 1; + } + + DES_set_key_checked(&cb, &ks); + memcpy(cb, input, 8); + DES_ecb_encrypt(&cb, &res, &ks, DES_ENCRYPT); + memcpy(output, res, 8); +} + +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name) +{ + MD4_CTX md4_ctx; + uint8_t z_hash[21]; + uint8_t nt_hash[24]; + char *passwd; + char *u_passwd; + int i; + + passwd = pwdb_get_passwd(ad->ppp,name); + if (!passwd) { + if (conf_ppp_verbose) + log_ppp_warn("mschap-v1: user not found\n"); + chap_send_failure(ad); + return PWDB_DENIED; + } + + u_passwd = _malloc(strlen(passwd) * 2); + for (i = 0; i< strlen(passwd); i++) { + u_passwd[i * 2] = passwd[i]; + u_passwd[i * 2 + 1] = 0; + } + + memset(z_hash, 0, sizeof(z_hash)); + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx, u_passwd, strlen(passwd) * 2); + MD4_Final(z_hash, &md4_ctx); + + des_encrypt(ad->val, z_hash, nt_hash); + des_encrypt(ad->val, z_hash + 7, nt_hash + 8); + des_encrypt(ad->val, z_hash + 14, nt_hash + 16); + + set_mppe_keys(ad, z_hash); + + _free(passwd); + _free(u_passwd); + + return memcmp(nt_hash, msg->nt_hash, 24) ? PWDB_DENIED : PWDB_SUCCESS; +} + +static int chap_check(uint8_t *ptr) +{ + return *ptr == MSCHAP_V1; +} + +static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash) +{ + MD4_CTX md4_ctx; + SHA_CTX sha_ctx; + uint8_t digest[20]; + + struct ev_mppe_keys_t ev_mppe = { + .ppp = ad->ppp, + .type = 1 << 2, + .policy = 1, + .recv_key = digest, + .send_key = digest, + }; + + //NtPasswordHashHash + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx, z_hash, 16); + MD4_Final(digest, &md4_ctx); + + //Get_Start_Key + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, digest, 16); + SHA1_Update(&sha_ctx, digest, 16); + SHA1_Update(&sha_ctx, ad->val, VALUE_SIZE); + SHA1_Final(digest, &sha_ctx); + + triton_event_fire(EV_MPPE_KEYS, &ev_mppe); +} + +static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + chap_send_challenge(d); + + return 0; +} + +static struct ppp_auth_handler_t chap = { + .name = "MSCHAP-v1", + .init = auth_data_init, + .free = auth_data_free, + .send_conf_req = lcp_send_conf_req, + .recv_conf_req = lcp_recv_conf_req, + .start = chap_start, + .finish = chap_finish, + .check = chap_check, + .restart = chap_restart, +}; + +static void chap_recv(struct ppp_handler_t *h) +{ + struct chap_auth_data_t *d = container_of(h, typeof(*d), h); + struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->chan_buf; + + if (d->ppp->chan_buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->chan_buf_size - 2) { + log_ppp_warn("mschap-v1: short packet received\n"); + return; + } + + if (hdr->code == CHAP_RESPONSE) + chap_recv_response(d, hdr); + else + log_ppp_warn("mschap-v1: unknown code received %x\n", hdr->code); +} + +static void __init auth_mschap_v1_init() +{ + char *opt; + + opt = conf_get_opt("auth", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); + + opt = conf_get_opt("auth", "interval"); + if (opt && atoi(opt) > 0) + conf_interval = atoi(opt); + + opt = conf_get_opt("auth", "max-failure"); + if (opt && atoi(opt) > 0) + conf_max_failure = atoi(opt); + + opt = conf_get_opt("auth", "any-login"); + if (opt && atoi(opt) > 0) + conf_any_login = 1; + + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) { + log_emerg("mschap-v1: failed to open /dev/urandom: %s\n", strerror(errno)); + return; + } + if (ppp_auth_register_handler(&chap)) + log_emerg("mschap-v1: failed to register handler\n"); +} + diff --git a/accel-pppd/auth/auth_mschap_v2.c b/accel-pppd/auth/auth_mschap_v2.c new file mode 100644 index 00000000..e07c4f7e --- /dev/null +++ b/accel-pppd/auth/auth_mschap_v2.c @@ -0,0 +1,639 @@ +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <byteswap.h> +#include <arpa/inet.h> + +#include <openssl/md4.h> +#include <openssl/des.h> +#include <openssl/sha.h> + +#include "log.h" +#include "ppp.h" +#include "events.h" +#include "ppp_auth.h" +#include "ppp_lcp.h" +#include "pwdb.h" + +#include "memdebug.h" + +#define MSCHAP_V2 0x81 + +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +#define VALUE_SIZE 16 +#define RESPONSE_VALUE_SIZE (16+8+24+1) + +#define MSG_FAILURE "E=691 R=0 C=cccccccccccccccccccccccccccccccc V=3 M=Authentication failure" +#define MSG_SUCCESS "S=cccccccccccccccccccccccccccccccccccccccc M=Authentication successed" + +#define HDR_LEN (sizeof(struct chap_hdr_t)-2) + +static int conf_timeout = 5; +static int conf_interval = 0; +static int conf_max_failure = 3; + +static int urandom_fd; + +struct chap_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); + +struct chap_challenge_t +{ + struct chap_hdr_t hdr; + uint8_t val_size; + uint8_t val[VALUE_SIZE]; + char name[0]; +} __attribute__((packed)); + +struct chap_response_t +{ + struct chap_hdr_t hdr; + uint8_t val_size; + uint8_t peer_challenge[16]; + uint8_t reserved[8]; + uint8_t nt_hash[24]; + uint8_t flags; + char name[0]; +} __attribute__((packed)); + +struct chap_failure_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_FAILURE)]; +} __attribute__((packed)); + +struct chap_success_t +{ + struct chap_hdr_t hdr; + char message[sizeof(MSG_SUCCESS)]; +} __attribute__((packed)); + + +struct chap_auth_data_t +{ + struct auth_data_t auth; + struct ppp_handler_t h; + struct ppp_t *ppp; + int id; + uint8_t val[VALUE_SIZE]; + struct triton_timer_t timeout; + struct triton_timer_t interval; + int failure; + int started:1; +}; + +static void chap_send_challenge(struct chap_auth_data_t *ad); +static void chap_recv(struct ppp_handler_t *h); +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name); +static void chap_timeout_timer(struct triton_timer_t *t); +static void chap_restart_timer(struct triton_timer_t *t); +static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash, uint8_t *nt_hash); + +static void print_buf(const uint8_t *buf, int size) +{ + int i; + for (i = 0; i < size; i++) + log_ppp_info2("%x", buf[i]); +} + +static void print_str(const char *buf, int size) +{ + int i; + for (i = 0; i < size; i++) + log_ppp_info2("%c", buf[i]); +} + +static struct auth_data_t* auth_data_init(struct ppp_t *ppp) +{ + struct chap_auth_data_t *d = _malloc(sizeof(*d)); + + memset(d, 0, sizeof(*d)); + d->auth.proto = PPP_CHAP; + d->ppp = ppp; + + return &d->auth; +} + +static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + _free(d); +} + +static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + d->h.proto = PPP_CHAP; + d->h.recv = chap_recv; + d->timeout.expire = chap_timeout_timer; + d->timeout.period = conf_timeout * 1000; + d->interval.expire = chap_restart_timer; + d->interval.period = conf_interval * 1000; + + ppp_register_chan_handler(ppp, &d->h); + + chap_send_challenge(d); + + return 0; +} + +static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + if (d->interval.tpd) + triton_timer_del(&d->interval); + + ppp_unregister_handler(ppp,&d->h); + + return 0; +} + +static void chap_timeout_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + + if (conf_ppp_verbose) + log_ppp_warn("mschap-v2: timeout\n"); + + if (++d->failure == conf_max_failure) { + if (d->started) + ppp_terminate(d->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(d->ppp, NULL); + } else { + --d->id; + chap_send_challenge(d); + } +} + +static void chap_restart_timer(struct triton_timer_t *t) +{ + struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + + chap_send_challenge(d); +} + +static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + *ptr = MSCHAP_V2; + return 1; +} + +static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + if (*ptr == MSCHAP_V2) + return LCP_OPT_ACK; + return LCP_OPT_NAK; +} + +static void chap_send_failure(struct chap_auth_data_t *ad) +{ + struct chap_failure_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_FAILURE, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg) - 1 - 2), + .message = MSG_FAILURE, + }; + + if (conf_ppp_verbose) + log_ppp_info2("send [MSCHAP-v2 Failure id=%x \"%s\"]\n", msg.hdr.id, MSG_FAILURE); + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); +} + +static int generate_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name, char *authenticator) +{ + MD4_CTX md4_ctx; + SHA_CTX sha_ctx; + char *passwd; + char *u_passwd; + uint8_t pw_hash[MD4_DIGEST_LENGTH]; + uint8_t c_hash[SHA_DIGEST_LENGTH]; + uint8_t response[SHA_DIGEST_LENGTH]; + int i; + + uint8_t magic1[39] = + {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; + uint8_t magic2[41] = + {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E}; + + + passwd = pwdb_get_passwd(ad->ppp,name); + if (!passwd) + return -1; + + u_passwd=_malloc(strlen(passwd)*2); + for(i=0; i<strlen(passwd); i++) + { + u_passwd[i*2]=passwd[i]; + u_passwd[i*2+1]=0; + } + + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx,u_passwd,strlen(passwd)*2); + MD4_Final(pw_hash,&md4_ctx); + + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx,pw_hash,16); + MD4_Final(pw_hash,&md4_ctx); + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx,pw_hash,16); + SHA1_Update(&sha_ctx,msg->nt_hash,24); + SHA1_Update(&sha_ctx,magic1,39); + SHA1_Final(response,&sha_ctx); + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx,msg->peer_challenge,16); + SHA1_Update(&sha_ctx,ad->val,16); + SHA1_Update(&sha_ctx,name,strlen(name)); + SHA1_Final(c_hash,&sha_ctx); + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx,response,20); + SHA1_Update(&sha_ctx,c_hash,8); + SHA1_Update(&sha_ctx,magic2,41); + SHA1_Final(response,&sha_ctx); + + for(i=0; i<20; i++) + sprintf(authenticator+i*2,"%02X",response[i]); + + _free(passwd); + _free(u_passwd); + + return 0; +} + +static void chap_send_success(struct chap_auth_data_t *ad, struct chap_response_t *res_msg, const char *authenticator) +{ + struct chap_success_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_SUCCESS, + .hdr.id = ad->id, + .hdr.len = htons(sizeof(msg) - 1 - 2), + .message = MSG_SUCCESS, + }; + + memcpy(msg.message + 2, authenticator, 40); + + if (conf_ppp_verbose) + log_ppp_info2("send [MSCHAP-v2 Success id=%x \"%s\"]\n", msg.hdr.id, msg.message); + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); +} + +static void chap_send_challenge(struct chap_auth_data_t *ad) +{ + struct chap_challenge_t msg = { + .hdr.proto = htons(PPP_CHAP), + .hdr.code = CHAP_CHALLENGE, + .hdr.id = ++ad->id, + .hdr.len = htons(sizeof(msg) - 2), + .val_size = VALUE_SIZE, + }; + + read(urandom_fd, ad->val, VALUE_SIZE); + memcpy(msg.val, ad->val, VALUE_SIZE); + + if (conf_ppp_verbose) { + log_ppp_info2("send [MSCHAP-v2 Challenge id=%x <", msg.hdr.id); + print_buf(msg.val, VALUE_SIZE); + log_ppp_info2(">]\n"); + } + + ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); + + if (conf_timeout && !ad->timeout.tpd) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->timeout, 0); +} + +static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +{ + struct chap_response_t *msg = (struct chap_response_t*)hdr; + char *name; + char authenticator[41]; + int r; + + if (ad->timeout.tpd) + triton_timer_del(&ad->timeout); + + if (conf_ppp_verbose) { + log_ppp_info2("recv [MSCHAP-v2 Response id=%x <", msg->hdr.id); + print_buf(msg->peer_challenge,16); + log_ppp_info2(">, <"); + print_buf(msg->nt_hash, 24); + log_ppp_info2(">, F=%i, name=\"", msg->flags); + print_str(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); + log_ppp_info2("\"]\n"); + } + + if (msg->hdr.id != ad->id) { + if (conf_ppp_verbose) + log_ppp_error("mschap-v2: id mismatch\n"); + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + } + + if (msg->val_size != RESPONSE_VALUE_SIZE) { + log_ppp_error("mschap-v2: incorrect value-size (%i)\n", msg->val_size); + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + } + + name = _strndup(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); + if (!name) { + log_emerg("mschap-v2: out of memory\n"); + if (ad->started) + ppp_terminate(ad->ppp, TERM_NAS_ERROR, 0); + else + ppp_auth_failed(ad->ppp, NULL); + return; + } + + r = pwdb_check(ad->ppp, name, PPP_CHAP, MSCHAP_V2, ad->id, ad->val, msg->peer_challenge, msg->reserved, msg->nt_hash, msg->flags, authenticator); + + if (r == PWDB_NO_IMPL) { + r = chap_check_response(ad, msg, name); + if (r) + r = PWDB_DENIED; + else if (generate_response(ad, msg, name, authenticator)) + r = PWDB_DENIED; + } + + if (r == PWDB_DENIED) { + chap_send_failure(ad); + if (ad->started) + ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + _free(name); + } else { + chap_send_success(ad, msg, authenticator); + if (!ad->started) { + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); + ppp_auth_successed(ad->ppp, name); + } else + _free(name); + } +} + +static void des_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *output) +{ + int i,j,parity; + union + { + uint64_t u64; + uint8_t buf[8]; + } p_key; + DES_cblock cb; + DES_cblock res; + DES_key_schedule ks; + + memcpy(p_key.buf,key,7); + p_key.u64=bswap_64(p_key.u64); + + for(i=0;i<8;i++) + { + cb[i]=(((p_key.u64<<(7*i))>>56)&0xfe); + for(j=0, parity=0; j<7; j++) + if ((cb[i]>>(j+1))&1) parity++; + cb[i]|=(~parity)&1; + } + + DES_set_key_checked(&cb, &ks); + memcpy(cb,input,8); + DES_ecb_encrypt(&cb,&res,&ks,DES_ENCRYPT); + memcpy(output,res,8); +} + +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name) +{ + MD4_CTX md4_ctx; + SHA_CTX sha_ctx; + uint8_t z_hash[21]; + uint8_t c_hash[SHA_DIGEST_LENGTH]; + uint8_t nt_hash[24]; + char *passwd; + char *u_passwd; + int i; + + passwd = pwdb_get_passwd(ad->ppp, name); + if (!passwd) { + if (conf_ppp_verbose) + log_ppp_warn("mschap-v2: user not found\n"); + chap_send_failure(ad); + return -1; + } + + u_passwd=_malloc(strlen(passwd)*2); + for(i=0; i<strlen(passwd); i++) + { + u_passwd[i*2]=passwd[i]; + u_passwd[i*2+1]=0; + } + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx,msg->peer_challenge,16); + SHA1_Update(&sha_ctx,ad->val,16); + SHA1_Update(&sha_ctx,name,strlen(name)); + SHA1_Final(c_hash,&sha_ctx); + + memset(z_hash,0,sizeof(z_hash)); + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx,u_passwd,strlen(passwd)*2); + MD4_Final(z_hash,&md4_ctx); + + des_encrypt(c_hash,z_hash,nt_hash); + des_encrypt(c_hash,z_hash+7,nt_hash+8); + des_encrypt(c_hash,z_hash+14,nt_hash+16); + + set_mppe_keys(ad, z_hash, msg->nt_hash); + + _free(passwd); + _free(u_passwd); + + return memcmp(nt_hash,msg->nt_hash,24); +} + +static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash, uint8_t *nt_hash) +{ + MD4_CTX md4_ctx; + SHA_CTX sha_ctx; + uint8_t digest[20]; + uint8_t send_key[20]; + uint8_t recv_key[20]; + + uint8_t pad1[40] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + uint8_t pad2[40] = + {0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2}; + + uint8_t magic1[27] = + {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}; + + uint8_t magic2[84] = + {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e}; + + uint8_t magic3[84] = + {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e}; + + struct ev_mppe_keys_t ev_mppe = { + .ppp = ad->ppp, + .type = 1 << 2, + .policy = 1, + .recv_key = recv_key, + .send_key = send_key, + }; + + //NtPasswordHashHash + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx, z_hash, 16); + MD4_Final(digest, &md4_ctx); + + //GetMasterKey + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, digest, 16); + SHA1_Update(&sha_ctx, nt_hash, 24); + SHA1_Update(&sha_ctx, magic1, sizeof(magic1)); + SHA1_Final(digest, &sha_ctx); + + //send key + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, digest, 16); + SHA1_Update(&sha_ctx, pad1, sizeof(pad1)); + SHA1_Update(&sha_ctx, magic3, sizeof(magic2)); + SHA1_Update(&sha_ctx, pad2, sizeof(pad2)); + SHA1_Final(send_key, &sha_ctx); + + //recv key + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, digest, 16); + SHA1_Update(&sha_ctx, pad1, sizeof(pad1)); + SHA1_Update(&sha_ctx, magic2, sizeof(magic3)); + SHA1_Update(&sha_ctx, pad2, sizeof(pad2)); + SHA1_Final(recv_key, &sha_ctx); + + triton_event_fire(EV_MPPE_KEYS, &ev_mppe); +} + +static int chap_check(uint8_t *ptr) +{ + return *ptr == MSCHAP_V2; +} + +static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + chap_send_challenge(d); + + return 0; +} + +static struct ppp_auth_handler_t chap= +{ + .name = "MSCHAP-v2", + .init = auth_data_init, + .free = auth_data_free, + .send_conf_req = lcp_send_conf_req, + .recv_conf_req = lcp_recv_conf_req, + .start = chap_start, + .finish = chap_finish, + .check = chap_check, + .restart = chap_restart, +}; + +static void chap_recv(struct ppp_handler_t *h) +{ + struct chap_auth_data_t *d = container_of(h, typeof(*d), h); + struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->chan_buf; + + if (d->ppp->chan_buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->chan_buf_size - 2) { + log_ppp_warn("mschap-v2: short packet received\n"); + return; + } + + if (hdr->code == CHAP_RESPONSE) + chap_recv_response(d, hdr); + else + log_ppp_warn("mschap-v2: unknown code received %x\n",hdr->code); +} + +static void __init auth_mschap_v2_init() +{ + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) { + log_emerg("mschap-v2: failed to open /dev/urandom: %s\n", strerror(errno)); + return; + } + + if (ppp_auth_register_handler(&chap)) + log_emerg("mschap-v2: failed to register handler\n"); +} + diff --git a/accel-pppd/auth/auth_pap.c b/accel-pppd/auth/auth_pap.c new file mode 100644 index 00000000..69090464 --- /dev/null +++ b/accel-pppd/auth/auth_pap.c @@ -0,0 +1,273 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "log.h" +#include "ppp.h" +#include "ppp_auth.h" +#include "ppp_lcp.h" +#include "pwdb.h" + +#include "memdebug.h" + +#define MSG_FAILED "Authentication failed" +#define MSG_SUCCESSED "Authentication successed" + +#define HDR_LEN (sizeof(struct pap_hdr_t)-2) + +#define PAP_REQ 1 +#define PAP_ACK 2 +#define PAP_NAK 3 + +static int conf_timeout = 5; +static int conf_any_login = 0; + +static struct auth_data_t* auth_data_init(struct ppp_t *ppp); +static void auth_data_free(struct ppp_t*, struct auth_data_t*); +static int lcp_send_conf_req(struct ppp_t*, struct auth_data_t*, uint8_t*); +static int lcp_recv_conf_req(struct ppp_t*, struct auth_data_t*, uint8_t*); +static int pap_start(struct ppp_t*, struct auth_data_t*); +static int pap_finish(struct ppp_t*, struct auth_data_t*); +static void pap_recv(struct ppp_handler_t*h); +static void pap_timeout(struct triton_timer_t *t); + +struct pap_auth_data_t +{ + struct auth_data_t auth; + struct ppp_handler_t h; + struct ppp_t *ppp; + int started:1; + struct triton_timer_t timeout; +}; + +struct pap_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); + +struct pap_ack_t +{ + struct pap_hdr_t hdr; + uint8_t msg_len; + char msg[0]; +} __attribute__((packed)); + +static struct ppp_auth_handler_t pap= +{ + .name = "PAP", + .init = auth_data_init, + .free = auth_data_free, + .send_conf_req = lcp_send_conf_req, + .recv_conf_req = lcp_recv_conf_req, + .start = pap_start, + .finish = pap_finish, +}; + +static struct auth_data_t* auth_data_init(struct ppp_t *ppp) +{ + struct pap_auth_data_t *d = _malloc(sizeof(*d)); + + memset(d, 0, sizeof(*d)); + d->auth.proto = PPP_PAP; + d->ppp = ppp; + + return &d->auth; +} + +static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + _free(d); +} + +static int pap_start(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + d->h.proto = PPP_PAP; + d->h.recv = pap_recv; + d->timeout.expire = pap_timeout; + d->timeout.period = conf_timeout * 1000; + + triton_timer_add(ppp->ctrl->ctx, &d->timeout, 0); + + ppp_register_chan_handler(ppp, &d->h); + + return 0; +} +static int pap_finish(struct ppp_t *ppp, struct auth_data_t *auth) +{ + struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + + if (d->timeout.tpd) + triton_timer_del(&d->timeout); + + ppp_unregister_handler(ppp, &d->h); + + return 0; +} + +static void pap_timeout(struct triton_timer_t *t) +{ + struct pap_auth_data_t *d = container_of(t, typeof(*d), timeout); + + if (conf_ppp_verbose) + log_ppp_warn("pap: timeout\n"); + + ppp_auth_failed(d->ppp, NULL); +} + +static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + return 0; +} + +static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr) +{ + return LCP_OPT_ACK; +} + +static void pap_send_ack(struct pap_auth_data_t *p, int id) +{ + uint8_t buf[128]; + struct pap_ack_t *msg = (struct pap_ack_t*)buf; + msg->hdr.proto = htons(PPP_PAP); + msg->hdr.code = PAP_ACK; + msg->hdr.id = id; + msg->hdr.len = htons(HDR_LEN + 1 + sizeof(MSG_SUCCESSED) - 1); + msg->msg_len = sizeof(MSG_SUCCESSED) - 1; + memcpy(msg->msg, MSG_SUCCESSED, sizeof(MSG_SUCCESSED)); + + if (conf_ppp_verbose) + log_ppp_info2("send [PAP AuthAck id=%x \"%s\"]\n", id, MSG_SUCCESSED); + + ppp_chan_send(p->ppp, msg, ntohs(msg->hdr.len) + 2); +} + +static void pap_send_nak(struct pap_auth_data_t *p, int id) +{ + uint8_t buf[128]; + struct pap_ack_t *msg = (struct pap_ack_t*)buf; + msg->hdr.proto = htons(PPP_PAP); + msg->hdr.code = PAP_NAK; + msg->hdr.id = id; + msg->hdr.len = htons(HDR_LEN + 1 + sizeof(MSG_FAILED) - 1); + msg->msg_len = sizeof(MSG_FAILED) - 1; + memcpy(msg->msg, MSG_FAILED, sizeof(MSG_FAILED)); + + if (conf_ppp_verbose) + log_ppp_info2("send [PAP AuthNak id=%x \"%s\"]\n", id, MSG_FAILED); + + ppp_chan_send(p->ppp, msg, ntohs(msg->hdr.len) + 2); +} + +static int pap_recv_req(struct pap_auth_data_t *p, struct pap_hdr_t *hdr) +{ + int ret, r; + char *peer_id; + char *passwd; + char *passwd2; + int peer_id_len; + int passwd_len; + uint8_t *ptr = (uint8_t*)(hdr + 1); + + if (p->timeout.tpd) + triton_timer_del(&p->timeout); + + if (conf_ppp_verbose) + log_ppp_info2("recv [PAP AuthReq id=%x]\n", hdr->id); + + peer_id_len = *(uint8_t*)ptr; ptr++; + if (peer_id_len > ntohs(hdr->len) - sizeof(*hdr) + 2 - 1) { + log_ppp_warn("PAP: short packet received\n"); + return -1; + } + peer_id = (char*)ptr; ptr += peer_id_len; + + passwd_len = *(uint8_t*)ptr; ptr++; + if (passwd_len > ntohs(hdr->len) - sizeof(*hdr ) + 2 - 2 - peer_id_len) { + log_ppp_warn("PAP: short packet received\n"); + return -1; + } + + peer_id = _strndup((const char*)peer_id, peer_id_len); + + if (conf_any_login) { + pap_send_ack(p, hdr->id); + p->started = 1; + ppp_auth_successed(p->ppp, peer_id); + return 0; + } + + passwd = _strndup((const char*)ptr, passwd_len); + + r = pwdb_check(p->ppp, peer_id, PPP_PAP, passwd); + if (r == PWDB_NO_IMPL) { + passwd2 = pwdb_get_passwd(p->ppp, peer_id); + if (!passwd2 || strcmp(passwd2, passwd)) + r = PWDB_DENIED; + else + r = PWDB_SUCCESS; + _free(passwd2); + } + if (r == PWDB_DENIED) { + if (conf_ppp_verbose) + log_ppp_warn("PAP: authentication error\n"); + pap_send_nak(p, hdr->id); + if (p->started) + ppp_terminate(p->ppp, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(p->ppp, peer_id); + ret=-1; + _free(peer_id); + } else { + pap_send_ack(p, hdr->id); + if (!p->started) { + p->started = 1; + ppp_auth_successed(p->ppp, peer_id); + } + ret = 0; + } + + _free(passwd); + + return ret; +} + +static void pap_recv(struct ppp_handler_t *h) +{ + struct pap_auth_data_t *d = container_of(h, typeof(*d), h); + struct pap_hdr_t *hdr = (struct pap_hdr_t *)d->ppp->chan_buf; + + if (d->ppp->chan_buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->chan_buf_size - 2) { + log_ppp_warn("PAP: short packet received\n"); + return; + } + + if (hdr->code == PAP_REQ) + pap_recv_req(d, hdr); + else { + log_ppp_warn("PAP: unknown code received %x\n",hdr->code); + } +} + +static void __init auth_pap_init() +{ + char *opt; + + opt = conf_get_opt("auth", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); + + opt = conf_get_opt("auth", "any-login"); + if (opt && atoi(opt) > 0) + conf_any_login = 1; + + ppp_auth_register_handler(&pap); +} + |