diff options
-rw-r--r-- | accel-pptpd/CMakeLists.txt | 4 | ||||
-rw-r--r-- | accel-pptpd/ipcp_opt_ipaddr.c | 2 | ||||
-rw-r--r-- | accel-pptpd/main.c | 82 | ||||
-rw-r--r-- | accel-pptpd/ppp.c | 26 | ||||
-rw-r--r-- | accel-pptpd/ppp.h | 5 | ||||
-rw-r--r-- | accel-pptpd/ppp_ccp.c | 4 | ||||
-rw-r--r-- | accel-pptpd/ppp_fsm.c | 18 | ||||
-rw-r--r-- | accel-pptpd/ppp_ipcp.c | 4 | ||||
-rw-r--r-- | accel-pptpd/ppp_lcp.c | 4 | ||||
-rw-r--r-- | accel-pptpd/pptp.c | 91 | ||||
-rw-r--r-- | accel-pptpd/triton/CMakeLists.txt | 5 | ||||
-rw-r--r-- | accel-pptpd/triton/conf_file.c | 54 | ||||
-rw-r--r-- | accel-pptpd/triton/conf_file.h | 16 | ||||
-rw-r--r-- | accel-pptpd/triton/loader.c | 47 | ||||
-rw-r--r-- | accel-pptpd/triton/log.c | 34 | ||||
-rw-r--r-- | accel-pptpd/triton/md.c | 65 | ||||
-rw-r--r-- | accel-pptpd/triton/spinlock.h | 6 | ||||
-rw-r--r-- | accel-pptpd/triton/timer.c | 80 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.c | 104 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.h | 61 | ||||
-rw-r--r-- | accel-pptpd/triton/triton_p.h | 45 | ||||
-rw-r--r-- | doc/rfc3079.txt | 1179 |
22 files changed, 1600 insertions, 336 deletions
diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt index 5e424036..d68cbe91 100644 --- a/accel-pptpd/CMakeLists.txt +++ b/accel-pptpd/CMakeLists.txt @@ -1,12 +1,12 @@ PROJECT (pptpd) cmake_minimum_required(VERSION 2.6) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fvisibility=hidden -D_GNU_SOURCE") ADD_SUBDIRECTORY(triton) ADD_EXECUTABLE(pptpd - pptpd.c + main.c pptp.c log.c ppp.c diff --git a/accel-pptpd/ipcp_opt_ipaddr.c b/accel-pptpd/ipcp_opt_ipaddr.c index 8eae84b6..206c2e6e 100644 --- a/accel-pptpd/ipcp_opt_ipaddr.c +++ b/accel-pptpd/ipcp_opt_ipaddr.c @@ -12,7 +12,7 @@ static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt); static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); -static int ipaddr_recv_conf_ack(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +//static int ipaddr_recv_conf_ack(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t*, uint8_t *ptr); struct ipaddr_option_t diff --git a/accel-pptpd/main.c b/accel-pptpd/main.c index ff74305b..90f206df 100644 --- a/accel-pptpd/main.c +++ b/accel-pptpd/main.c @@ -1,17 +1,82 @@ +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> + #include "triton/triton.h" -#include "log.h" void sigterm(int num) { - triton_terminate(); } int main(int argc,char **argv) { + int i; + int daemon=0; + char *pid_file=NULL; + char *conf_file=NULL; sigset_t set; - log_init(stdout,4,0); + if (argc<2) + goto usage; + + for(i=1; i<argc; i++) + { + if (!strcmp(argv[i],"-d")) + daemon=1; + else if (!strcmp(argv[i],"-p")) + { + if (i==argc-1) + goto usage; + pid_file=argv[++i]; + } + else if (!strcmp(argv[i],"-c")) + { + if (i==argc-1) + goto usage; + conf_file=argv[++i]; + } + } + + if (!conf_file) + goto usage; + + if (triton_init(conf_file)) + return EXIT_FAILURE; - triton_init(); + if (daemon) + { + pid_t pid=fork(); + if (pid>0) + _exit(EXIT_SUCCESS); + if (pid<0) + { + perror("fork"); + return EXIT_FAILURE; + } + if (setsid()<0) + return EXIT_FAILURE; + pid=fork(); + if (pid) + _exit(0); + umask(0); + chdir("/"); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + if (pid_file) + { + FILE *f=fopen("pid_file","w"); + if (f) + { + fprintf(f,"%i",getpid()); + fclose(f); + } + } + triton_run(); signal(SIGTERM,sigterm); @@ -23,7 +88,16 @@ int main(int argc,char **argv) sigdelset(&set, SIGBUS); sigsuspend(&set); + + triton_terminate(); return EXIT_SUCCESS; +usage: + printf("usage: pptpd [-d] [-p <file>] -c <file>\ + where:\ + -d - daemon mode\ + -p - write pid to <file>\ + -c - config file\n"); + return EXIT_FAILURE; } diff --git a/accel-pptpd/ppp.c b/accel-pptpd/ppp.c index 518f7572..b4388718 100644 --- a/accel-pptpd/ppp.c +++ b/accel-pptpd/ppp.c @@ -25,8 +25,8 @@ struct layer_node_t struct list_head items; }; -static void ppp_chan_read(struct triton_md_handler_t*); -static void ppp_unit_read(struct triton_md_handler_t*); +static int ppp_chan_read(struct triton_md_handler_t*); +static int ppp_unit_read(struct triton_md_handler_t*); static void init_layers(struct ppp_t *); static void start_first_layer(struct ppp_t *); @@ -103,10 +103,10 @@ int establish_ppp(struct ppp_t *ppp) ppp->chan_hnd.fd=ppp->chan_fd; ppp->chan_hnd.read=ppp_chan_read; - ppp->chan_hnd.twait=-1; + //ppp->chan_hnd.twait=-1; ppp->unit_hnd.fd=ppp->unit_fd; ppp->unit_hnd.read=ppp_unit_read; - ppp->unit_hnd.twait=-1; + //ppp->unit_hnd.twait=-1; triton_md_register_handler(&ppp->chan_hnd); triton_md_register_handler(&ppp->unit_hnd); @@ -142,7 +142,7 @@ void destablish_ppp(struct ppp_t *ppp) log_debug("ppp destablished\n"); - if (ppp->events.finished) ppp->events.finished(ppp); + ppp->ctrl->finished(ppp); } void print_buf(uint8_t *buf,int size) @@ -179,7 +179,7 @@ int ppp_unit_send(struct ppp_t *ppp, void *data, int size) return n; } -static void ppp_chan_read(struct triton_md_handler_t*h) +static int ppp_chan_read(struct triton_md_handler_t*h) { struct ppp_t *ppp=container_of(h,typeof(*ppp),chan_hnd); struct ppp_handler_t *ppp_h; @@ -193,7 +193,7 @@ static void ppp_chan_read(struct triton_md_handler_t*h) if (ppp->chan_buf_size<2) { log_error("ppp_chan_read: short read %i\n",ppp->chan_buf_size); - return; + return 0; } proto=ntohs(*(uint16_t*)ppp->chan_buf); @@ -202,14 +202,15 @@ static void ppp_chan_read(struct triton_md_handler_t*h) if (ppp_h->proto==proto) { ppp_h->recv(ppp_h); - return; + return 0; } } log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); + return 0; } -static void ppp_unit_read(struct triton_md_handler_t*h) +static int ppp_unit_read(struct triton_md_handler_t*h) { struct ppp_t *ppp=container_of(h,typeof(*ppp),unit_hnd); struct ppp_handler_t *ppp_h; @@ -223,7 +224,7 @@ static void ppp_unit_read(struct triton_md_handler_t*h) if (ppp->unit_buf_size<2) { log_error("ppp_chan_read: short read %i\n",ppp->unit_buf_size); - return; + return 0; } proto=ntohs(*(uint16_t*)ppp->unit_buf); @@ -232,11 +233,12 @@ static void ppp_unit_read(struct triton_md_handler_t*h) if (ppp_h->proto==proto) { ppp_h->recv(ppp_h); - return; + return 0; } } log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); + return 0; } void ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) @@ -250,7 +252,7 @@ void ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) if (n->entry.next==&ppp->layers) { - if (ppp->events.started) ppp->events.started(ppp); + ppp->ctrl->started(ppp); }else { n=list_entry(n->entry.next,typeof(*n),entry); diff --git a/accel-pptpd/ppp.h b/accel-pptpd/ppp.h index 39a0d41b..6dd05bea 100644 --- a/accel-pptpd/ppp.h +++ b/accel-pptpd/ppp.h @@ -52,8 +52,9 @@ struct ppp_t; -struct ppp_events_t +struct ppp_ctrl_t { + struct triton_ctx_t *ctx; void (*started)(struct ppp_t*); void (*finished)(struct ppp_t*); }; @@ -71,7 +72,7 @@ struct ppp_t char *chan_name; - struct ppp_events_t events; + struct ppp_ctrl_t *ctrl; int log:1; diff --git a/accel-pptpd/ppp_ccp.c b/accel-pptpd/ppp_ccp.c index 3c8c5cdb..4bceb5b2 100644 --- a/accel-pptpd/ppp_ccp.c +++ b/accel-pptpd/ppp_ccp.c @@ -528,14 +528,14 @@ static void ccp_recv(struct ppp_handler_t*h) ppp_fsm_recv_conf_rej(&ccp->fsm); break; case TERMREQ: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [CCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_req(&ccp->fsm); ppp_terminate(ccp->ppp); break; case TERMACK: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [CCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_ack(&ccp->fsm); diff --git a/accel-pptpd/ppp_fsm.c b/accel-pptpd/ppp_fsm.c index 41436ebe..72a42d0e 100644 --- a/accel-pptpd/ppp_fsm.c +++ b/accel-pptpd/ppp_fsm.c @@ -29,10 +29,7 @@ static int restart_timer_func(struct triton_timer_t*t); void ppp_fsm_init(struct ppp_fsm_t *layer) { layer->fsm_state=FSM_Initial; - layer->restart_timer.active=0; - layer->restart_timer.pd=layer; - layer->restart_timer.expire=restart_timer_func; - layer->restart_timer.period=3000; + //layer->restart_timer.active=0; layer->restart_counter=0; layer->max_terminate=2; layer->max_configure=10; @@ -461,20 +458,20 @@ void send_term_ack(struct ppp_fsm_t *layer) static void init_req_counter(struct ppp_fsm_t *layer,int timeout) { - triton_timer_del(&layer->restart_timer); + //triton_timer_del(&layer->restart_timer); layer->restart_timer.expire_tv.tv_sec=0; - triton_timer_add(&layer->restart_timer); + //triton_timer_add(&layer->restart_timer); layer->restart_counter=timeout; } static void zero_req_counter(struct ppp_fsm_t *layer) { - triton_timer_del(&layer->restart_timer); + //triton_timer_del(&layer->restart_timer); layer->restart_timer.expire_tv.tv_sec=0; - triton_timer_add(&layer->restart_timer); + //triton_timer_add(&layer->restart_timer); layer->restart_counter=0; } -static int restart_timer_func(struct triton_timer_t*t) +/*static int restart_timer_func(struct triton_timer_t*t) { struct ppp_fsm_t *layer=(struct ppp_fsm_t *)t->pd; @@ -486,4 +483,5 @@ static int restart_timer_func(struct triton_timer_t*t) ppp_fsm_timeout1(layer); return 0; -} +}*/ + diff --git a/accel-pptpd/ppp_ipcp.c b/accel-pptpd/ppp_ipcp.c index fc25230a..ad552bdd 100644 --- a/accel-pptpd/ppp_ipcp.c +++ b/accel-pptpd/ppp_ipcp.c @@ -519,14 +519,14 @@ static void ipcp_recv(struct ppp_handler_t*h) ppp_fsm_recv_conf_rej(&ipcp->fsm); break; case TERMREQ: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [IPCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_req(&ipcp->fsm); ppp_terminate(ipcp->ppp); break; case TERMACK: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [IPCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_ack(&ipcp->fsm); diff --git a/accel-pptpd/ppp_lcp.c b/accel-pptpd/ppp_lcp.c index dbc819a1..1f0431a7 100644 --- a/accel-pptpd/ppp_lcp.c +++ b/accel-pptpd/ppp_lcp.c @@ -532,14 +532,14 @@ static void lcp_recv(struct ppp_handler_t*h) ppp_fsm_recv_conf_rej(&lcp->fsm); break; case TERMREQ: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [LCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_req(&lcp->fsm); ppp_terminate(lcp->ppp); break; case TERMACK: - term_msg=strndup((uint8_t*)(hdr+1),ntohs(hdr->len)); + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); log_debug("recv [LCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); free(term_msg); ppp_fsm_recv_term_ack(&lcp->fsm); diff --git a/accel-pptpd/pptp.c b/accel-pptpd/pptp.c index a261b195..1ec35c8f 100644 --- a/accel-pptpd/pptp.c +++ b/accel-pptpd/pptp.c @@ -50,20 +50,22 @@ struct pptp_conn_t int out_size; int out_pos; + struct ppp_ctrl_t ctrl; struct ppp_t ppp; }; -static void pptp_read(struct triton_md_handler_t *h); -static void pptp_write(struct triton_md_handler_t *h); +static int pptp_read(struct triton_md_handler_t *h); +static int pptp_write(struct triton_md_handler_t *h); static void pptp_timeout(struct triton_md_handler_t *h); static void ppp_started(struct ppp_t *); static void ppp_finished(struct ppp_t *); static void disconnect(struct pptp_conn_t *conn) { - close(conn->hnd.fd); triton_md_unregister_handler(&conn->hnd); - free(conn); + close(conn->hnd.fd); + conn->hnd.fd=-1; + triton_unregister_ctx(&conn->ctx); } static int post_msg(struct pptp_conn_t *conn,void *buf,int size) @@ -125,7 +127,7 @@ static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn) ppp_terminate(&conn->ppp); conn->state=STATE_FIN; - conn->hnd.twait=1000; + //conn->hnd.twait=1000; return send_pptp_stop_ctrl_conn_rply(conn,PPTP_CONN_STOP_OK,0); } @@ -258,14 +260,16 @@ static int pptp_out_call_rqst(struct pptp_conn_t *conn) conn->ppp.fd=pptp_sock; conn->ppp.chan_name=strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr)); - conn->ppp.events.started=ppp_started; - conn->ppp.events.finished=ppp_finished; + conn->ppp.ctrl=&conn->ctrl; + conn->ctrl.ctx=&conn->ctx; + conn->ctrl.started=ppp_started; + conn->ctrl.finished=ppp_finished; if (establish_ppp(&conn->ppp)) { close(pptp_sock); send_pptp_stop_ctrl_conn_rqst(conn,0,0); conn->state=STATE_FIN; - conn->hnd.twait=1000; + //conn->hnd.twait=1000; }else conn->state=STATE_PPP; return 0; @@ -286,7 +290,7 @@ static int process_packet(struct pptp_conn_t *conn) return 0; } -static void pptp_read(struct triton_md_handler_t *h) +static int pptp_read(struct triton_md_handler_t *h) { struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd); struct pptp_header *hdr=(struct pptp_header *)conn->in_buf; @@ -295,9 +299,8 @@ static void pptp_read(struct triton_md_handler_t *h) n=read(h->fd,conn->in_buf,PPTP_CTRL_SIZE_MAX-conn->in_size); if (n<=0) { - if (errno==EAGAIN) return; - disconnect(conn); - return; + if (errno==EAGAIN) return 0; + goto drop; } conn->in_size+=n; if (conn->in_size>=sizeof(*hdr)) @@ -312,25 +315,25 @@ static void pptp_read(struct triton_md_handler_t *h) conn->in_size=0; } } - h->twait=TIMEOUT; - return; + //h->twait=TIMEOUT; + return 0; drop: disconnect(conn); - return; + return 1; } -static void pptp_write(struct triton_md_handler_t *h) +static int pptp_write(struct triton_md_handler_t *h) { struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd); int n=write(h->fd,conn->out_buf+conn->out_pos,conn->out_size-conn->out_pos); if (n<0) { - if (errno==EINTR) n=0; + if (errno==EAGAIN) n=0; else { log_debug("post_msg: failed to write socket %i\n",errno); disconnect(conn); - return; + return 1; } } @@ -341,12 +344,27 @@ static void pptp_write(struct triton_md_handler_t *h) conn->out_size=0; triton_md_disable_handler(h,MD_MODE_WRITE); } - h->twait=TIMEOUT; + return 0; + //h->twait=TIMEOUT; } static void pptp_timeout(struct triton_md_handler_t *h) { } - +static void pptp_close(struct triton_ctx_t *ctx) +{ + struct pptp_conn_t *conn=container_of(ctx,typeof(*conn),ctx); + if (conn->state==STATE_PPP) + ppp_terminate(&conn->ppp); + else + disconnect(conn); +} +static void pptp_free(struct triton_ctx_t *ctx) +{ + struct pptp_conn_t *conn=container_of(ctx,typeof(*conn),ctx); + free(conn->in_buf); + free(conn->out_buf); + free(conn); +} static void ppp_started(struct ppp_t *ppp) { log_msg("ppp_started\n"); @@ -359,11 +377,17 @@ static void ppp_finished(struct ppp_t *ppp) close(conn->ppp.fd); send_pptp_stop_ctrl_conn_rqst(conn,0,0); conn->state=STATE_FIN; - conn->hnd.twait=1000; + //conn->hnd.twait=1000; } //================================== +struct pptp_serv_t +{ + struct triton_ctx_t ctx; + struct triton_md_handler_t hnd; +}; + static int pptp_connect(struct triton_md_handler_t *h) { struct sockaddr_in addr; @@ -373,7 +397,7 @@ static int pptp_connect(struct triton_md_handler_t *h) while(1) { - sock=accept(f->fd,(struct sockaddr *)&addr,&size); + sock=accept(h->fd,(struct sockaddr *)&addr,&size); if (sock<0) { if (errno==EAGAIN) @@ -383,10 +407,11 @@ static int pptp_connect(struct triton_md_handler_t *h) } conn=malloc(sizeof(*conn)); memset(conn,0,sizeof(*conn)); - conn->hnd.fd=fd; + conn->hnd.fd=sock; conn->hnd.read=pptp_read; conn->hnd.write=pptp_write; - conn->hnd.close=pptp_close; + conn->ctx.close=pptp_close; + conn->ctx.free=pptp_free; conn->hnd.ctx=&conn->ctx; conn->in_buf=malloc(PPTP_CTRL_SIZE_MAX); conn->out_buf=malloc(PPTP_CTRL_SIZE_MAX); @@ -397,29 +422,23 @@ static int pptp_connect(struct triton_md_handler_t *h) } return 0; } -static void pptp_serv_close(struct triton_md_handler_t *h) +static void pptp_serv_close(struct triton_ctx_t *ctx) { - triton_md_unregister_handler(h); - close(h->fd); + struct pptp_serv_t *s=container_of(ctx,typeof(*s),ctx); + triton_md_unregister_handler(&s->hnd); + close(s->hnd.fd); } -struct pptp_serv_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; -}; - static struct pptp_serv_t serv= { .hnd.read=pptp_connect, - .hnd.close=pptp_serv_close, + .ctx.close=pptp_serv_close, .hnd.ctx=&serv.ctx, }; void __init pptp_init() { struct sockaddr_in addr; - socklen_t size; serv.hnd.fd=socket (PF_INET, SOCK_STREAM, 0); if (serv.hnd.fd<0) @@ -442,7 +461,7 @@ void __init pptp_init() { log_error("pptp: failed to listen socket\n"); close(serv.hnd.fd); - return -1; + return; } triton_register_ctx(&serv.ctx); diff --git a/accel-pptpd/triton/CMakeLists.txt b/accel-pptpd/triton/CMakeLists.txt index f2de0175..a531438c 100644 --- a/accel-pptpd/triton/CMakeLists.txt +++ b/accel-pptpd/triton/CMakeLists.txt @@ -1,10 +1,11 @@ SET(target triton) SET(sources_c md.c - conf_file.c timer.c - options.c + triton.c + conf_file.c loader.c + log.c ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/accel-pptpd/triton/conf_file.c b/accel-pptpd/triton/conf_file.c index 3ddb649e..026c4d3c 100644 --- a/accel-pptpd/triton/conf_file.c +++ b/accel-pptpd/triton/conf_file.c @@ -3,14 +3,13 @@ #include <unistd.h> #include <stdlib.h> -#include "conf_file.h" #include "triton_p.h" struct sect_t { struct list_head entry; - struct conf_file_sect_t *sect; + struct conf_sect_t *sect; }; static LIST_HEAD(sections); @@ -18,22 +17,22 @@ static LIST_HEAD(sections); static char* skip_space(char *str); static char* skip_word(char *str); -static struct conf_file_sect_t *find_sect(const char *name); -static struct conf_file_sect_t *create_sect(const char *name); -static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val); -static struct option_t *find_item(struct conf_file_sect_t *,const char *name); +static struct conf_sect_t *find_sect(const char *name); +static struct conf_sect_t *create_sect(const char *name); +static void sect_add_item(struct conf_sect_t *sect,const char *name,const char *val); +static struct conf_option_t *find_item(struct conf_sect_t *,const char *name); -void conf_file_load(const char *fname) +int conf_load(const char *fname) { char *buf,*str,*str2; char *path0,*path; int cur_line=0; - static struct conf_file_sect_t *cur_sect=NULL; + static struct conf_sect_t *cur_sect=NULL; FILE *f=fopen(fname,"r"); if (!f) { - perror("triton: open conf file"); - return; + perror("conf_file: open"); + return -1; } buf=(char*)malloc(1024); @@ -62,7 +61,7 @@ void conf_file_load(const char *fname) strcat(path,str+1); str=path; }*/ - conf_file_load(str); + conf_load(str); continue; } if (*str=='[') @@ -71,8 +70,8 @@ void conf_file_load(const char *fname) if (*str2!=']') { //L1: - printf("triton: sintax error in conf file %s line %i\n",fname,cur_line); - return; + fprintf(stderr,"conf_file:%s:%i: sintax error\n",fname,cur_line); + return -1; } *str2=0; cur_sect=find_sect(str); @@ -81,8 +80,8 @@ void conf_file_load(const char *fname) } if (!cur_sect) { - printf("triton: no section opened in conf file %s line %i\n",fname,cur_line); - return; + fprintf(stderr,"conf_file:%s:%i: no section opened\n",fname,cur_line); + return -1; } str2=skip_word(str); if (*str2==' ') @@ -98,7 +97,7 @@ void conf_file_load(const char *fname) if (*str2 && *(str2+1) && *str2=='$' && *(str2+1)=='{') { char *s; - struct option_t *opt; + struct conf_option_t *opt; for (s=str2+2; *s && *s!='}'; s++); if (*s=='}') { @@ -108,8 +107,8 @@ void conf_file_load(const char *fname) opt=find_item(cur_sect,str2); if (!opt) { - printf("triton: parent option not found int conf file %s line %i\n",fname,cur_line); - return; + fprintf(stderr,"conf_file:%s:%i: parent option not found\n",fname,cur_line); + return -1; } str2=opt->val; } @@ -121,6 +120,8 @@ void conf_file_load(const char *fname) free(path); free(path0); fclose(f); + + return 0; } static char* skip_space(char *str) @@ -134,7 +135,7 @@ static char* skip_word(char *str) return str; } -static struct conf_file_sect_t *find_sect(const char *name) +static struct conf_sect_t *find_sect(const char *name) { struct sect_t *s; list_for_each_entry(s,§ions,entry) @@ -144,11 +145,11 @@ static struct conf_file_sect_t *find_sect(const char *name) return NULL; } -static struct conf_file_sect_t *create_sect(const char *name) +static struct conf_sect_t *create_sect(const char *name) { struct sect_t *s=(struct sect_t *)malloc(sizeof(struct sect_t)); - s->sect=(struct conf_file_sect_t*)malloc(sizeof(struct conf_file_sect_t)); + s->sect=(struct conf_sect_t*)malloc(sizeof(struct conf_sect_t)); s->sect->name=(char*)strdup(name); INIT_LIST_HEAD(&s->sect->items); @@ -157,9 +158,9 @@ static struct conf_file_sect_t *create_sect(const char *name) return s->sect; } -static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val) +static void sect_add_item(struct conf_sect_t *sect,const char *name,const char *val) { - struct option_t *opt=(struct option_t *)malloc(sizeof(struct option_t)); + struct conf_option_t *opt=(struct conf_option_t *)malloc(sizeof(struct conf_option_t)); opt->name=(char*)strdup(name); opt->val=val?(char*)strdup(val):NULL; @@ -167,9 +168,9 @@ static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const c list_add_tail(&opt->entry,§->items); } -static struct option_t *find_item(struct conf_file_sect_t *sect,const char *name) +static struct conf_option_t *find_item(struct conf_sect_t *sect,const char *name) { - struct option_t *opt; + struct conf_option_t *opt; list_for_each_entry(opt,§->items,entry) { if (strcmp(opt->name,name)==0) @@ -179,7 +180,8 @@ static struct option_t *find_item(struct conf_file_sect_t *sect,const char *name return NULL; } -struct conf_file_sect_t *conf_file_get_section(const char *name) +struct conf_sect_t *conf_file_get_section(const char *name) { return find_sect(name); } + diff --git a/accel-pptpd/triton/conf_file.h b/accel-pptpd/triton/conf_file.h deleted file mode 100644 index 47ade313..00000000 --- a/accel-pptpd/triton/conf_file.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CONF_FILE_H -#define CONF_FILE_H - -#include "list.h" - -struct conf_file_sect_t -{ - const char *name; - - struct list_head items; -}; - -void conf_file_load(const char *fname); -struct conf_file_sect_t *conf_file_get_section(const char *name); - -#endif diff --git a/accel-pptpd/triton/loader.c b/accel-pptpd/triton/loader.c index 33d48315..a390f0a9 100644 --- a/accel-pptpd/triton/loader.c +++ b/accel-pptpd/triton/loader.c @@ -4,52 +4,5 @@ #include <stdio.h> #include <pthread.h> -#include "conf_file.h" #include "triton_p.h" -void md_init(void); -void event_init(void); -void timer_init(void); - -struct thread_arg_t -{ - int (*post_init)(void*); - void *arg; -}; - -void *thread(struct thread_arg_t *arg) -{ - printf("triton: starting new thread\n"); - #ifdef USE_CORO - coroutine_init(); - #endif - md_init(); - event_init(); - timer_init(); - - arg->post_init(arg->arg); - - free(arg); - - //conf_file_load(cf_name); - #ifdef USE_CORO - schedule(); - #else - md_run(); - #endif - - return NULL; -} - -int triton_init(const char *conf_file) -{ - return 0; -} -int triton_run(int (*post_init)(void*),void *arg) -{ - pthread_t thr; - struct thread_arg_t *thr_arg=malloc(sizeof(*thr_arg)); - thr_arg->post_init=post_init; - thr_arg->arg=arg; - return pthread_create(&thr,NULL,(void*(*)(void*))thread,thr_arg); -} diff --git a/accel-pptpd/triton/log.c b/accel-pptpd/triton/log.c new file mode 100644 index 00000000..39a9cb18 --- /dev/null +++ b/accel-pptpd/triton/log.c @@ -0,0 +1,34 @@ +#include <stdio.h> + +#include "triton_p.h" + +static FILE *f_error; +static FILE *f_debug; + +int log_init(void) +{ + char *log_error=conf_get_opt("core","log_error"); + char *log_debug=conf_get_opt("core","log_debug"); + + if (log_error) + { + f_error=fopen(log_error,"a"); + if (!f_error) + { + perror("log:log_error:open"); + return -1; + } + } + if (log_debug) + { + f_debug=fopen(log_debug,"a"); + if (!f_debug) + { + perror("log:log_debug:open"); + return -1; + } + } + + return 0; +} + diff --git a/accel-pptpd/triton/md.c b/accel-pptpd/triton/md.c index 3080c5a2..50e969c9 100644 --- a/accel-pptpd/triton/md.c +++ b/accel-pptpd/triton/md.c @@ -3,6 +3,7 @@ #include <sys/time.h> #include <signal.h> #include <string.h> +#include <errno.h> #include "triton_p.h" @@ -12,9 +13,9 @@ static int epoll_fd; static struct epoll_event *epoll_events; static pthread_t md_thr; -static void* md_thread(void *arg) +static void* md_thread(void *arg); -int md_init() +int md_init(void) { epoll_fd=epoll_create(1); if (epoll_fd<0) @@ -34,40 +35,42 @@ int md_init() } void md_run() { - pthread_create(&md_thr,md_thread,NULL); + pthread_create(&md_thr,NULL,md_thread,NULL); } void md_terminate() { - pthread_join(&md_thr); + pthread_cancel(md_thr); + pthread_join(md_thr,NULL); } static void* md_thread(void *arg) { int i,n,r; struct triton_md_handler_t *h; - - n=epoll_wait(epoll_fd,epoll_events,MAX_EVENTS,-1); - if (n<0) - { - if (errno!=EINTR) - perror("epoll_wait"); - continue; - } - if (n==0) - return; - - for(i=0; i<n; i++) + + while(1) { - h=(struct triton_md_handler_t*)epoll_events[i].data.ptr; - spin_lock(&h->ctx->lock); - h->trig_epoll_events=epoll_events[i].events; - list_add_tail(&h->entry2,&h->ctx->pending_handlers); - h->pending=1; - r=triton_queue_ctx(h->ctx); - spin_unlock(&h->ctx->lock); - if (r) - triton_thread_wakeup(ctx->thread); + n=epoll_wait(epoll_fd,epoll_events,max_events,-1); + if (n<0) + { + if (errno!=EINTR) + perror("epoll_wait"); + continue; + } + + for(i=0; i<n; i++) + { + h=(struct triton_md_handler_t*)epoll_events[i].data.ptr; + spin_lock(&h->ctx->lock); + h->trig_epoll_events=epoll_events[i].events; + list_add_tail(&h->entry2,&h->ctx->pending_handlers); + h->pending=1; + r=triton_queue_ctx(h->ctx); + spin_unlock(&h->ctx->lock); + if (r) + triton_thread_wakeup(h->ctx->thread); + } } } @@ -76,17 +79,17 @@ void triton_md_register_handler(struct triton_md_handler_t *h) h->epoll_event.data.ptr=h; if (!h->ctx) h->ctx=default_ctx; - pthread_mutex_lock(&h->ctx->lock); + spin_lock(&h->ctx->lock); list_add_tail(&h->entry,&h->ctx->handlers); - pthread_mutex_unlock(&h->ctx->lock); + spin_unlock(&h->ctx->lock); } void triton_md_unregister_handler(struct triton_md_handler_t *h) { - pthread_mutex_lock(&h->ctx->lock); + spin_lock(&h->ctx->lock); list_del(&h->entry); if (h->pending) list_del(&h->entry2); - pthread_lock_unlock(&h->ctx->lock); + spin_unlock(&h->ctx->lock); } int triton_md_enable_handler(struct triton_md_handler_t *h, int mode) { @@ -109,7 +112,9 @@ int triton_md_enable_handler(struct triton_md_handler_t *h, int mode) } int triton_md_disable_handler(struct triton_md_handler_t *h,int mode) { - if (h->epoll_events.events) + int r; + + if (!h->epoll_event.events) return -1; if (mode&MD_MODE_READ) diff --git a/accel-pptpd/triton/spinlock.h b/accel-pptpd/triton/spinlock.h index a75e29cb..7da93f8c 100644 --- a/accel-pptpd/triton/spinlock.h +++ b/accel-pptpd/triton/spinlock.h @@ -2,15 +2,17 @@ #define __TRITON_SPINLOCK_H #ifdef USE_SPINLOCK -typedef spinlock_t unsigned char; +typedef unsigned char spinlock_t; #define spin_lock(l) {while(__sync_lock_test_and_set(l,1);} #define spin_unlock(l) __sync_lock_release(l) #define SPINLOCK_INITIALIZER 0 #else -typedef spinlock_t pthread_mutex_t; +#include <pthread.h> +typedef pthread_mutex_t spinlock_t; #define spin_lock(l) pthread_mutex_lock(l) #define spin_unlock(l) pthread_mutex_unlock(l) #define SPINLOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define spinlock_init(l) pthread_mutex_init(l,NULL) #endif #endif diff --git a/accel-pptpd/triton/timer.c b/accel-pptpd/triton/timer.c index 57270f65..3adbde5a 100644 --- a/accel-pptpd/triton/timer.c +++ b/accel-pptpd/triton/timer.c @@ -4,22 +4,19 @@ #include <sys/epoll.h> #include <sys/timerfd.h> #include <string.h> +#include <errno.h> +#include <unistd.h> #include "triton_p.h" -static pthread_thread_t timer_thr; -static void *timer_thread(void *arg); - -static spinlock_t timers_lock=SPINLOCK_INITIALIZER; -static LIST_HEAD(timers); - -extern int max_events; -static epoll_fd; +int max_events=128; +static int epoll_fd; static struct epoll_event *epoll_events; -static void tv_add(struct timeval *tv,int msec); +static pthread_t timer_thr; +static void *timer_thread(void *arg); -void timer_init(void) +int timer_init(void) { epoll_fd=epoll_create(1); if (epoll_fd<0) @@ -34,6 +31,8 @@ void timer_init(void) fprintf(stderr,"cann't allocate memory\n"); return -1; } + + return 0; } void timer_run(void) @@ -43,8 +42,8 @@ void timer_run(void) void timer_terminate(void) { - pthread_cancel(&timer_thr); - pthread_join(&timer_thr); + pthread_cancel(timer_thr); + pthread_join(timer_thr,NULL); } void *timer_thread(void *arg) @@ -52,43 +51,44 @@ void *timer_thread(void *arg) int i,n,r; struct triton_timer_t *t; - n=epoll_wait(epoll_fd,epoll_events,MAX_EVENTS,-1); - if (n<0) + while(1) { - if (errno!=EINTR) - perror("epoll_wait"); - continue; - } - if (n==0) - return; - - for(i=0; i<n; i++) - { - t=(struct triton_md_handler_t*)epoll_events[i].data.ptr; - spin_lock(&t->ctx->lock); - list_add_tail(&t->entry2,&t->ctx->pending_timers); - t->pending=1; - r=triton_queue_ctx(t->ctx); - spin_unlock(&t->ctx->lock); - if (r) - triton_thread_wakeup(ctx->thread); + n=epoll_wait(epoll_fd,epoll_events,max_events,-1); + if (n<0) + { + if (errno!=EINTR) + perror("epoll_wait"); + continue; + } + + for(i=0; i<n; i++) + { + t=(struct triton_timer_t*)epoll_events[i].data.ptr; + spin_lock(&t->ctx->lock); + list_add_tail(&t->entry2,&t->ctx->pending_timers); + t->pending=1; + r=triton_queue_ctx(t->ctx); + spin_unlock(&t->ctx->lock); + if (r) + triton_thread_wakeup(t->ctx->thread); + } } } -int triton_timer_add(struct triton_timer_t *t) +int triton_timer_add(struct triton_timer_t *t, int abs_time) { t->epoll_event.data.ptr=t; t->epoll_event.events=EPOLLIN|EPOLLET; if (!t->ctx) t->ctx=default_ctx; - t->fd=timerfd_create(CLOCK_MONOTONIC,0); + t->fd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK); if (t->fd<0) { fprintf(stderr,"timer: timerfd_create failed: %s\n",strerror(errno)); return -1; } - if (triton_timer_mod(t)) + if (triton_timer_mod(t,abs_time)) { close(t->fd); return -1; @@ -110,10 +110,8 @@ int triton_timer_add(struct triton_timer_t *t) return 0; } -int triton_timer_mod(struct triton_timer_t *t) +int triton_timer_mod(struct triton_timer_t *t,int abs_time) { - int flags; - struct itimerspec ts= { .it_value.tv_sec=t->expire_tv.tv_sec, @@ -123,13 +121,9 @@ int triton_timer_mod(struct triton_timer_t *t) }; if (t->expire_tv.tv_sec==0 && t->expire_tv.tv_usec==0) - { - ts.it_value=ts.interval; - flags=0; - }else - flags=TFD_TIMER_ABSTIME; + ts.it_value=ts.it_interval; - if (timerfd_settime(t->fd,flags,&ts,NULL)) + if (timerfd_settime(t->fd,abs_time?TFD_TIMER_ABSTIME:0,&ts,NULL)) { fprintf(stderr,"timer: timerfd_settime failed: %s\n",strerror(errno)); return -1; diff --git a/accel-pptpd/triton/triton.c b/accel-pptpd/triton/triton.c index 23a69c60..e4fa117c 100644 --- a/accel-pptpd/triton/triton.c +++ b/accel-pptpd/triton/triton.c @@ -1,4 +1,8 @@ #include <signal.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> #include "triton_p.h" @@ -6,19 +10,19 @@ int thread_count=64; static spinlock_t threads_lock=SPINLOCK_INITIALIZER; static LIST_HEAD(threads); -static int threads_count; +static LIST_HEAD(sleep_threads); -static spinlock_t ctx_queue_lock=SPINLOCK_INITIALIZER; static LIST_HEAD(ctx_queue); static spinlock_t ctx_list_lock=SPINLOCK_INITIALIZER; static LIST_HEAD(ctx_list); struct triton_ctx_t *default_ctx; +static int terminate; void triton_thread_wakeup(struct triton_thread_t *thread) { - pthread_kill(&thread->thread,SIGUSR1); + pthread_kill(thread->thread,SIGUSR1); } static void* triton_thread(struct triton_thread_t *thread) @@ -36,19 +40,11 @@ static void* triton_thread(struct triton_thread_t *thread) { sigwait(&set,&sig); - if (thread->terminate) - return NULL; - cont: - if (thread->ctx->close) + if (thread->ctx->need_close) { - list_for_each_entry(h,&thread->ctx->handlers,entry) - if (h->close) - h->close(h); - list_for_each_entry(t,&thread->ctx->timers,entry) - if (t->close) - t->close(t); - thread->ctx->close=0; + thread->ctx->close(thread->ctx); + thread->ctx->need_close=0; } while (1) @@ -56,15 +52,15 @@ cont: spin_lock(&thread->ctx->lock); if (!list_empty(&thread->ctx->pending_timers)) { - t=list_entry(thread->ctx->pending_timers.next); + t=list_entry(thread->ctx->pending_timers.next,typeof(*t),entry2); list_del(&t->entry2); spin_unlock(&thread->ctx->lock); if (t->expire(t)) continue; } - if (!list_empty(&thread->ctx->pending_events)) + if (!list_empty(&thread->ctx->pending_handlers)) { - h=list_entry(thread->ctx->pending_events.next); + h=list_entry(thread->ctx->pending_handlers.next,typeof(*h),entry2); list_del(&h->entry2); h->pending=0; spin_unlock(&thread->ctx->lock); @@ -73,7 +69,7 @@ cont: if (h->read) if (h->read(h)) continue; - if (h->trig_epoll_events&(EPOLLOUT|EPOLLERR|EPOLLHUP)) + if (h->trig_epoll_events&(EPOLLOUT)) if (h->write) if (h->write(h)) continue; @@ -82,6 +78,8 @@ cont: } thread->ctx->thread=NULL; spin_unlock(&thread->ctx->lock); + if (thread->ctx->need_free) + thread->ctx->free(thread->ctx); thread->ctx=NULL; break; } @@ -89,18 +87,21 @@ cont: spin_lock(&threads_lock); if (!list_empty(&ctx_queue)) { - thread->ctx=list_entry(ctx_queue.next); + thread->ctx=list_entry(ctx_queue.next,typeof(*thread->ctx),entry2); list_del(&thread->ctx->entry2); spin_unlock(&threads_lock); spin_lock(&thread->ctx->lock); - ctx->thread=thread; - ctx->queue=0; + thread->ctx->thread=thread; + thread->ctx->queued=0; spin_unlock(&thread->ctx->lock); goto cont; }else { - list_add(&thread->entry,&threads); + if (!terminate) + list_add(&thread->entry2,&sleep_threads); spin_unlock(&threads_lock); + if (terminate) + return NULL; } } } @@ -110,21 +111,18 @@ struct triton_thread_t *create_thread() struct triton_thread_t *thread=malloc(sizeof(*thread)); memset(thread,0,sizeof(*thread)); - pthread_mutex_init(&thread->lock); - pthread_cond_init(&thread->cond); - pthread_create(&thread->thread,NULL,md_thread,thread); - ++threads_count; + pthread_create(&thread->thread,NULL,(void*(*)(void*))triton_thread,thread); return thread; } -void triton_queue_ctx(struct triton_ctx_t *ctx) +int triton_queue_ctx(struct triton_ctx_t *ctx) { if (ctx->thread || ctx->queued) return 0; spin_lock(&threads_lock); - if (list_empty(&threads)) + if (list_empty(&sleep_threads)) { list_add_tail(&ctx->entry2,&ctx_queue); spin_unlock(&threads_lock); @@ -132,8 +130,8 @@ void triton_queue_ctx(struct triton_ctx_t *ctx) return 0; } - ctx->thread=list_entry(threads.next); - list_del(&ctx->thread->entry); + ctx->thread=list_entry(sleep_threads.next,typeof(*ctx->thread),entry2); + list_del(&ctx->thread->entry2); spin_unlock(&threads_lock); return 1; @@ -141,7 +139,7 @@ void triton_queue_ctx(struct triton_ctx_t *ctx) void triton_register_ctx(struct triton_ctx_t *ctx) { - pthread_mutex_init(&ctx->lock); + spinlock_init(&ctx->lock); INIT_LIST_HEAD(&ctx->handlers); INIT_LIST_HEAD(&ctx->timers); INIT_LIST_HEAD(&ctx->pending_handlers); @@ -154,12 +152,13 @@ void triton_register_ctx(struct triton_ctx_t *ctx) void triton_unregister_ctx(struct triton_ctx_t *ctx) { + ctx->need_free=1; spin_lock(&ctx_list_lock); - list_add_tail(&ctx->entry,&ctx_list); + list_del(&ctx->entry); spin_unlock(&ctx_list_lock); } -int triton_init() +int triton_init(const char *conf_file) { default_ctx=malloc(sizeof(*default_ctx)); if (!default_ctx) @@ -169,10 +168,19 @@ int triton_init() } triton_register_ctx(default_ctx); + if (conf_load(conf_file)) + return -1; + + if (log_init()) + return -1; + if (md_init()) return -1; + if (timer_init()) return -1; + + return 0; } void triton_run() @@ -180,11 +188,13 @@ void triton_run() struct triton_thread_t *t; int i; - for(i=0;i<max_threads;i++) + for(i=0;i<thread_count;i++) { t=create_thread(); list_add_tail(&t->entry,&threads); + list_add_tail(&t->entry2,&sleep_threads); } + md_run(); timer_run(); } @@ -192,17 +202,29 @@ void triton_run() void triton_terminate() { struct triton_ctx_t *ctx; - pthread_mutex_lock(&ctx_list_lock); + struct triton_thread_t *t; + + md_terminate(); + timer_terminate(); + + spin_lock(&ctx_list_lock); list_for_each_entry(ctx,&ctx_list,entry) { - pthread_mutex_lock(&ctx->lock); - ctx->close=1; + spin_lock(&ctx->lock); + ctx->need_close=1; triton_queue_ctx(ctx); - pthread_mutex_unlock(&ctx->lock); + spin_unlock(&ctx->lock); } - pthread_mutex_unlock(&ctx_list_lock); + spin_unlock(&ctx_list_lock); - timer_terminate(); - md_terminate(); + spin_lock(&threads_lock); + terminate=1; + spin_unlock(&threads_lock); + + list_for_each_entry(t,&threads,entry) + triton_thread_wakeup(t); + + list_for_each_entry(t,&threads,entry) + pthread_join(t->thread,NULL); } diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h index 0e9b73bf..73640219 100644 --- a/accel-pptpd/triton/triton.h +++ b/accel-pptpd/triton/triton.h @@ -5,11 +5,13 @@ #include <pthread.h> #include <sys/epoll.h> -#include <triton.h> +#include "list.h" +#include "spinlock.h" struct triton_thread_t { struct list_head entry; + struct list_head entry2; pthread_t thread; int terminate:1; struct triton_ctx_t *ctx; @@ -23,11 +25,15 @@ struct triton_ctx_t struct list_head handlers; struct list_head timers; - triton_thread_t *thread; + struct triton_thread_t *thread; struct list_head pending_handlers; struct list_head pending_timers; int queued:1; - int close:1; + int need_close:1; + int need_free:1; + + void (*close)(struct triton_ctx_t*); + void (*free)(struct triton_ctx_t*); }; struct triton_md_handler_t @@ -38,7 +44,7 @@ struct triton_md_handler_t struct list_head entry2; struct triton_ctx_t *ctx; struct epoll_event epoll_event; - uint32_t trig_epoll_event; + uint32_t trig_epoll_events; int pending:1; //========= @@ -48,14 +54,16 @@ struct triton_md_handler_t int (*read)(struct triton_md_handler_t *); int (*write)(struct triton_md_handler_t *); - void (*close)(struct triton_md_handler_t *); //========= }; struct triton_timer_t { struct list_head entry; - int active; + struct list_head entry2; + struct epoll_event epoll_event; + struct triton_ctx_t *ctx; + int fd; int pending:1; struct timeval expire_tv; @@ -63,28 +71,36 @@ struct triton_timer_t int (*expire)(struct triton_timer_t *); }; +struct conf_option_t +{ + struct list_head entry; + + char *name; + char *val; +}; + +struct conf_sect_t +{ + const char *name; + struct list_head items; +}; + +void triton_register_ctx(struct triton_ctx_t *); +void triton_unregister_ctx(struct triton_ctx_t *); + #define MD_MODE_READ 1 #define MD_MODE_WRITE 2 void triton_md_register_handler(struct triton_md_handler_t *h); void triton_md_unregister_handler(struct triton_md_handler_t *h); -void triton_md_enable_handler(struct triton_md_handler_t *h, int mode); -void triton_md_disable_handler(struct triton_md_handler_t *h,int mode); -void triton_md_set_timeout(struct triton_md_handler_t *h, int msec); +int triton_md_enable_handler(struct triton_md_handler_t *h, int mode); +int triton_md_disable_handler(struct triton_md_handler_t *h,int mode); -void triton_timer_add(struct triton_timer_t*); +int triton_timer_add(struct triton_timer_t*,int abs_time); +int triton_timer_mod(struct triton_timer_t*,int abs_time); void triton_timer_del(struct triton_timer_t*); -typedef void (*triton_ss_func)(void); -void triton_timer_single_shot1(int twait,triton_ss_func,int argc,...); -void triton_timer_single_shot2(struct timeval *shot_tv,triton_ss_func,int argc,...); -void triton_timer_single_shot3(int tv_sec,int tv_usec,triton_ss_func,int argc,...); - -int triton_get_int_option(const char *str); -const char* triton_get_str_option(const char *str); -double triton_get_double_option(const char *str); - -void triton_terminate(void); -void triton_process_events(void); +struct conf_sect_t *conf_get_section(const char *name); +char *conf_get_opt(const char *sect, const char *name); #define TRITON_OK 0 #define TRITON_ERR_NOCOMP -1 @@ -96,6 +112,7 @@ void triton_process_events(void); #define TRITON_ERR_BUSY -5 int triton_init(const char *conf_file); -int triton_run(int (*post_init)(void*),void *arg); +void triton_run(void); +void triton_terminate(void); #endif diff --git a/accel-pptpd/triton/triton_p.h b/accel-pptpd/triton/triton_p.h index fae48487..e10c7a8e 100644 --- a/accel-pptpd/triton/triton_p.h +++ b/accel-pptpd/triton/triton_p.h @@ -4,39 +4,16 @@ #include "triton.h" #include "list.h" -#include <stdarg.h> - -#define MAX_ARGS 32 - -struct option_t -{ - struct list_head entry; - - char *name; - char *val; -}; - -struct timer_t -{ - struct list_head entry; - int del; - struct triton_timer_t *timer; -}; - -struct timer_single_shot_t -{ - struct list_head entry; - - struct timeval expire_tv; - int arg_cnt; - void *args; - triton_ss_func ss_func; -}; - -extern void md_run(); -extern void md_terminate(); -extern void timer_run(); -extern void timer_terminate(); -extern struct triton_ctx_t *default_ctx; +int log_init(void); +int md_init(); +void md_run(); +void md_terminate(); +int timer_init(); +void timer_run(); +void timer_terminate(); +struct triton_ctx_t *default_ctx; +int triton_queue_ctx(struct triton_ctx_t*); +void triton_thread_wakeup(struct triton_thread_t*); +int conf_load(const char *fname); #endif diff --git a/doc/rfc3079.txt b/doc/rfc3079.txt new file mode 100644 index 00000000..4d7ba0de --- /dev/null +++ b/doc/rfc3079.txt @@ -0,0 +1,1179 @@ + + + + + + +Network Working Group G. Zorn +Request for Comments: 3079 cisco Systems +Category: Informational March 2001 + + + Deriving Keys for use with Microsoft Point-to-Point Encryption (MPPE) + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2001). All Rights Reserved. + +Abstract + + The Point-to-Point Protocol (PPP) provides a standard method for + transporting multi-protocol datagrams over point-to-point links. + + The PPP Compression Control Protocol provides a method to negotiate + and utilize compression protocols over PPP encapsulated links. + + Microsoft Point to Point Encryption (MPPE) is a means of representing + PPP packets in an encrypted form. MPPE uses the RSA RC4 algorithm to + provide data confidentiality. The length of the session key to be + used for initializing encryption tables can be negotiated. MPPE + currently supports 40-bit, 56-bit and 128-bit session keys. MPPE + session keys are changed frequently; the exact frequency depends upon + the options negotiated, but may be every packet. MPPE is negotiated + within option 18 in the Compression Control Protocol. + + This document describes the method used to derive initial MPPE + session keys from a variety of credential types. It is expected that + this memo will be updated whenever Microsoft defines a new key + derivation method for MPPE, since its primary purpose is to provide + an open, easily accessible reference for third-parties wishing to + interoperate with Microsoft products. + + MPPE itself (including the protocol used to negotiate its use, the + details of the encryption method used and the algorithm used to + change session keys during a session) is described in RFC 3078. + + + + + + + +Zorn Informational [Page 1] + +RFC 3079 MPPE Key Derivation March 2001 + + +Table of Contents + + 1. Specification of Requirements ............................... 2 + 2. Deriving Session Keys from MS-CHAP Credentials .............. 2 + 2.1. Generating 40-bit Session Keys ............................ 3 + 2.2. Generating 56-bit Session Keys ............................ 3 + 2.3. Generating 128-bit Session Keys ........................... 4 + 2.4. Key Derivation Functions .................................. 5 + 2.5. Sample Key Derivations .................................... 6 + 2.5.1. Sample 40-bit Key Derivation ............................ 6 + 2.5.2. Sample 56-bit Key Derivation ............................ 6 + 2.5.3. Sample 128-bit Key Derivation ........................... 7 + 3. Deriving Session Keys from MS-CHAP-2 Credentials ............ 7 + 3.1. Generating 40-bit Session Keys ............................ 8 + 3.2. Generating 56-bit Session Keys ............................ 9 + 3.3. Generating 128-bit Session Keys ...........................10 + 3.4. Key Derivation Functions ..................................11 + 3.5. Sample Key Derivations ....................................13 + 3.5.1. Sample 40-bit Key Derivation ............................13 + 3.5.2. Sample 56-bit Key Derivation ............................14 + 3.5.3. Sample 128-bit Key Derivation ...........................15 + 4. Deriving MPPE Session Keys from TLS Session Keys ............16 + 4.1. Generating 40-bit Session Keys ............................16 + 4.2. Generating 56-bit Session Keys ............................17 + 4.3. Generating 128-bit Session Keys ...........................17 + 5. Security Considerations .....................................18 + 5.1. MS-CHAP Credentials .......................................18 + 5.2. EAP-TLS Credentials .......................................19 + 6. References ..................................................19 + 7. Acknowledgements ............................................20 + 8. Author's Address ............................................20 + 9. Full Copyright Statement ....................................21 + +1. Specification of Requirements + + In this document, the key words "MAY", "MUST, "MUST NOT", "optional", + "recommended", "SHOULD", and "SHOULD NOT" are to be interpreted as + described in [6]. + +2. Deriving Session Keys from MS-CHAP Credentials + + The Microsoft Challenge-Handshake Authentication Protocol (MS-CHAP-1) + [2] is a Microsoft-proprietary PPP [1] authentication protocol, + providing the functionality to which LAN-based users are accustomed + while integrating the encryption and hashing algorithms used on + Windows networks. + + + + + +Zorn Informational [Page 2] + +RFC 3079 MPPE Key Derivation March 2001 + + + The following sections detail the methods used to derive initial + session keys (40-, 56- and 128-bit) from MS-CHAP-1 credentials. + + Implementation Note + + The initial session key in both directions is derived from the + credentials of the peer that initiated the call and the challenge + used (if any) is the challenge from the first authentication. + This is true for both unilateral and bilateral authentication, as + well as for each link in a multilink bundle. In the multi-chassis + multilink case, implementations are responsible for ensuring that + the correct keys are generated on all participating machines. + +2.1. Generating 40-bit Session Keys + + MPPE uses a derivative of the peer's LAN Manager password as the 40- + bit session key used for initializing the RC4 encryption tables. + + The first step is to obfuscate the peer's password using the + LmPasswordHash() function (described in [2]). The first 8 octets of + the result are used as the basis for the session key generated in the + following way: + +/* +* PasswordHash is the basis for the session key +* SessionKey is a copy of PasswordHash and is the generative session key +* 8 is the length (in octets) of the key to be generated. +* +*/ +Get_Key(PasswordHash, SessionKey, 8) + +/* +* The effective length of the key is reduced to 40 bits by +* replacing the first three bytes as follows: +*/ +SessionKey[0] = 0xd1 ; +SessionKey[1] = 0x26 ; +SessionKey[2] = 0x9e ; + +2.2. Generating 56-bit Session Keys + + MPPE uses a derivative of the peer's LAN Manager password as the 56- + bit session key used for initializing the RC4 encryption tables. + + The first step is to obfuscate the peer's password using the + LmPasswordHash() function (described in [2]). The first 8 octets of + the result are used as the basis for the session key generated in the + following way: + + + +Zorn Informational [Page 3] + +RFC 3079 MPPE Key Derivation March 2001 + + +/* +* PasswordHash is the basis for the session key +* SessionKey is a copy of PasswordHash and is the generative session key +* 8 is the length (in octets) of the key to be generated. +* +*/ +Get_Key(PasswordHash, SessionKey, 8) + +/* +* The effective length of the key is reduced to 56 bits by +* replacing the first byte as follows: +*/ +SessionKey[0] = 0xd1 ; + +2.3. Generating 128-bit Session Keys + + MPPE uses a derivative of the peer's Windows NT password as the 128- + bit session key used for initializing encryption tables. + + The first step is to obfuscate the peer's password using + NtPasswordHash() function as described in [2]. The first 16 octets + of the result are then hashed again using the MD4 algorithm. The + first 16 octets of the second hash are used as the basis for the + session key generated in the following way: + +/* +* Challenge (as described in [9]) is sent by the PPP authenticator +* during authentication and is 8 octets long. +* NtPasswordHashHash is the basis for the session key. +* On return, InitialSessionKey contains the initial session +* key to be used. +*/ +Get_Start_Key(Challenge, NtPasswordHashHash, InitialSessionKey) + +/* +* CurrentSessionKey is a copy of InitialSessionKey +* and is the generative session key. +* Length (in octets) of the key to generate is 16. +* +*/ +Get_Key(InitialSessionKey, CurrentSessionKey, 16) + + + + + + + + + + +Zorn Informational [Page 4] + +RFC 3079 MPPE Key Derivation March 2001 + + +2.4. Key Derivation Functions + + The following procedures are used to derive the session key. + +/* + * Pads used in key derivation + */ + +SHApad1[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}; + +SHApad2[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}; + +/* + * SHAInit(), SHAUpdate() and SHAFinal() functions are an + * implementation of Secure Hash Algorithm (SHA-1) [7]. These are + * available in public domain or can be licensed from + * RSA Data Security, Inc. + * + * 1) InitialSessionKey is 8 octets long for 56- and 40-bit + * session keys, 16 octets long for 128 bit session keys. + * 2) CurrentSessionKey is same as InitialSessionKey when this + * routine is called for the first time for the session. + */ + +Get_Key( +IN InitialSessionKey, +IN/OUT CurrentSessionKey +IN LengthOfDesiredKey ) +{ + SHAInit(Context) + SHAUpdate(Context, InitialSessionKey, LengthOfDesiredKey) + SHAUpdate(Context, SHAPad1, 40) + SHAUpdate(Context, CurrentSessionKey, LengthOfDesiredKey) + SHAUpdate(Context, SHAPad2, 40) + SHAFinal(Context, Digest) + memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey) +} + +Get_Start_Key( +IN Challenge, + + + +Zorn Informational [Page 5] + +RFC 3079 MPPE Key Derivation March 2001 + + +IN NtPasswordHashHash, +OUT InitialSessionKey) +{ + SHAInit(Context) + SHAUpdate(Context, NtPasswordHashHash, 16) + SHAUpdate(Context, NtPasswordHashHash, 16) + SHAUpdate(Context, Challenge, 8) + SHAFinal(Context, Digest) + memcpy(InitialSessionKey, Digest, 16) +} + +2.5. Sample Key Derivations + + The following sections illustrate 40-, 56- and 128-bit key + derivations. All intermediate values are in hexadecimal. + +2.5.1. Sample 40-bit Key Derivation + + + Initial Values + Password = "clientPass" + + Step 1: LmPasswordHash(Password, PasswordHash) + PasswordHash = 76 a1 52 93 60 96 d7 83 0e 23 90 22 74 04 af d2 + + Step 2: Copy PasswordHash to SessionKey + SessionKey = 76 a1 52 93 60 96 d7 83 0e 23 90 22 74 04 af d2 + + Step 3: GetKey(PasswordHash, SessionKey, 8) + SessionKey = d8 08 01 53 8c ec 4a 08 + + Step 4: Reduce the effective key length to 40 bits + SessionKey = d1 26 9e 53 8c ec 4a 08 + +2.5.2. Sample 56-bit Key Derivation + + Initial Values + Password = "clientPass" + + Step 1: LmPasswordHash(Password, PasswordHash) + PasswordHash = 76 a1 52 93 60 96 d7 83 0e 23 90 22 74 04 af d2 + + Step 2: Copy PasswordHash to SessionKey + SessionKey = 76 a1 52 93 60 96 d7 83 0e 23 90 22 74 04 af d2 + + Step 3: GetKey(PasswordHash, SessionKey, 8) + SessionKey = d8 08 01 53 8c ec 4a 08 + + + + +Zorn Informational [Page 6] + +RFC 3079 MPPE Key Derivation March 2001 + + + Step 4: Reduce the effective key length to 56 bits + SessionKey = d1 08 01 53 8c ec 4a 08 + +2.5.3. Sample 128-bit Key Derivation + +Initial Values + Password = "clientPass" + Challenge = 10 2d b5 df 08 5d 30 41 + +Step 1: NtPasswordHash(Password, PasswordHash) + PasswordHash = 44 eb ba 8d 53 12 b8 d6 11 47 44 11 f5 69 89 ae + +Step 2: PasswordHashHash = MD4(PasswordHash) + PasswordHashHash = 41 c0 0c 58 4b d2 d9 1c 40 17 a2 a1 2f a5 9f 3f + +Step 3: GetStartKey(Challenge, PasswordHashHash, InitialSessionKey) + InitialSessionKey = a8 94 78 50 cf c0 ac ca d1 78 9f b6 2d dc dd b0 + +Step 4: Copy InitialSessionKey to CurrentSessionKey + CurrentSessionKey = a8 94 78 50 cf c0 ac c1 d1 78 9f b6 2d dc dd b0 + +Step 5: GetKey(InitialSessionKey, CurrentSessionKey, 16) + CurrentSessionKey = 59 d1 59 bc 09 f7 6f 1d a2 a8 6a 28 ff ec 0b 1e + +3. Deriving Session Keys from MS-CHAP-2 Credentials + + Version 2 of the Microsoft Challenge-Handshake Authentication + Protocol (MS-CHAP-2) [8] is a Microsoft-proprietary PPP + authentication protocol, providing the functionality to which LAN- + based users are accustomed while integrating the encryption and + hashing algorithms used on Windows networks. + + The following sections detail the methods used to derive initial + session keys from MS-CHAP-2 credentials. 40-, 56- and 128-bit keys + are all derived using the same algorithm from the authenticating + peer's Windows NT password. The only difference is in the length of + the keys and their effective strength: 40- and 56-bit keys are 8 + octets in length, while 128-bit keys are 16 octets long. Separate + keys are derived for the send and receive directions of the session. + + Implementation Note + + The initial session keys in both directions are derived from the + credentials of the peer that initiated the call and the challenges + used are those from the first authentication. This is true as + well for each link in a multilink bundle. In the multi-chassis + multilink case, implementations are responsible for ensuring that + the correct keys are generated on all participating machines. + + + +Zorn Informational [Page 7] + +RFC 3079 MPPE Key Derivation March 2001 + + +3.1. Generating 40-bit Session Keys + + When used in conjunction with MS-CHAP-2 authentication, the initial + MPPE session keys are derived from the peer's Windows NT password. + + The first step is to obfuscate the peer's password using + NtPasswordHash() function as described in [8]. + + NtPasswordHash(Password, PasswordHash) + + The first 16 octets of the result are then hashed again using the MD4 + algorithm. + + PasswordHashHash = md4(PasswordHash) + + The first 16 octets of this second hash are used together with the + NT- Response field from the MS-CHAP-2 Response packet [8] as the + basis for the master session key: + + GetMasterKey(PasswordHashHash, NtResponse, MasterKey) + + Once the master key has been generated, it is used to derive two 40- + bit session keys, one for sending and one for receiving: + + GetAsymmetricStartKey(MasterKey, MasterSendKey, 8, TRUE, TRUE) + GetAsymmetricStartKey(MasterKey, MasterReceiveKey, 8, FALSE, TRUE) + + The master session keys are never used to encrypt or decrypt data; + they are only used in the derivation of transient session keys. The + initial transient session keys are obtained by calling the function + GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 8, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 8, + ReceiveSessionKey) + + Next, the effective strength of both keys is reduced by setting the + first three octets to known constants: + + SendSessionKey[0] = ReceiveSessionKey[0] = 0xd1 + SendSessionKey[1] = ReceiveSessionKey[1] = 0x26 + SendSessionKey[2] = ReceiveSessionKey[2] = 0x9e + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 8, SendSessionKey) + rc4_key(ReceiveRC4key, 8, ReceiveSessionKey) + + + + +Zorn Informational [Page 8] + +RFC 3079 MPPE Key Derivation March 2001 + + +3.2. Generating 56-bit Session Keys + + When used in conjunction with MS-CHAP-2 authentication, the initial + MPPE session keys are derived from the peer's Windows NT password. + + The first step is to obfuscate the peer's password using + NtPasswordHash() function as described in [8]. + + NtPasswordHash(Password, PasswordHash) + + The first 16 octets of the result are then hashed again using the MD4 + algorithm. + + PasswordHashHash = md4(PasswordHash) + + The first 16 octets of this second hash are used together with the + NT-Response field from the MS-CHAP-2 Response packet [8] as the basis + for the master session key: + + GetMasterKey(PasswordHashHash, NtResponse, MasterKey) + + Once the master key has been generated, it is used to derive two + 56-bit session keys, one for sending and one for receiving: + + GetAsymmetricStartKey(MasterKey, MasterSendKey, 8, TRUE, TRUE) + GetAsymmetricStartKey(MasterKey, MasterReceiveKey, 8, FALSE, TRUE) + + The master session keys are never used to encrypt or decrypt data; + they are only used in the derivation of transient session keys. The + initial transient session keys are obtained by calling the function + GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 8, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 8, + ReceiveSessionKey) + + Next, the effective strength of both keys is reduced by setting the + first octet to a known constant: + + SendSessionKey[0] = ReceiveSessionKey[0] = 0xd1 + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 8, SendSessionKey) + rc4_key(ReceiveRC4key, 8, ReceiveSessionKey) + + + + + + +Zorn Informational [Page 9] + +RFC 3079 MPPE Key Derivation March 2001 + + +3.3. Generating 128-bit Session Keys + + When used in conjunction with MS-CHAP-2 authentication, the initial + MPPE session keys are derived from the peer's Windows NT password. + + The first step is to obfuscate the peer's password using + NtPasswordHash() function as described in [8]. + + NtPasswordHash(Password, PasswordHash) + + The first 16 octets of the result are then hashed again using the MD4 + algorithm. + + PasswordHashHash = md4(PasswordHash) + + The first 16 octets of this second hash are used together with the + NT-Response field from the MS-CHAP-2 Response packet [8] as the basis + for the master session key: + + GetMasterKey(PasswordHashHash, NtResponse, MasterKey) + + Once the master key has been generated, it is used to derive two + 128-bit master session keys, one for sending and one for receiving: + +GetAsymmetricStartKey(MasterKey, MasterSendKey, 16, TRUE, TRUE) +GetAsymmetricStartKey(MasterKey, MasterReceiveKey, 16, FALSE, TRUE) + + The master session keys are never used to encrypt or decrypt data; + they are only used in the derivation of transient session keys. The + initial transient session keys are obtained by calling the function + GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 16, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 16, + ReceiveSessionKey) + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 16, SendSessionKey) + rc4_key(ReceiveRC4key, 16, ReceiveSessionKey) + + + + + + + + + + + +Zorn Informational [Page 10] + +RFC 3079 MPPE Key Derivation March 2001 + + +3.4. Key Derivation Functions + + The following procedures are used to derive the session key. + +/* + * Pads used in key derivation + */ + +SHSpad1[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}; + +SHSpad2[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}; + +/* + * "Magic" constants used in key derivations + */ + +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}; + +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}; + +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, + + + +Zorn Informational [Page 11] + +RFC 3079 MPPE Key Derivation March 2001 + + + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e}; + + + GetMasterKey( + IN 16-octet PasswordHashHash, + IN 24-octet NTResponse, + OUT 16-octet MasterKey ) + { + 20-octet Digest + + ZeroMemory(Digest, sizeof(Digest)); + + /* + * SHSInit(), SHSUpdate() and SHSFinal() + * are an implementation of the Secure Hash Standard [7]. + */ + + SHSInit(Context); + SHSUpdate(Context, PasswordHashHash, 16); + SHSUpdate(Context, NTResponse, 24); + SHSUpdate(Context, Magic1, 27); + SHSFinal(Context, Digest); + + MoveMemory(MasterKey, Digest, 16); + } + + VOID + GetAsymetricStartKey( + IN 16-octet MasterKey, + OUT 8-to-16 octet SessionKey, + IN INTEGER SessionKeyLength, + IN BOOLEAN IsSend, + IN BOOLEAN IsServer ) + { + + 20-octet Digest; + + ZeroMemory(Digest, 20); + + if (IsSend) { + if (IsServer) { + s = Magic3 + } else { + s = Magic2 + } + } else { + if (IsServer) { + + + +Zorn Informational [Page 12] + +RFC 3079 MPPE Key Derivation March 2001 + + + s = Magic2 + } else { + s = Magic3 + } + } + + /* + * SHSInit(), SHSUpdate() and SHSFinal() + * are an implementation of the Secure Hash Standard [7]. + */ + + SHSInit(Context); + SHSUpdate(Context, MasterKey, 16); + SHSUpdate(Context, SHSpad1, 40); + SHSUpdate(Context, s, 84); + SHSUpdate(Context, SHSpad2, 40); + SHSFinal(Context, Digest); + + MoveMemory(SessionKey, Digest, SessionKeyLength); + } + +3.5. Sample Key Derivations + + The following sections illustrate 40-, 56- and 128-bit key + derivations. All intermediate values are in hexadecimal. + +3.5.1. Sample 40-bit Key Derivation + +Initial Values + UserName = "User" + = 55 73 65 72 + + Password = "clientPass" + = 63 00 6C 00 69 00 65 00 6E 00 + 74 00 50 00 61 00 73 00 73 00 + + AuthenticatorChallenge = 5B 5D 7C 7D 7B 3F 2F 3E 3C 2C + 60 21 32 26 26 28 + PeerChallenge = 21 40 23 24 25 5E 26 2A 28 29 5F 2B 3A 33 7C 7E + + Challenge = D0 2E 43 86 BC E9 12 26 + + NT-Response = + 82 30 9E CD 8D 70 8B 5E A0 8F AA 39 81 CD 83 54 42 33 + 11 4A 3D 85 D6 DF + +Step 1: NtPasswordHash(Password, PasswordHash) + PasswordHash = 44 EB BA 8D 53 12 B8 D6 11 47 44 11 F5 69 89 AE + + + +Zorn Informational [Page 13] + +RFC 3079 MPPE Key Derivation March 2001 + + +Step 2: PasswordHashHash = MD4(PasswordHash) + PasswordHashHash = 41 C0 0C 58 4B D2 D9 1C 40 17 A2 A1 2F A5 9F 3F + +Step 3: Derive the master key (GetMasterKey()) + MasterKey = FD EC E3 71 7A 8C 83 8C B3 88 E5 27 AE 3C DD 31 + +Step 4: Derive the master send session key (GetAsymmetricStartKey()) + SendStartKey40 = 8B 7C DC 14 9B 99 3A 1B + +Step 5: Derive the initial send session key (GetNewKeyFromSHA()) + SendSessionKey40 = D1 26 9E C4 9F A6 2E 3E + +Sample Encrypted Message + rc4(SendSessionKey40, "test message") = 92 91 37 91 7E 58 03 D6 + 68 D7 58 98 + +3.5.2. Sample 56-bit Key Derivation + +Initial Values + UserName = "User" + = 55 73 65 72 + + Password = "clientPass" + = 63 00 6C 00 69 00 65 00 6E 00 74 00 50 + 00 61 00 73 00 73 00 + + AuthenticatorChallenge = 5B 5D 7C 7D 7B 3F 2F 3E 3C 2C + 60 21 32 26 26 28 + PeerChallenge = 21 40 23 24 25 5E 26 2A 28 29 5F 2B 3A 33 7C 7E + + Challenge = D0 2E 43 86 BC E9 12 26 + + NT-Response = + 82 30 9E CD 8D 70 8B 5E A0 8F AA 39 81 CD 83 54 42 33 + 11 4A 3D 85 D6 DF + +Step 1: NtPasswordHash(Password, PasswordHash) + PasswordHash = 44 EB BA 8D 53 12 B8 D6 11 47 44 11 F5 69 89 AE + +Step 2: PasswordHashHash = MD4(PasswordHash) + PasswordHashHash = 41 C0 0C 58 4B D2 D9 1C 40 17 A2 A1 2F A5 9F 3F + +Step 3: Derive the master key (GetMasterKey()) + MasterKey = FD EC E3 71 7A 8C 83 8C B3 88 E5 27 AE 3C DD 31 + +Step 4: Derive the master send session key (GetAsymmetricStartKey()) + SendStartKey56 = 8B 7C DC 14 9B 99 3A 1B + + + + +Zorn Informational [Page 14] + +RFC 3079 MPPE Key Derivation March 2001 + + +Step 5: Derive the initial send session key (GetNewKeyFromSHA()) + SendSessionKey56 = D1 5C 00 C4 9F A6 2E 3E + +Sample Encrypted Message + rc4(SendSessionKey40, "test message") = 3F 10 68 33 FA 44 8D + A8 42 BC 57 58 + +3.5.3. Sample 128-bit Key Derivation + +Initial Values + UserName = "User" + = 55 73 65 72 + + Password = "clientPass" + = 63 00 6C 00 69 00 65 00 6E 00 + 74 00 50 00 61 00 73 00 73 00 + + AuthenticatorChallenge = 5B 5D 7C 7D 7B 3F 2F 3E 3C 2C + 60 21 32 26 26 28 + + PeerChallenge = 21 40 23 24 25 5E 26 2A 28 29 5F 2B 3A 33 7C 7E + + Challenge = D0 2E 43 86 BC E9 12 26 + + NT-Response = + 82 30 9E CD 8D 70 8B 5E A0 8F AA 39 81 CD 83 54 42 33 + 11 4A 3D 85 D6 DF + +Step 1: NtPasswordHash(Password, PasswordHash) + PasswordHash = 44 EB BA 8D 53 12 B8 D6 11 47 44 11 F5 69 89 AE + +Step 2: PasswordHashHash = MD4(PasswordHash) + PasswordHashHash = 41 C0 0C 58 4B D2 D9 1C 40 17 A2 A1 2F A5 9F 3F + +Step 2: Derive the master key (GetMasterKey()) + MasterKey = FD EC E3 71 7A 8C 83 8C B3 88 E5 27 AE 3C DD 31 + +Step 3: Derive the send master session key (GetAsymmetricStartKey()) + + SendStartKey128 = 8B 7C DC 14 9B 99 3A 1B A1 18 CB 15 3F 56 DC CB + +Step 4: Derive the initial send session key (GetNewKeyFromSHA()) + SendSessionKey128 = 40 5C B2 24 7A 79 56 E6 E2 11 00 7A E2 7B 22 D4 + +Sample Encrypted Message + rc4(SendSessionKey128, "test message") = 81 84 83 17 DF 68 + 84 62 72 FB 5A BE + + + + +Zorn Informational [Page 15] + +RFC 3079 MPPE Key Derivation March 2001 + + +4. Deriving MPPE Session Keys from TLS Session Keys + + The Extensible Authentication Protocol (EAP) [10] is a PPP extension + that provides support for additional authentication methods within + PPP. Transport Level Security (TLS) [11] provides for mutual + authentication, integrity-protected ciphersuite negotiation and key + exchange between two endpoints. EAP-TLS [12] is an EAP + authentication type which allows the use of TLS within the PPP + authentication framework. The following sections describe the + methods used to derive initial session keys from TLS session keys. + 56-, 40- and 128-bit keys are derived using the same algorithm. The + only difference is in the length of the keys and their effective + strength: 56- and 40-bit keys are 8 octets in length, while 128-bit + keys are 16 octets long. Separate keys are derived for the send and + receive directions of the session. + +4.1. Generating 40-bit Session Keys + + When MPPE is used in conjunction with EAP-TLS authentication, the TLS + master secret is used as the master session key. + + The algorithm used to derive asymmetrical master session keys from + the TLS master secret is described in [12]. The master session keys + are never used to encrypt or decrypt data; they are only used in the + derivation of transient session keys. + + Implementation Note + + If the asymmetrical master keys are less than 8 octets in length, + they MUST be padded on the left with zeroes before being used to + derive the initial transient session keys. Conversely, if the + asymmetrical master keys are more than 8 octets in length, they + must be truncated to 8 octets before being used to derive the + initial transient session keys. + + The initial transient session keys are obtained by calling the + function GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 8, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 8, +ReceiveSessionKey) + + Next, the effective strength of both keys is reduced by setting the + first three octets to known constants: + + SendSessionKey[0] = ReceiveSessionKey[0] = 0xD1 + SendSessionKey[1] = ReceiveSessionKey[1] = 0x26 + SendSessionKey[2] = ReceiveSessionKey[2] = 0x9E + + + +Zorn Informational [Page 16] + +RFC 3079 MPPE Key Derivation March 2001 + + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 8, SendSessionKey) + rc4_key(ReceiveRC4key, 8, ReceiveSessionKey) + +4.2. Generating 56-bit Session Keys + + When MPPE is used in conjunction with EAP-TLS authentication, the TLS + master secret is used as the master session key. + + The algorithm used to derive asymmetrical master session keys from + the TLS master secret is described in [12]. The master session keys + are never used to encrypt or decrypt data; they are only used in the + derivation of transient session keys. + + Implementation Note + + If the asymmetrical master keys are less than 8 octets in length, + they MUST be padded on the left with zeroes before being used to + derive the initial transient session keys. Conversely, if the + asymmetrical master keys are more than 8 octets in length, they + must be truncated to 8 octets before being used to derive the + initial transient session keys. + + The initial transient session keys are obtained by calling the + function GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 8, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 8, +ReceiveSessionKey) + + Next, the effective strength of both keys is reduced by setting the + initial octet to a known constant: + + SendSessionKey[0] = ReceiveSessionKey[0] = 0xD1 + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 8, SendSessionKey) + rc4_key(ReceiveRC4key, 8, ReceiveSessionKey) + +4.3. Generating 128-bit Session Keys + + When MPPE is used in conjunction with EAP-TLS authentication, the TLS + master secret is used as the master session key. + + + + + + +Zorn Informational [Page 17] + +RFC 3079 MPPE Key Derivation March 2001 + + + The algorithm used to derive asymmetrical master session keys from + the TLS master secret is described in [12]. Note that the send key + on one side is the receive key on the other. + + The master session keys are never used to encrypt or decrypt data; + they are only used in the derivation of transient session keys. + + Implementation Note + + If the asymmetrical master keys are less than 16 octets in length, + they MUST be padded on the left with zeroes before being used to + derive the initial transient session keys. Conversely, if the + asymmetrical master keys are more than 16 octets in length, they + must be truncated to 16 octets before being used to derive the + initial transient session keys. + + The initial transient session keys are obtained by calling the + function GetNewKeyFromSHA() (described in [3]): + +GetNewKeyFromSHA(MasterSendKey, MasterSendKey, 16, SendSessionKey) +GetNewKeyFromSHA(MasterReceiveKey, MasterReceiveKey, 16, +ReceiveSessionKey) + + Finally, the RC4 tables are initialized using the new session keys: + + rc4_key(SendRC4key, 16, SendSessionKey) + rc4_key(ReceiveRC4key, 16, ReceiveSessionKey) + +5. Security Considerations + +5.1. MS-CHAP Credentials + + Because of the way in which 40-bit keys are derived from MS-CHAP-1 + credentials, the initial 40-bit session key will be identical in all + sessions established under the same peer credentials. For this + reason, and because RC4 with a 40-bit key length is believed to be a + relatively weak cipher, peers SHOULD NOT use 40-bit keys derived from + the LAN Manager password hash (as described above) if it can be + avoided. + + Since the MPPE session keys are derived from user passwords (in the + MS- CHAP-1 and MS-CHAP-2 cases), care should be taken to ensure the + selection of strong passwords and passwords should be changed + frequently. + + + + + + + +Zorn Informational [Page 18] + +RFC 3079 MPPE Key Derivation March 2001 + + +5.2. EAP-TLS Credentials + + The strength of the session keys is dependent upon the security of + the TLS protocol. + + The EAP server may be on a separate machine from the PPP + authenticator; if this is the case, adequate care must be taken in + the transmission of the EAP-TLS master keys to the authenticator. + +6. References + + [1] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51, RFC + 1661, July 1994. + + [2] Zorn, G. and S. Cobb, "Microsoft PPP CHAP Extensions", RFC 2433, + October 1998. + + [3] Pall, G. and G. Zorn, "Microsoft Point-to-Point Encryption + (MPPE) RFC 3078, March 2001. + + [4] RC4 is a proprietary encryption algorithm available under + license from RSA Data Security Inc. For licensing information, + contact: + RSA Data Security, Inc. + 100 Marine Parkway + Redwood City, CA 94065-1031 + + [5] Pall, G., "Microsoft Point-to-Point Compression (MPPC) + Protocol", RFC 2118, March 1997. + + [6] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [7] "Secure Hash Standard", Federal Information Processing Standards + Publication 180-1, National Institute of Standards and + Technology, April 1995. + + [8] Zorn, G., "Microsoft PPP CHAP Extensions, Version 2", RFC 2759, + January 2000. + + [9] Simpson, W., "PPP Challenge Handshake Authentication Protocol + (CHAP)", RFC 1994, August 1996. + + [10] Blunk, L. and J. Vollbrecht, "PPP Extensible Authentication + Protocol (EAP)", RFC 2284, March 1998. + + + + + + +Zorn Informational [Page 19] + +RFC 3079 MPPE Key Derivation March 2001 + + + [11] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC + 2246, January 1999. + + [12] Aboba, B. and D. Simon, "PPP EAP TLS Authentication Protocol", + RFC 2716, October 1999. + +7. Acknowledgements + + Anthony Bell, Richard B. Ward, Terence Spies and Thomas Dimitri, all + of Microsoft Corporation, significantly contributed to the design and + development of MPPE. + + Additional thanks to Robert Friend, Joe Davies, Jody Terrill, Archie + Cobbs, Mark Deuser, Vijay Baliga, Brad Robel-Forrest and Jeff Haag + for useful feedback. + + The technical portions of this memo were completed while the author + was employed by Microsoft Corporation. + +8. Author's Address + + Questions about this memo can also be directed to: + + Glen Zorn + cisco Systems + 500 108th Avenue N.E. + Suite 500 + Bellevue, Washington 98004 + USA + + Phone: +1 425 438 8218 + FAX: +1 425 438 1848 + EMail: gwz@cisco.com + + + + + + + + + + + + + + + + + + +Zorn Informational [Page 20] + +RFC 3079 MPPE Key Derivation March 2001 + + +9. Full Copyright Statement + + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Zorn Informational [Page 21] + |