diff options
author | Kozlov Dmitry <dima@server> | 2010-09-09 11:01:43 +0400 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-09-09 11:01:43 +0400 |
commit | 29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5 (patch) | |
tree | 7e530a420c4c303706e39cc917f0ad8ea5d657e2 /accel-pptpd | |
parent | 4dcca9422c5c001789b17c3266f3db8e0590568d (diff) | |
download | accel-ppp-29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5.tar.gz accel-ppp-29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5.zip |
radius: implemented accounting (start/stop/interim-update)
Diffstat (limited to 'accel-pptpd')
-rw-r--r-- | accel-pptpd/accel-pptpd.conf | 2 | ||||
-rw-r--r-- | accel-pptpd/auth/auth_chap_md5.c | 7 | ||||
-rw-r--r-- | accel-pptpd/auth/auth_mschap_v1.c | 18 | ||||
-rw-r--r-- | accel-pptpd/auth/auth_mschap_v2.c | 19 | ||||
-rw-r--r-- | accel-pptpd/auth/auth_pap.c | 4 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp.c | 33 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp.h | 10 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_auth.c | 3 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_auth.h | 2 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_notify.c | 20 | ||||
-rw-r--r-- | accel-pptpd/radius/CMakeLists.txt | 2 | ||||
-rw-r--r-- | accel-pptpd/radius/acct.c | 181 | ||||
-rw-r--r-- | accel-pptpd/radius/auth.c | 173 | ||||
-rw-r--r-- | accel-pptpd/radius/dictionary | 4 | ||||
-rw-r--r-- | accel-pptpd/radius/packet.c | 15 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.c | 194 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.h | 28 | ||||
-rw-r--r-- | accel-pptpd/radius/req.c | 180 |
18 files changed, 665 insertions, 230 deletions
diff --git a/accel-pptpd/accel-pptpd.conf b/accel-pptpd/accel-pptpd.conf index 1e3bc92..2c7b33f 100644 --- a/accel-pptpd/accel-pptpd.conf +++ b/accel-pptpd/accel-pptpd.conf @@ -23,5 +23,5 @@ nas-identifier=pptp nas-ip-address=127.0.0.1 gw-ip-address=192.168.100.100 auth_server=127.0.0.1:1812,testing123 -acct_server=127.0.0.1:1813,secret +acct_server=127.0.0.1:1813,testing123 verbose=1 diff --git a/accel-pptpd/auth/auth_chap_md5.c b/accel-pptpd/auth/auth_chap_md5.c index 0bcec37..1abf63b 100644 --- a/accel-pptpd/auth/auth_chap_md5.c +++ b/accel-pptpd/auth/auth_chap_md5.c @@ -251,18 +251,17 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h }else { chap_send_success(ad); - auth_successed(ad->ppp); + auth_successed(ad->ppp, name); } free(passwd); } else if (r == PWDB_DENIED) { chap_send_failure(ad); auth_failed(ad->ppp); + free(name); } else { chap_send_success(ad); - auth_successed(ad->ppp); + auth_successed(ad->ppp, name); } - - free(name); } static struct ppp_auth_handler_t chap= diff --git a/accel-pptpd/auth/auth_mschap_v1.c b/accel-pptpd/auth/auth_mschap_v1.c index 595fb15..4a7341b 100644 --- a/accel-pptpd/auth/auth_mschap_v1.c +++ b/accel-pptpd/auth/auth_mschap_v1.c @@ -82,7 +82,7 @@ struct chap_auth_data_t 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 int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *res, char *name); static void print_buf(const uint8_t *buf,int size) { @@ -209,6 +209,7 @@ static void chap_send_challenge(struct chap_auth_data_t *ad) static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) { struct chap_response_t *msg=(struct chap_response_t*)hdr; + char *name; log_debug("recv [MSCHAP-v1 Response id=%x <", msg->hdr.id); print_buf(msg->lm_hash,24); @@ -222,24 +223,27 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h { log_error("mschap-v1: id mismatch\n"); chap_send_failure(ad); - ppp_terminate(ad->ppp, 0); + auth_failed(ad->ppp); } 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); + auth_failed(ad->ppp); } - if (chap_check_response(ad,msg)) + name = strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2); + + if (chap_check_response(ad, msg, name)) { chap_send_failure(ad); auth_failed(ad->ppp); + free(name); }else { chap_send_success(ad); - auth_successed(ad->ppp); + auth_successed(ad->ppp, name); } } @@ -272,17 +276,15 @@ static void des_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *outpu memcpy(output,res,8); } -static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg) +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, char *name) { 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) { diff --git a/accel-pptpd/auth/auth_mschap_v2.c b/accel-pptpd/auth/auth_mschap_v2.c index 01127cf..6f1de0e 100644 --- a/accel-pptpd/auth/auth_mschap_v2.c +++ b/accel-pptpd/auth/auth_mschap_v2.c @@ -95,7 +95,7 @@ struct chap_auth_data_t 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 int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *res, char *name); static void print_buf(const uint8_t *buf,int size) { @@ -289,6 +289,7 @@ static void chap_send_challenge(struct chap_auth_data_t *ad) static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) { struct chap_response_t *msg=(struct chap_response_t*)hdr; + char *name; log_debug("recv [MSCHAP-v2 Response id=%x <", msg->hdr.id); print_buf(msg->peer_challenge,16); @@ -312,14 +313,22 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h ppp_terminate(ad->ppp, 0); } - if (chap_check_response(ad,msg)) + name=strndup(msg->name,ntohs(msg->hdr.len)-sizeof(*msg)+2); + if (!name) { + log_error("mschap-v2: out of memory\n"); + auth_failed(ad->ppp); + return; + } + + if (chap_check_response(ad, msg, name)) { chap_send_failure(ad); auth_failed(ad->ppp); + free(name); }else { chap_send_success(ad,msg); - auth_successed(ad->ppp); + auth_successed(ad->ppp, name); } } @@ -352,7 +361,7 @@ static void des_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *outpu memcpy(output,res,8); } -static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg) +static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, char *name) { MD4_CTX md4_ctx; SHA_CTX sha_ctx; @@ -361,10 +370,8 @@ static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response 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) { diff --git a/accel-pptpd/auth/auth_pap.c b/accel-pptpd/auth/auth_pap.c index 7337468..288bccb 100644 --- a/accel-pptpd/auth/auth_pap.c +++ b/accel-pptpd/auth/auth_pap.c @@ -184,13 +184,13 @@ static int pap_recv_req(struct pap_auth_data_t *p,struct pap_hdr_t *hdr) pap_send_nak(p, hdr->id); auth_failed(p->ppp); ret=-1; + free(peer_id); } else { pap_send_ack(p, hdr->id); - auth_successed(p->ppp); + auth_successed(p->ppp, peer_id); ret = 0; } - free(peer_id); free(passwd); return ret; diff --git a/accel-pptpd/ppp/ppp.c b/accel-pptpd/ppp/ppp.c index 247f819..1e2ed86 100644 --- a/accel-pptpd/ppp/ppp.c +++ b/accel-pptpd/ppp/ppp.c @@ -10,6 +10,7 @@ #include <arpa/inet.h> #include <linux/ppp_defs.h> #include <linux/if_ppp.h> +#include <openssl/md5.h> #include "triton.h" @@ -20,7 +21,7 @@ int conf_ppp_verbose; static LIST_HEAD(layers); -int sock_fd; +int __export sock_fd; struct layer_node_t { @@ -46,6 +47,28 @@ static void free_ppp(struct ppp_t *ppp) { free(ppp->chan_buf); free(ppp->unit_buf); + + if (ppp->username) + free(ppp->username); +} + +static void generate_sessionid(struct ppp_t *ppp) +{ + MD5_CTX ctx; + uint8_t md5[MD5_DIGEST_LENGTH]; + int i; + + MD5_Init(&ctx); + MD5_Update(&ctx,&ppp->unit_idx, 4); + MD5_Update(&ctx,&ppp->unit_fd, 4); + MD5_Update(&ctx,&ppp->chan_fd, 4); + MD5_Update(&ctx,&ppp->fd, 4); + MD5_Update(&ctx,&ppp->start_time, sizeof(time_t)); + MD5_Update(&ctx,ppp->ctrl->ctx, sizeof(void *)); + MD5_Final(md5,&ctx); + + for( i = 0; i < 16; i++) + sprintf(ppp->sessionid + i*2, "%02X", md5[i]); } int __export establish_ppp(struct ppp_t *ppp) @@ -90,6 +113,9 @@ int __export establish_ppp(struct ppp_t *ppp) goto exit_close_unit; } + ppp->start_time = time(NULL); + generate_sessionid(ppp); + log_info("connect: ppp%i <--> pptp(%s)\n",ppp->unit_idx,ppp->chan_name); ppp->chan_buf=malloc(PPP_MRU); @@ -131,7 +157,7 @@ int __export establish_ppp(struct ppp_t *ppp) log_debug("ppp established\n"); - ppp_notify_started(ppp); + ppp_notify_starting(ppp); start_first_layer(ppp); return 0; @@ -298,6 +324,7 @@ void __export ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) if (n->entry.next==&ppp->layers) { ppp->ctrl->started(ppp); + ppp_notify_started(ppp); }else { n=list_entry(n->entry.next,typeof(*n),entry); @@ -339,6 +366,8 @@ void __export ppp_terminate(struct ppp_t *ppp, int hard) log_debug("ppp_terminate\n"); + ppp_notify_finishing(ppp); + if (hard) { destablish_ppp(ppp); return; diff --git a/accel-pptpd/ppp/ppp.h b/accel-pptpd/ppp/ppp.h index e287b7b..a82e975 100644 --- a/accel-pptpd/ppp/ppp.h +++ b/accel-pptpd/ppp/ppp.h @@ -2,6 +2,7 @@ #define PPP_H #include <sys/types.h> +#include <time.h> #include "triton.h" #include "list.h" @@ -41,6 +42,8 @@ #define PPP_LAYER_CCP 3 #define PPP_LAYER_IPCP 4 +#define PPP_SESSIONID_LEN 32 + struct ppp_t; struct ppp_ctrl_t @@ -53,7 +56,9 @@ struct ppp_ctrl_t struct ppp_notified_t { struct list_head entry; + void (*starting)(struct ppp_notified_t *, struct ppp_t *); void (*started)(struct ppp_notified_t *, struct ppp_t *); + void (*finishing)(struct ppp_notified_t *, struct ppp_t *); void (*finished)(struct ppp_notified_t *, struct ppp_t *); void (*authenticated)(struct ppp_notified_t *, struct ppp_t *); }; @@ -76,6 +81,9 @@ struct ppp_t int unit_idx; char *chan_name; + char sessionid[PPP_SESSIONID_LEN+1]; + time_t start_time; + char *username; struct ppp_ctrl_t *ctrl; @@ -143,7 +151,9 @@ struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *, struct ppp_layer_t void ppp_register_notified(struct ppp_notified_t *); void ppp_unregister_notified(struct ppp_notified_t *); +void ppp_notify_starting(struct ppp_t *ppp); void ppp_notify_started(struct ppp_t *ppp); +void ppp_notify_finishing(struct ppp_t *ppp); void ppp_notify_finished(struct ppp_t *ppp); extern int conf_ppp_verbose; diff --git a/accel-pptpd/ppp/ppp_auth.c b/accel-pptpd/ppp/ppp_auth.c index b767fdb..0a362e6 100644 --- a/accel-pptpd/ppp/ppp_auth.c +++ b/accel-pptpd/ppp/ppp_auth.c @@ -296,10 +296,11 @@ static void auth_layer_free(struct ppp_layer_data_t *ld) free(ad); } -void __export auth_successed(struct ppp_t *ppp) +void __export auth_successed(struct ppp_t *ppp, char *username) { struct auth_layer_data_t *ad=container_of(ppp_find_layer_data(ppp,&auth_layer),typeof(*ad),ld); log_debug("auth_layer_started\n"); + ppp->username = username; ppp_layer_started(ppp,&ad->ld); } diff --git a/accel-pptpd/ppp/ppp_auth.h b/accel-pptpd/ppp/ppp_auth.h index f1880d5..f858d33 100644 --- a/accel-pptpd/ppp/ppp_auth.h +++ b/accel-pptpd/ppp/ppp_auth.h @@ -27,7 +27,7 @@ struct ppp_auth_handler_t int ppp_auth_register_handler(struct ppp_auth_handler_t*); -void auth_successed(struct ppp_t *ppp); +void auth_successed(struct ppp_t *ppp, char *username); void auth_failed(struct ppp_t *ppp); #endif diff --git a/accel-pptpd/ppp/ppp_notify.c b/accel-pptpd/ppp/ppp_notify.c index 94ceb6d..ad9fd1f 100644 --- a/accel-pptpd/ppp/ppp_notify.c +++ b/accel-pptpd/ppp/ppp_notify.c @@ -12,6 +12,16 @@ void __export ppp_unregister_notified(struct ppp_notified_t *n) list_del(&n->entry); } +void ppp_notify_starting(struct ppp_t *ppp) +{ + struct ppp_notified_t *n; + + list_for_each_entry(n, ¬ified_list, entry) { + if (n->starting) + n->starting(n, ppp); + } +} + void ppp_notify_started(struct ppp_t *ppp) { struct ppp_notified_t *n; @@ -32,3 +42,13 @@ void ppp_notify_finished(struct ppp_t *ppp) } } +void ppp_notify_finishing(struct ppp_t *ppp) +{ + struct ppp_notified_t *n; + + list_for_each_entry(n, ¬ified_list, entry) { + if (n->finishing) + n->finishing(n, ppp); + } +} + diff --git a/accel-pptpd/radius/CMakeLists.txt b/accel-pptpd/radius/CMakeLists.txt index 17a8578..9655d91 100644 --- a/accel-pptpd/radius/CMakeLists.txt +++ b/accel-pptpd/radius/CMakeLists.txt @@ -4,6 +4,8 @@ SET(sources dict.c req.c packet.c + auth.c + acct.c ) ADD_LIBRARY(radius SHARED ${sources}) diff --git a/accel-pptpd/radius/acct.c b/accel-pptpd/radius/acct.c new file mode 100644 index 0000000..b342b33 --- /dev/null +++ b/accel-pptpd/radius/acct.c @@ -0,0 +1,181 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/if_ppp.h> +#include <openssl/md5.h> + +#include "log.h" +#include "radius.h" + +static int req_set_RA(struct rad_req_t *req, const char *secret) +{ + MD5_CTX ctx; + + if (rad_packet_build(req->pack, req->RA)) + return -1; + + MD5_Init(&ctx); + MD5_Update(&ctx, req->pack->buf, req->pack->len); + MD5_Update(&ctx, secret, strlen(secret)); + MD5_Final(req->pack->buf + 4, &ctx); + + return 0; +} + +static void req_set_stat(struct rad_req_t *req, struct ppp_t *ppp) +{ + struct ifpppstatsreq ifreq; + + memset(&ifreq, 0, sizeof(ifreq)); + ifreq.stats_ptr = (void *)&ifreq.stats; + sprintf(ifreq.ifr__name, "ppp%i", ppp->unit_idx); + + if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) { + log_error("radius: failed to get ppp statistics: %s\n", strerror(errno)); + return; + } + + rad_req_change_int(req, "Acct-Input-Octets", ifreq.stats.p.ppp_ibytes); + rad_req_change_int(req, "Acct-Output-Octets", ifreq.stats.p.ppp_obytes); + rad_req_change_int(req, "Acct-Input-Packets", ifreq.stats.p.ppp_ipackets); + rad_req_change_int(req, "Acct-Output-Packets", ifreq.stats.p.ppp_opackets); + rad_req_change_int(req, "Acct-Session-Time", time(NULL) - ppp->start_time); +} + +static int rad_acct_read(struct triton_md_handler_t *h) +{ + struct rad_req_t *req = container_of(h, typeof(*req), hnd); + + req->reply = rad_packet_recv(h->fd); + if (!req->reply) + return 0; + + if (conf_verbose) { + log_debug("send "); + rad_packet_print(req->reply, log_debug); + } + + if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) { + rad_packet_free(req->reply); + req->reply = NULL; + } else { + req->pack->id++; + req->timeout.period = 0; + triton_timer_del(&req->timeout); + } + + return 0; +} + +static void rad_acct_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + rad_req_send(req); +} + +static void rad_acct_interim_update(struct triton_timer_t *t) +{ + struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer); + + if (rpd->acct_req->timeout.period) + return; + + rad_req_change_val(rpd->acct_req, "Acct-Status-Type", "Interim-Update", 4); + req_set_stat(rpd->acct_req, rpd->ppp); + req_set_RA(rpd->acct_req, conf_acct_server_secret); + rad_req_send(rpd->acct_req); + rpd->acct_req->timeout.period = conf_timeout * 1000; + triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_req->timeout, 0); +} + +int rad_acct_start(struct radius_pd_t *rpd) +{ + rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ppp->username); + if (!rpd->acct_req) { + log_error("radius: out of memory\n"); + return -1; + } + + if (rad_req_acct_fill(rpd->acct_req)) { + log_error("radius:acct: failed to fill accounting attributes\n"); + goto out_err; + } + + //if (rad_req_add_val(rpd->acct_req, "Acct-Status-Type", "Start", 4)) + // goto out_err; + //if (rad_req_add_str(rpd->acct_req, "Acct-Session-Id", rpd->ppp->sessionid, PPP_SESSIONID_LEN, 1)) + // goto out_err; + + if (req_set_RA(rpd->acct_req, conf_acct_server_secret)) + goto out_err; + + if (rad_req_send(rpd->acct_req)) + goto out_err; + + rpd->acct_req->hnd.read = rad_acct_read; + + triton_md_register_handler(rpd->ppp->ctrl->ctx, &rpd->acct_req->hnd); + if (triton_md_enable_handler(&rpd->acct_req->hnd, MD_MODE_READ)) + goto out_err; + + rpd->acct_req->timeout.expire = rad_acct_timeout; + rpd->acct_req->timeout.period = conf_timeout * 1000; + if (triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_req->timeout, 0)) { + triton_md_unregister_handler(&rpd->acct_req->hnd); + goto out_err; + } + + rpd->acct_interim_timer.expire = rad_acct_interim_update; + rpd->acct_interim_timer.period = rpd->acct_interim_interval * 1000; + if (rpd->acct_interim_interval && triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_interim_timer, 0)) { + triton_md_unregister_handler(&rpd->acct_req->hnd); + triton_timer_del(&rpd->acct_req->timeout); + goto out_err; + } + return 0; + +out_err: + rad_req_free(rpd->acct_req); + rpd->acct_req = NULL; + return -1; +} + +void rad_acct_stop(struct radius_pd_t *rpd) +{ + int i; + + if (rpd->acct_interim_timer.period) + triton_timer_del(&rpd->acct_interim_timer); + + if (rpd->acct_req) { + triton_md_unregister_handler(&rpd->acct_req->hnd); + if (rpd->acct_req->timeout.period) + triton_timer_del(&rpd->acct_req->timeout); + + rad_req_change_val(rpd->acct_req, "Acct-Status-Type", "Stop", 4); + req_set_stat(rpd->acct_req, rpd->ppp); + req_set_RA(rpd->acct_req, conf_acct_server_secret); + /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", ""); + for(i = 0; i < conf_max_try; i++) { + if (rad_req_send(rpd->acct_req)) + break; + rad_req_wait(rpd->acct_req, conf_timeout); + if (!rpd->acct_req->reply) + continue; + if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) { + rad_packet_free(rpd->acct_req->reply); + rpd->acct_req->reply = NULL; + } else + break; + } + if (!rpd->acct_req->reply) + log_warn("radius:acct_stop: no response\n"); + + rad_req_free(rpd->acct_req); + rpd->acct_req = NULL; + } +} + diff --git a/accel-pptpd/radius/auth.c b/accel-pptpd/radius/auth.c new file mode 100644 index 0000000..98c7aa8 --- /dev/null +++ b/accel-pptpd/radius/auth.c @@ -0,0 +1,173 @@ +#include <stdlib.h> +#include <string.h> +#include <openssl/md5.h> + +#include "log.h" +#include "pwdb.h" + +#include "radius.h" + + +static uint8_t* encrypt_password(const char *passwd, const char *secret, const uint8_t *RA, int *epasswd_len) +{ + uint8_t *epasswd; + int i, j, chunk_cnt; + uint8_t b[16], c[16]; + MD5_CTX ctx; + + chunk_cnt = (strlen(passwd) - 1) / 16 + 1; + + epasswd = malloc(chunk_cnt * 16); + if (!epasswd) { + log_error("radius: out of memory\n"); + return NULL; + } + + memset(epasswd, 0, chunk_cnt * 16); + memcpy(epasswd, passwd, strlen(passwd)); + memcpy(c, RA, 16); + + for (i = 0; i < chunk_cnt; i++) { + MD5_Init(&ctx); + MD5_Update(&ctx, secret, strlen(secret)); + MD5_Update(&ctx, c, 16); + MD5_Final(b, &ctx); + + for(j = 0; j < 16; j++) + epasswd[i * 16 + j] ^= b[j]; + + memcpy(c, epasswd + i * 16, 16); + } + + *epasswd_len = chunk_cnt * 16; + return epasswd; +} + +int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) +{ + struct rad_req_t *req; + int i, r = PWDB_DENIED; + //int id = va_arg(args, int); + const char *passwd = va_arg(args, const char *); + uint8_t *epasswd; + int epasswd_len; + + req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + if (!req) + return PWDB_DENIED; + + epasswd = encrypt_password(passwd, conf_auth_server_secret, req->RA, &epasswd_len); + if (!epasswd) + goto out; + + if (rad_req_add_str(req, "Password", (char*)epasswd, epasswd_len, 0)) { + free(epasswd); + goto out; + } + + free(epasswd); + + for(i = 0; i < conf_max_try; i++) { + if (rad_req_send(req)) + goto out; + + rad_req_wait(req, conf_timeout); + + if (req->reply) { + if (req->reply->id != req->pack->id) { + rad_packet_free(req->reply); + req->reply = NULL; + } else + break; + } + } + + if (req->reply && req->reply->code == CODE_ACCESS_ACCEPT) { + rad_proc_attrs(req); + r = PWDB_SUCCESS; + } + +out: + rad_req_free(req); + + return r; +} + +int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args) +{ + struct rad_req_t *req; + int i, r = PWDB_DENIED; + char chap_password[17]; + + int id = va_arg(args, int); + const uint8_t *challenge = va_arg(args, const uint8_t *); + int challenge_len = va_arg(args, int); + const uint8_t *response = va_arg(args, const uint8_t *); + + chap_password[0] = id; + memcpy(chap_password + 1, response, 16); + + req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + if (!req) + return PWDB_DENIED; + + if (challenge_len == 16) + memcpy(req->RA, challenge, 16); + else { + if (rad_req_add_str(req, "CHAP-Challenge", (char*)challenge, challenge_len, 0)) + goto out; + } + + if (rad_req_add_str(req, "CHAP-Password", chap_password, 17, 0)) + goto out; + + for(i = 0; i < conf_max_try; i++) { + if (rad_req_send(req)) + goto out; + + rad_req_wait(req, conf_timeout); + + if (req->reply) { + if (req->reply->id != req->pack->id) { + rad_packet_free(req->reply); + req->reply = NULL; + } else + break; + } + } + + if (!req->reply) + log_warn("radius:auth: no response\n"); + else if (req->reply->code == CODE_ACCESS_ACCEPT) { + rad_proc_attrs(req); + r = PWDB_SUCCESS; + } + +out: + rad_req_free(req); + + return r; +} + +int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args) +{ + /*int id = va_arg(args, int); + const uint8_t *challenge = va_arg(args, const uint8_t *); + const uint8_t *lm_response = va_arg(args, const uint8_t *); + const uint8_t *nt_response = va_arg(args, const uint8_t *); + int flags = va_arg(args, int);*/ + return PWDB_NO_IMPL; +} + +int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args) +{ + /*int id = va_arg(args, int); + const uint8_t *challenge = va_arg(args, const uint8_t *); + const uint8_t *peer_challenge = va_arg(args, const uint8_t *); + const uint8_t *response = va_arg(args, const uint8_t *); + int flags = va_arg(args, int); + uint8_t *authenticator = va_arg(args, uint8_t *);*/ + return PWDB_NO_IMPL; +} + + diff --git a/accel-pptpd/radius/dictionary b/accel-pptpd/radius/dictionary index caebe9d..25896eb 100644 --- a/accel-pptpd/radius/dictionary +++ b/accel-pptpd/radius/dictionary @@ -82,6 +82,8 @@ ATTRIBUTE Port-Limit 62 integer ATTRIBUTE Login-LAT-Port 63 integer ATTRIBUTE Connect-Info 77 string +ATTRIBUTE Acct-Interim-Interval 85 integer + # # RFC3162 IPv6 attributes # @@ -162,7 +164,7 @@ VALUE Login-Service PortMaster 3 VALUE Acct-Status-Type Start 1 VALUE Acct-Status-Type Stop 2 -VALUE Acct-Status-Type Alive 3 +VALUE Acct-Status-Type Interim-Update 3 VALUE Acct-Status-Type Accounting-On 7 VALUE Acct-Status-Type Accounting-Off 8 diff --git a/accel-pptpd/radius/packet.c b/accel-pptpd/radius/packet.c index 627b6c5..e88e6e8 100644 --- a/accel-pptpd/radius/packet.c +++ b/accel-pptpd/radius/packet.c @@ -42,7 +42,11 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) struct rad_req_attr_t *attr; uint8_t *ptr; - ptr = malloc(pack->len); + if (pack->buf) + ptr = realloc(pack->buf, pack->len); + else + ptr = malloc(pack->len); + if (!ptr) { log_error("radius:packet: out of memory\n"); return -1; @@ -77,8 +81,7 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) ptr += attr->len; } - print_buf(pack->buf, pack->len); - + //print_buf(pack->buf, pack->len); return 0; } @@ -220,6 +223,12 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, case CODE_ACCESS_REJECT: print("Access-Reject"); break; + case CODE_ACCOUNTING_REQUEST: + printf("Accounting-Request"); + break; + case CODE_ACCOUNTING_RESPONSE: + printf("Accounting-Response"); + break; default: print("Unknown (%i)", pack->code); } diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c index 89eb9fe..89491b3 100644 --- a/accel-pptpd/radius/radius.c +++ b/accel-pptpd/radius/radius.c @@ -5,8 +5,6 @@ #include <unistd.h> #include <arpa/inet.h> -#include <openssl/md5.h> - #include "log.h" #include "ppp.h" #include "pwdb.h" @@ -35,173 +33,16 @@ char *conf_acct_server_secret; static struct ppp_notified_t notified; -static struct radius_pd_t *find_pd(struct ppp_t *ppp); - -static void proc_attrs(struct rad_req_t *req) +void rad_proc_attrs(struct rad_req_t *req) { struct rad_req_attr_t *attr; list_for_each_entry(attr, &req->reply->attrs, entry) { - if (!strcmp(attr->attr->name, "Framed-IP-Address")) { + if (!strcmp(attr->attr->name, "Framed-IP-Address")) req->rpd->ipaddr = attr->val.ipaddr; - } - } -} - -static uint8_t* encrypt_password(const char *passwd, const char *secret, const uint8_t *RA, int *epasswd_len) -{ - uint8_t *epasswd; - int i, j, chunk_cnt; - uint8_t b[16], c[16]; - MD5_CTX ctx; - - chunk_cnt = (strlen(passwd) - 1) / 16 + 1; - - epasswd = malloc(chunk_cnt * 16); - if (!epasswd) { - log_error("radius: out of memory\n"); - return NULL; - } - - memset(epasswd, 0, chunk_cnt * 16); - memcpy(epasswd, passwd, strlen(passwd)); - memcpy(c, RA, 16); - - for (i = 0; i < chunk_cnt; i++) { - MD5_Init(&ctx); - MD5_Update(&ctx, secret, strlen(secret)); - MD5_Update(&ctx, c, 16); - MD5_Final(b, &ctx); - - for(j = 0; j < 16; j++) - epasswd[i * 16 + j] ^= b[j]; - - memcpy(c, epasswd + i * 16, 16); - } - - *epasswd_len = chunk_cnt * 16; - return epasswd; -} - -static int check_pap(struct radius_pd_t *rpd, const char *username, va_list args) -{ - struct rad_req_t *req; - int i, r = PWDB_DENIED; - //int id = va_arg(args, int); - const char *passwd = va_arg(args, const char *); - uint8_t *epasswd; - int epasswd_len; - - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!req) - return PWDB_DENIED; - - req->server_name = conf_auth_server; - req->server_port = conf_auth_server_port; - - epasswd = encrypt_password(passwd, conf_auth_server_secret, req->RA, &epasswd_len); - if (!epasswd) - goto out; - - if (rad_req_add_str(req, "Password", (char*)epasswd, epasswd_len, 0)) { - free(epasswd); - goto out; - } - - free(epasswd); - - for(i = 0; i < conf_max_try; i++) { - if (rad_req_send(req)) - goto out; - - rad_req_wait(req, conf_timeout); - - if (req->reply) - break; - } - - if (req->reply && req->reply->code == CODE_ACCESS_ACCEPT) { - proc_attrs(req); - r = PWDB_SUCCESS; - } - -out: - rad_req_free(req); - - return r; -} - -static int check_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args) -{ - struct rad_req_t *req; - int i, r = PWDB_DENIED; - char chap_password[17]; - - int id = va_arg(args, int); - const uint8_t *challenge = va_arg(args, const uint8_t *); - int challenge_len = va_arg(args, int); - const uint8_t *response = va_arg(args, const uint8_t *); - - chap_password[0] = id; - memcpy(chap_password + 1, response, 16); - - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!req) - return PWDB_DENIED; - - req->server_name = conf_auth_server; - req->server_port = conf_auth_server_port; - - if (challenge_len == 16) - memcpy(req->RA, challenge, 16); - else { - if (rad_req_add_str(req, "CHAP-Challenge", (char*)challenge, challenge_len, 0)) - goto out; + else if (!strcmp(attr->attr->name, "Acct-Interim-Interval")) + req->rpd->acct_interim_interval = attr->val.integer; } - - if (rad_req_add_str(req, "CHAP-Password", chap_password, 17, 0)) - goto out; - - for(i = 0; i < conf_max_try; i++) { - if (rad_req_send(req)) - goto out; - - rad_req_wait(req, conf_timeout); - - if (req->reply) - break; - } - - if (req->reply && req->reply->code == CODE_ACCESS_ACCEPT) { - proc_attrs(req); - r = PWDB_SUCCESS; - } - -out: - rad_req_free(req); - - return r; -} - -static int check_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args) -{ - /*int id = va_arg(args, int); - const uint8_t *challenge = va_arg(args, const uint8_t *); - const uint8_t *lm_response = va_arg(args, const uint8_t *); - const uint8_t *nt_response = va_arg(args, const uint8_t *); - int flags = va_arg(args, int);*/ - return PWDB_DENIED; -} - -static int check_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args) -{ - /*int id = va_arg(args, int); - const uint8_t *challenge = va_arg(args, const uint8_t *); - const uint8_t *peer_challenge = va_arg(args, const uint8_t *); - const uint8_t *response = va_arg(args, const uint8_t *); - int flags = va_arg(args, int); - uint8_t *authenticator = va_arg(args, uint8_t *);*/ - return PWDB_DENIED; } static int check(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username, int type, va_list _args) @@ -215,19 +56,19 @@ static int check(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username, i switch(type) { case PPP_PAP: - r = check_pap(rpd, username, args); + r = rad_auth_pap(rpd, username, args); break; case PPP_CHAP: chap_type = va_arg(args, int); switch(chap_type) { case CHAP_MD5: - r = check_chap_md5(rpd, username, args); + r = rad_auth_chap_md5(rpd, username, args); break; case MSCHAP_V1: - r = check_mschap_v1(rpd, username, args); + r = rad_auth_mschap_v1(rpd, username, args); break; case MSCHAP_V2: - r = check_mschap_v2(rpd, username, args); + r = rad_auth_mschap_v2(rpd, username, args); break; } break; @@ -254,7 +95,7 @@ static int get_ip(struct ppp_t *ppp, in_addr_t *addr, in_addr_t *peer_addr) return -1; } -static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp) +static void ppp_starting(struct ppp_notified_t *n, struct ppp_t *ppp) { struct radius_pd_t *pd = malloc(sizeof(*pd)); @@ -264,6 +105,19 @@ static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp) list_add_tail(&pd->pd.entry, &ppp->pd_list); } +static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp) +{ + struct radius_pd_t *rpd = find_pd(ppp); + + if (rad_acct_start(rpd)) + ppp_terminate(rpd->ppp, 0); +} +static void ppp_finishing(struct ppp_notified_t *n, struct ppp_t *ppp) +{ + struct radius_pd_t *rpd = find_pd(ppp); + + rad_acct_stop(rpd); +} static void ppp_finished(struct ppp_notified_t *n, struct ppp_t *ppp) { struct radius_pd_t *rpd = find_pd(ppp); @@ -272,7 +126,7 @@ static void ppp_finished(struct ppp_notified_t *n, struct ppp_t *ppp) free(rpd); } -static struct radius_pd_t *find_pd(struct ppp_t *ppp) +struct radius_pd_t *find_pd(struct ppp_t *ppp) { struct ppp_pd_t *pd; struct radius_pd_t *rpd; @@ -297,7 +151,9 @@ static struct pwdb_t pwdb = { }; static struct ppp_notified_t notified = { + .starting = ppp_starting, .started = ppp_started, + .finishing = ppp_finishing, .finished = ppp_finished, }; diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h index 40b8320..c167151 100644 --- a/accel-pptpd/radius/radius.h +++ b/accel-pptpd/radius/radius.h @@ -18,11 +18,20 @@ #define CODE_ACCESS_REJECT 3 #define CODE_ACCESS_CHALLENGE 11 +#define CODE_ACCOUNTING_REQUEST 4 +#define CODE_ACCOUNTING_RESPONSE 5 + + struct radius_pd_t { struct ppp_pd_t pd; struct ppp_t *ppp; + + struct rad_req_t *acct_req; + struct triton_timer_t acct_interim_timer; + in_addr_t ipaddr; + int acct_interim_interval; }; typedef union @@ -92,8 +101,13 @@ extern int conf_timeout; extern int conf_verbose; extern char *conf_nas_identifier; extern char *conf_nas_ip_address; +extern char *conf_gw_ip_address; extern char *conf_auth_server; +extern char *conf_auth_server_secret; +extern int conf_auth_server_port; extern char *conf_acct_server; +extern char *conf_acct_server_secret; +extern int conf_acct_server_port; int rad_dict_load(const char *fname); void rad_dict_free(struct rad_dict_t *dict); @@ -103,12 +117,16 @@ struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *, const struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *, rad_value_t val); struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username); +int rad_req_acct_fill(struct rad_req_t *); void rad_req_free(struct rad_req_t *); int rad_req_send(struct rad_req_t *); int rad_req_wait(struct rad_req_t *, int); +struct rad_req_attr_t *rad_req_find_attr(struct rad_req_t *req, const char *name); int rad_req_add_int(struct rad_req_t *req, const char *name, int val); int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, int len); int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, int len, int printable); +int rad_req_change_int(struct rad_req_t *req, const char *name, int val); +int rad_req_change_val(struct rad_req_t *req, const char *name, const char *val, int len); struct rad_packet_t *rad_packet_alloc(int code); int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA); @@ -116,6 +134,16 @@ struct rad_packet_t *rad_packet_recv(int fd); void rad_packet_free(struct rad_packet_t *); void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...)); +struct radius_pd_t *find_pd(struct ppp_t *ppp); +void rad_proc_attrs(struct rad_req_t *req); + +int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args); +int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args); +int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args); +int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args); + +int rad_acct_start(struct radius_pd_t *rpd); +void rad_acct_stop(struct radius_pd_t *rpd); #endif diff --git a/accel-pptpd/radius/req.c b/accel-pptpd/radius/req.c index cc59a43..3d71bf8 100644 --- a/accel-pptpd/radius/req.c +++ b/accel-pptpd/radius/req.c @@ -7,7 +7,6 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include "triton.h" #include "log.h" #include "radius.h" @@ -26,8 +25,9 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u memset(req, 0, sizeof(*req)); req->rpd = rpd; req->hnd.fd = -1; - req->hnd.read = rad_req_read; - req->timeout.expire = rad_req_timeout; + + req->server_name = conf_auth_server; + req->server_port = conf_auth_server_port; while (1) { if (read(urandom_fd, req->RA, 16) != 16) { @@ -64,6 +64,31 @@ out_err: return NULL; } +int rad_req_acct_fill(struct rad_req_t *req) +{ + req->server_name = conf_acct_server; + req->server_port = conf_acct_server_port; + + memset(req->RA, 0, sizeof(req->RA)); + + if (rad_req_add_val(req, "Acct-Status-Type", "Start", 4)) + return -1; + if (rad_req_add_str(req, "Acct-Session-Id", req->rpd->ppp->sessionid, PPP_SESSIONID_LEN, 1)) + return -1; + if (rad_req_add_int(req, "Acct-Session-Time", 0)) + return -1; + if (rad_req_add_int(req, "Acct-Input-Octets", 0)) + return -1; + if (rad_req_add_int(req, "Acct-Output-Octets", 0)) + return -1; + if (rad_req_add_int(req, "Acct-Input-Packets", 0)) + return -1; + if (rad_req_add_int(req, "Acct-Output-Packets", 0)) + return -1; + + return 0; +} + void rad_req_free(struct rad_req_t *req) { if (req->hnd.fd >= 0 ) @@ -75,46 +100,58 @@ void rad_req_free(struct rad_req_t *req) free(req); } -int rad_req_send(struct rad_req_t *req) +static int make_socket(struct rad_req_t *req) { struct sockaddr_in addr; - int n; - - if (req->hnd.fd == -1) { - req->hnd.fd = socket(PF_INET, SOCK_DGRAM, 0); - if (req->hnd.fd < 0) { - log_error("radius:socket: %s\n", strerror(errno)); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - if (conf_nas_ip_address) { - addr.sin_addr.s_addr = inet_addr(conf_nas_ip_address); - if (bind(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) { - log_error("radius:bind: %s\n", strerror(errno)); - goto out_err; - } - } + req->hnd.fd = socket(PF_INET, SOCK_DGRAM, 0); + if (req->hnd.fd < 0) { + log_error("radius:socket: %s\n", strerror(errno)); + return -1; + } - addr.sin_addr.s_addr = inet_addr(req->server_name); - addr.sin_port = htons(req->server_port); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; - if (connect(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) { - log_error("radius:connect: %s\n", strerror(errno)); + if (conf_nas_ip_address) { + addr.sin_addr.s_addr = inet_addr(conf_nas_ip_address); + if (bind(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) { + log_error("radius:bind: %s\n", strerror(errno)); goto out_err; } + } - if (fcntl(req->hnd.fd, F_SETFL, O_NONBLOCK)) { - log_error("radius: failed to set nonblocking mode: %s\n", strerror(errno)); - goto out_err; - } + addr.sin_addr.s_addr = inet_addr(req->server_name); + addr.sin_port = htons(req->server_port); - if (rad_packet_build(req->pack, req->RA)) - goto out_err; + if (connect(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) { + log_error("radius:connect: %s\n", strerror(errno)); + goto out_err; + } + + if (fcntl(req->hnd.fd, F_SETFL, O_NONBLOCK)) { + log_error("radius: failed to set nonblocking mode: %s\n", strerror(errno)); + goto out_err; } + return 0; + +out_err: + close(req->hnd.fd); + req->hnd.fd = -1; + return -1; +} + +int rad_req_send(struct rad_req_t *req) +{ + int n; + + if (req->hnd.fd == -1 && make_socket(req)) + return -1; + + if (!req->pack->buf && rad_packet_build(req->pack, req->RA)) + goto out_err; + if (conf_verbose) { log_debug("send "); rad_packet_print(req->pack, log_debug); @@ -169,6 +206,19 @@ int rad_req_add_int(struct rad_req_t *req, const char *name, int val) return 0; } +int rad_req_change_int(struct rad_req_t *req, const char *name, int val) +{ + struct rad_req_attr_t *ra; + + ra = rad_req_find_attr(req, name); + if (!ra) + return -1; + + ra->val.integer = val; + + return 0; +} + int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, int len, int printable) { struct rad_req_attr_t *ra; @@ -204,6 +254,34 @@ int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, in return 0; } +int rad_req_change_str(struct rad_req_t *req, const char *name, const char *val, int len) +{ + struct rad_req_attr_t *ra; + + ra = rad_req_find_attr(req, name); + if (!ra) + return -1; + + if (ra->len != len) { + if (req->pack->len - ra->len + len >= REQ_LENGTH_MAX) + return -1; + + ra->val.string = realloc(ra->val.string, len + 1); + if (!ra->val.string) { + log_error("radius: out of memory\n"); + return -1; + } + + req->pack->len += len - ra->len; + ra->len = len; + } + + memcpy(ra->val.string, val, len); + ra->val.string[len] = 0; + + return 0; +} + int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, int len) { struct rad_req_attr_t *ra; @@ -235,6 +313,41 @@ int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, in return 0; } +int rad_req_change_val(struct rad_req_t *req, const char *name, const char *val, int len) +{ + struct rad_req_attr_t *ra; + struct rad_dict_value_t *v; + + ra = rad_req_find_attr(req, name); + if (!ra) + return -1; + + v = rad_dict_find_val_name(ra->attr, val); + if (!v) + return -1; + + if (req->pack->len - ra->len + len >= REQ_LENGTH_MAX) + return -1; + + req->pack->len += len - ra->len; + + ra->len = len; + ra->val = v->val; + + return 0; +} + +struct rad_req_attr_t *rad_req_find_attr(struct rad_req_t *req, const char *name) +{ + struct rad_req_attr_t *ra; + + list_for_each_entry(ra, &req->pack->attrs, entry) + if (!strcmp(ra->attr->name, name)) + return ra; + + return NULL; +} + static void req_wakeup(struct rad_req_t *req) { triton_context_wakeup(req->rpd->ppp->ctrl->ctx); @@ -260,6 +373,9 @@ static void rad_req_timeout(struct triton_timer_t *t) int rad_req_wait(struct rad_req_t *req, int timeout) { + req->hnd.read = rad_req_read; + req->timeout.expire = rad_req_timeout; + triton_context_register(&req->ctx); triton_md_register_handler(&req->ctx, &req->hnd); if (triton_md_enable_handler(&req->hnd, MD_MODE_READ)) |