summaryrefslogtreecommitdiff
path: root/accel-pptpd/auth
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2010-09-03 18:58:53 +0400
committerKozlov Dmitry <dima@server>2010-09-03 18:58:53 +0400
commite8aa3a1457295f70f8ccc9cd7f2f9073f01a5e2e (patch)
tree17a99610798630e83fc1032c82ee51c404ce19fe /accel-pptpd/auth
parenta22573e91dac7971aa4c9b1d874d6751e8502d16 (diff)
downloadaccel-ppp-e8aa3a1457295f70f8ccc9cd7f2f9073f01a5e2e.tar.gz
accel-ppp-e8aa3a1457295f70f8ccc9cd7f2f9073f01a5e2e.zip
project restructured
Diffstat (limited to 'accel-pptpd/auth')
-rw-r--r--accel-pptpd/auth/CMakeLists.txt5
-rw-r--r--accel-pptpd/auth/auth_chap_md5.c294
-rw-r--r--accel-pptpd/auth/auth_mschap_v1.c358
-rw-r--r--accel-pptpd/auth/auth_mschap_v2.c446
-rw-r--r--accel-pptpd/auth/auth_pap.c214
5 files changed, 1317 insertions, 0 deletions
diff --git a/accel-pptpd/auth/CMakeLists.txt b/accel-pptpd/auth/CMakeLists.txt
new file mode 100644
index 00000000..f0e6465c
--- /dev/null
+++ b/accel-pptpd/auth/CMakeLists.txt
@@ -0,0 +1,5 @@
+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)
+
diff --git a/accel-pptpd/auth/auth_chap_md5.c b/accel-pptpd/auth/auth_chap_md5.c
new file mode 100644
index 00000000..5577794f
--- /dev/null
+++ b/accel-pptpd/auth/auth_chap_md5.c
@@ -0,0 +1,294 @@
+#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"
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+
+#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 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];
+};
+
+static void chap_send_challenge(struct chap_auth_data_t *ad);
+static void chap_recv(struct ppp_handler_t *h);
+
+static void print_buf(const uint8_t *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%x ",buf[i]);
+}
+static void print_str(const char *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%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);
+
+ 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;
+
+ 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);
+
+ ppp_unregister_handler(ppp,&d->h);
+
+ return 0;
+}
+
+static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ *ptr=5;
+ return 1;
+}
+
+static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ if (*ptr==5)
+ 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,
+ };
+
+ log_debug("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,
+ };
+
+ log_debug("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);
+
+ log_debug("send [CHAP Challenge id=%x <",msg.hdr.id);
+ print_buf(msg.val,VALUE_SIZE);
+ log_debug(">]\n");
+
+ ppp_chan_send(ad->ppp,&msg,ntohs(msg.hdr.len)+2);
+}
+
+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;
+ struct chap_challenge_t *msg=(struct chap_challenge_t*)hdr;
+
+ log_debug("recv [CHAP Response id=%x <", msg->hdr.id);
+ print_buf(msg->val,msg->val_size);
+ log_debug(">, name=\"");
+ print_str(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ log_debug("\"]\n");
+
+ if (msg->hdr.id!=ad->id)
+ {
+ log_error("chap-md5: id mismatch\n");
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ if (msg->val_size!=VALUE_SIZE)
+ {
+ log_error("chap-md5: value-size should be %i, expected %i\n",VALUE_SIZE,msg->val_size);
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ name=strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ passwd=pwdb_get_passwd(ad->ppp,name);
+ if (!passwd)
+ {
+ free(name);
+ log_debug("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)))
+ {
+ log_debug("chap-md5: challenge response mismatch\n");
+ chap_send_failure(ad);
+ auth_failed(ad->ppp);
+ }else
+ {
+ chap_send_success(ad);
+ auth_successed(ad->ppp);
+ }
+
+ free(name);
+ free(passwd);
+}
+
+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,
+};
+
+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_warn("CHAP: short packet received\n");
+ return;
+ }
+
+ if (hdr->code==CHAP_RESPONSE) chap_recv_response(d,hdr);
+ else
+ {
+ log_warn("CHAP: unknown code received %x\n",hdr->code);
+ }
+}
+
+static void __init auth_chap_md5_init()
+{
+ urandom_fd=open("/dev/urandom",O_RDONLY);
+ if (urandom_fd<0)
+ {
+ log_error("chap-md5: failed to open /dev/urandom: %s\n",strerror(errno));
+ return;
+ }
+ if (ppp_auth_register_handler(&chap))
+ log_error("chap-md5: failed to register handler\n");
+}
+
diff --git a/accel-pptpd/auth/auth_mschap_v1.c b/accel-pptpd/auth/auth_mschap_v1.c
new file mode 100644
index 00000000..1cf5eb8b
--- /dev/null
+++ b/accel-pptpd/auth/auth_mschap_v1.c
@@ -0,0 +1,358 @@
+#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 "log.h"
+#include "ppp.h"
+#include "ppp_auth.h"
+#include "ppp_lcp.h"
+#include "pwdb.h"
+
+#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 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 use_nt_hash;
+ 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];
+};
+
+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);
+
+static void print_buf(const uint8_t *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%x",buf[i]);
+}
+static void print_str(const char *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%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);
+
+ 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;
+
+ 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);
+
+ ppp_unregister_handler(ppp,&d->h);
+
+ return 0;
+}
+
+static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ *ptr=0x80;
+ return 1;
+}
+
+static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ if (*ptr==0x80)
+ 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,
+ };
+
+ log_debug("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,
+ };
+
+ log_debug("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);
+
+ log_debug("send [MSCHAP-v1 Challenge id=%x <",msg.hdr.id);
+ print_buf(msg.val,VALUE_SIZE);
+ log_debug(">]\n");
+
+ ppp_chan_send(ad->ppp,&msg,ntohs(msg.hdr.len)+2);
+}
+
+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;
+
+ log_debug("recv [MSCHAP-v1 Response id=%x <", msg->hdr.id);
+ print_buf(msg->lm_hash,24);
+ log_debug(">, <");
+ print_buf(msg->nt_hash,24);
+ log_debug(">, F=%i, name=\"",msg->use_nt_hash);
+ print_str(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ log_debug("\"]\n");
+
+ if (msg->hdr.id!=ad->id)
+ {
+ log_error("mschap-v1: id mismatch\n");
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ if (msg->val_size!=RESPONSE_VALUE_SIZE)
+ {
+ log_error("mschap-v1: value-size should be %i, expected %i\n",RESPONSE_VALUE_SIZE,msg->val_size);
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ if (chap_check_response(ad,msg))
+ {
+ chap_send_failure(ad);
+ auth_failed(ad->ppp);
+ }else
+ {
+ chap_send_success(ad);
+ auth_successed(ad->ppp);
+ }
+}
+
+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)
+{
+ MD4_CTX md4_ctx;
+ uint8_t z_hash[21];
+ uint8_t nt_hash[24];
+ char *passwd;
+ char *u_passwd;
+ char *name;
+ int i;
+
+ name=strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ passwd=pwdb_get_passwd(ad->ppp,name);
+ if (!passwd)
+ {
+ free(name);
+ log_debug("mschap-v1: 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;
+ }
+
+ 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);
+
+ free(name);
+ free(passwd);
+ free(u_passwd);
+
+ return memcmp(nt_hash,msg->nt_hash,24);
+}
+
+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,
+};
+
+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_warn("mschap-v1: short packet received\n");
+ return;
+ }
+
+ if (hdr->code==CHAP_RESPONSE) chap_recv_response(d,hdr);
+ else
+ {
+ log_warn("mschap-v1: unknown code received %x\n",hdr->code);
+ }
+}
+
+static void __init auth_mschap_v1_init()
+{
+ urandom_fd=open("/dev/urandom",O_RDONLY);
+ if (urandom_fd<0)
+ {
+ log_error("mschap-v1: failed to open /dev/urandom: %s\n",strerror(errno));
+ return;
+ }
+ if (ppp_auth_register_handler(&chap))
+ log_error("mschap-v1: failed to register handler\n");
+}
+
diff --git a/accel-pptpd/auth/auth_mschap_v2.c b/accel-pptpd/auth/auth_mschap_v2.c
new file mode 100644
index 00000000..502f3686
--- /dev/null
+++ b/accel-pptpd/auth/auth_mschap_v2.c
@@ -0,0 +1,446 @@
+#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 "ppp_auth.h"
+#include "ppp_lcp.h"
+#include "pwdb.h"
+
+#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 urandom_fd;
+static 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};
+static 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};
+
+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];
+};
+
+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);
+
+static void print_buf(const uint8_t *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%x",buf[i]);
+}
+static void print_str(const char *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ log_debug("%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);
+
+ 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;
+
+ 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);
+
+ ppp_unregister_handler(ppp,&d->h);
+
+ return 0;
+}
+
+static int lcp_send_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ *ptr=0x81;
+ return 1;
+}
+
+static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t *ptr)
+{
+ if (*ptr==0x81)
+ 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,
+ };
+
+ log_debug("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, uint8_t *response)
+{
+ MD4_CTX md4_ctx;
+ SHA_CTX sha_ctx;
+ char *passwd;
+ char *u_passwd;
+ char *name;
+ uint8_t pw_hash[MD4_DIGEST_LENGTH];
+ uint8_t c_hash[SHA_DIGEST_LENGTH];
+ int i;
+
+ name=strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ passwd=pwdb_get_passwd(ad->ppp,name);
+ if (!passwd)
+ {
+ free(name);
+ 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);
+
+ free(name);
+ free(passwd);
+ free(u_passwd);
+
+ return 0;
+}
+
+static void chap_send_success(struct chap_auth_data_t *ad, struct chap_response_t *res_msg)
+{
+ 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,
+ };
+ uint8_t response[20];
+ int i;
+
+ if (generate_response(ad,res_msg,response))
+ return;
+ for(i=0; i<20; i++)
+ sprintf(msg.message+2+i*2,"%02X",response[i]);
+ msg.message[2+i*2]=' ';
+
+ log_debug("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);
+
+ log_debug("send [MSCHAP-v2 Challenge id=%x <",msg.hdr.id);
+ print_buf(msg.val,VALUE_SIZE);
+ log_debug(">]\n");
+
+ ppp_chan_send(ad->ppp,&msg,ntohs(msg.hdr.len)+2);
+}
+
+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;
+
+ log_debug("recv [MSCHAP-v2 Response id=%x <", msg->hdr.id);
+ print_buf(msg->peer_challenge,16);
+ log_debug(">, <");
+ print_buf(msg->nt_hash,24);
+ log_debug(">, F=%i, name=\"",msg->flags);
+ print_str(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ log_debug("\"]\n");
+
+ if (msg->hdr.id!=ad->id)
+ {
+ log_error("mschap-v2: id mismatch\n");
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ if (msg->val_size!=RESPONSE_VALUE_SIZE)
+ {
+ log_error("mschap-v2: value-size should be %i, expected %i\n",RESPONSE_VALUE_SIZE,msg->val_size);
+ chap_send_failure(ad);
+ ppp_terminate(ad->ppp, 0);
+ }
+
+ if (chap_check_response(ad,msg))
+ {
+ chap_send_failure(ad);
+ auth_failed(ad->ppp);
+ }else
+ {
+ chap_send_success(ad,msg);
+ auth_successed(ad->ppp);
+ }
+}
+
+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)
+{
+ 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;
+ char *name;
+ int i;
+
+ name=strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2);
+ passwd=pwdb_get_passwd(ad->ppp,name);
+ if (!passwd)
+ {
+ free(name);
+ log_debug("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);
+
+ free(name);
+ free(passwd);
+ free(u_passwd);
+
+ return memcmp(nt_hash,msg->nt_hash,24);
+}
+
+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,
+};
+
+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_warn("mschap-v2: short packet received\n");
+ return;
+ }
+
+ if (hdr->code==CHAP_RESPONSE) chap_recv_response(d,hdr);
+ else
+ {
+ log_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_error("mschap-v2: failed to open /dev/urandom: %s\n",strerror(errno));
+ return;
+ }
+ if (ppp_auth_register_handler(&chap))
+ log_error("mschap-v2: failed to register handler\n");
+}
+
diff --git a/accel-pptpd/auth/auth_pap.c b/accel-pptpd/auth/auth_pap.c
new file mode 100644
index 00000000..92ddef52
--- /dev/null
+++ b/accel-pptpd/auth/auth_pap.c
@@ -0,0 +1,214 @@
+#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"
+
+#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
+
+char *strndup(const char *s, size_t n);
+
+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);
+
+struct pap_auth_data_t
+{
+ struct auth_data_t auth;
+ struct ppp_handler_t h;
+ struct ppp_t *ppp;
+};
+
+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;
+
+ 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);
+
+ ppp_unregister_handler(ppp,&d->h);
+
+ return 0;
+}
+
+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));
+
+ log_debug("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));
+
+ log_debug("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;
+ char *peer_id;
+ char *passwd;
+ int peer_id_len;
+ int passwd_len;
+ uint8_t *ptr=(uint8_t*)(hdr+1);
+
+ log_debug("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_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_warn("PAP: short packet received\n");
+ return -1;
+ }
+
+ peer_id=strndup((const char*)peer_id,peer_id_len);
+ passwd=strndup((const char*)ptr,passwd_len);
+
+ if (pwdb_check(p->ppp,peer_id,passwd))
+ {
+ log_warn("PAP: authentication error\n");
+ pap_send_nak(p,hdr->id);
+ auth_failed(p->ppp);
+ ret=-1;
+ }else
+ {
+ pap_send_ack(p,hdr->id);
+ auth_successed(p->ppp);
+ ret=0;
+ }
+
+ free(peer_id);
+ 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_warn("PAP: short packet received\n");
+ return;
+ }
+
+ if (hdr->code==PAP_REQ) pap_recv_req(d,hdr);
+ else
+ {
+ log_warn("PAP: unknown code received %x\n",hdr->code);
+ }
+}
+
+static void __init auth_pap_init()
+{
+ ppp_auth_register_handler(&pap);
+}
+