summaryrefslogtreecommitdiff
path: root/accel-pppd/auth
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2011-01-05 15:18:59 +0300
committerDmitry Kozlov <xeb@mail.ru>2011-01-05 15:18:59 +0300
commitf28cb1b0a926f1ea98700b7871537ad1793511fd (patch)
treebaf35570bc6b38b6fab5b6524e8f19f58f71e57f /accel-pppd/auth
parent2fdf3586c13a72c36f9530084962e29d57dc0329 (diff)
downloadaccel-ppp-xebd-f28cb1b0a926f1ea98700b7871537ad1793511fd.tar.gz
accel-ppp-xebd-f28cb1b0a926f1ea98700b7871537ad1793511fd.zip
rename accel-pptp to accel-ppp
Diffstat (limited to 'accel-pppd/auth')
-rw-r--r--accel-pppd/auth/CMakeLists.txt13
-rw-r--r--accel-pppd/auth/auth_chap_md5.c427
-rw-r--r--accel-pppd/auth/auth_mschap_v1.c517
-rw-r--r--accel-pppd/auth/auth_mschap_v2.c639
-rw-r--r--accel-pppd/auth/auth_pap.c273
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 0000000..ef9478a
--- /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 0000000..d19634a
--- /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 0000000..5b38db5
--- /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 0000000..e07c4f7
--- /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 0000000..6909046
--- /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);
+}
+