diff options
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/auth/auth_chap_md5.c | 101 | ||||
-rw-r--r-- | accel-pppd/auth/auth_mschap_v1.c | 126 | ||||
-rw-r--r-- | accel-pppd/auth/auth_mschap_v2.c | 142 | ||||
-rw-r--r-- | accel-pppd/auth/auth_pap.c | 91 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 96 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 4 | ||||
-rw-r--r-- | accel-pppd/extra/chap-secrets.c | 2 | ||||
-rw-r--r-- | accel-pppd/ifcfg.c | 19 | ||||
-rw-r--r-- | accel-pppd/include/ap_session.h | 2 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp.c | 6 | ||||
-rw-r--r-- | accel-pppd/pwdb.c | 6 | ||||
-rw-r--r-- | accel-pppd/pwdb.h | 12 | ||||
-rw-r--r-- | accel-pppd/radius/acct.c | 654 | ||||
-rw-r--r-- | accel-pppd/radius/auth.c | 492 | ||||
-rw-r--r-- | accel-pppd/radius/packet.c | 11 | ||||
-rw-r--r-- | accel-pppd/radius/radius.c | 70 | ||||
-rw-r--r-- | accel-pppd/radius/radius_p.h | 47 | ||||
-rw-r--r-- | accel-pppd/radius/req.c | 173 | ||||
-rw-r--r-- | accel-pppd/radius/serv.c | 205 | ||||
-rw-r--r-- | accel-pppd/session.c | 2 | ||||
-rw-r--r-- | accel-pppd/triton/mempool.c | 80 | ||||
-rw-r--r-- | accel-pppd/triton/mempool.h | 7 | ||||
-rw-r--r-- | accel-pppd/triton/triton.c | 4 |
24 files changed, 1299 insertions, 1054 deletions
diff --git a/accel-pppd/auth/auth_chap_md5.c b/accel-pppd/auth/auth_chap_md5.c index 9a52581c..5be8b875 100644 --- a/accel-pppd/auth/auth_chap_md5.c +++ b/accel-pppd/auth/auth_chap_md5.c @@ -30,39 +30,39 @@ #define MSG_FAILURE "Authentication failed" #define MSG_SUCCESS "Authentication succeeded" -#define HDR_LEN (sizeof(struct chap_hdr_t)-2) +#define HDR_LEN (sizeof(struct chap_hdr)-2) static int conf_timeout = 5; static int conf_interval = 0; static int conf_max_failure = 3; static int conf_any_login = 0; -struct chap_hdr_t { +struct chap_hdr { uint16_t proto; uint8_t code; uint8_t id; uint16_t len; } __attribute__((packed)); -struct chap_challenge_t { - struct chap_hdr_t hdr; +struct chap_challenge { + struct chap_hdr hdr; uint8_t val_size; uint8_t val[VALUE_SIZE]; char name[0]; } __attribute__((packed)); -struct chap_failure_t { - struct chap_hdr_t hdr; +struct chap_failure { + struct chap_hdr hdr; char message[sizeof(MSG_FAILURE)]; } __attribute__((packed)); -struct chap_success_t { - struct chap_hdr_t hdr; +struct chap_success { + struct chap_hdr hdr; char message[sizeof(MSG_SUCCESS)]; } __attribute__((packed)); -struct chap_auth_data_t { +struct chap_auth_data { struct auth_data_t auth; struct ppp_handler_t h; struct ppp_t *ppp; @@ -71,10 +71,12 @@ struct chap_auth_data_t { struct triton_timer_t timeout; struct triton_timer_t interval; int failure; + char *name; + char *mschap_error; int started:1; }; -static void chap_send_challenge(struct chap_auth_data_t *ad, int new); +static void chap_send_challenge(struct chap_auth_data *ad, int new); static void chap_recv(struct ppp_handler_t *h); static void chap_timeout_timer(struct triton_timer_t *t); static void chap_restart_timer(struct triton_timer_t *t); @@ -94,7 +96,7 @@ static void print_str(const char *buf, int size) static struct auth_data_t* auth_data_init(struct ppp_t *ppp) { - struct chap_auth_data_t *d = _malloc(sizeof(*d)); + struct chap_auth_data *d = _malloc(sizeof(*d)); memset(d, 0, sizeof(*d)); d->auth.proto = PPP_CHAP; @@ -105,7 +107,7 @@ static struct auth_data_t* auth_data_init(struct ppp_t *ppp) static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); @@ -118,7 +120,7 @@ static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); d->h.proto = PPP_CHAP; d->h.recv = chap_recv; @@ -127,6 +129,7 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) d->interval.expire = chap_restart_timer; d->interval.period = conf_interval * 1000; d->id = 1; + d->name = NULL; ppp_register_chan_handler(ppp, &d->h); @@ -137,13 +140,16 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); if (d->interval.tpd) triton_timer_del(&d->interval); + + if (d->name) + _free(d->name); ppp_unregister_handler(ppp, &d->h); @@ -152,7 +158,7 @@ static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) static void chap_timeout_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + struct chap_auth_data *d = container_of(t, typeof(*d), timeout); if (conf_ppp_verbose) log_ppp_warn("chap-md5: timeout\n"); @@ -168,7 +174,7 @@ static void chap_timeout_timer(struct triton_timer_t *t) static void chap_restart_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + struct chap_auth_data *d = container_of(t, typeof(*d), interval); chap_send_challenge(d, 1); } @@ -186,9 +192,9 @@ static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t * return LCP_OPT_NAK; } -static void chap_send_failure(struct chap_auth_data_t *ad) +static void chap_send_failure(struct chap_auth_data *ad) { - struct chap_failure_t msg = { + struct chap_failure msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_FAILURE, .hdr.id = ad->id, @@ -202,9 +208,9 @@ static void chap_send_failure(struct chap_auth_data_t *ad) ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); } -static void chap_send_success(struct chap_auth_data_t *ad, int id) +static void chap_send_success(struct chap_auth_data *ad, int id) { - struct chap_success_t msg = { + struct chap_success msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_SUCCESS, .hdr.id = id, @@ -218,9 +224,9 @@ static void chap_send_success(struct chap_auth_data_t *ad, int id) ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); } -static void chap_send_challenge(struct chap_auth_data_t *ad, int new) +static void chap_send_challenge(struct chap_auth_data *ad, int new) { - struct chap_challenge_t msg = { + struct chap_challenge msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_CHALLENGE, .hdr.id = ad->id, @@ -245,14 +251,45 @@ static void chap_send_challenge(struct chap_auth_data_t *ad, int new) triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->timeout, 0); } -static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +static void auth_result(struct chap_auth_data *ad, int res) +{ + char *name = ad->name; + + ad->name = NULL; + + if (res == PWDB_DENIED) { + chap_send_failure(ad); + if (ad->started) + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + } else { + if (ppp_auth_succeeded(ad->ppp, name)) { + chap_send_failure(ad); + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + } else { + chap_send_success(ad, ad->id); + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->interval, 0); + name = NULL; + } + } + + ad->id++; + + if (name) + _free(name); +} + +static void chap_recv_response(struct chap_auth_data *ad, struct chap_hdr *hdr) { MD5_CTX md5_ctx; uint8_t md5[MD5_DIGEST_LENGTH]; char *passwd; char *name; int r; - struct chap_challenge_t *msg = (struct chap_challenge_t*)hdr; + struct chap_challenge *msg = (struct chap_challenge*)hdr; if (ad->timeout.tpd) triton_timer_del(&ad->timeout); @@ -270,6 +307,9 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } + if (ad->name) + return; + if (msg->hdr.id != ad->id) { if (conf_ppp_verbose) log_ppp_warn("chap-md5: id mismatch\n"); @@ -301,7 +341,12 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } - r = pwdb_check(&ad->ppp->ses, name, PPP_CHAP, CHAP_MD5, ad->id, ad->val, VALUE_SIZE, msg->val); + r = pwdb_check(&ad->ppp->ses, (pwdb_callback)auth_result, ad, name, PPP_CHAP, CHAP_MD5, ad->id, ad->val, VALUE_SIZE, msg->val); + + if (r == PWDB_WAIT) { + ad->name = name; + return; + } if (r == PWDB_NO_IMPL) { passwd = pwdb_get_passwd(&ad->ppp->ses, name); @@ -383,7 +428,7 @@ static int chap_check(uint8_t *ptr) static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); chap_send_challenge(d, 1); @@ -405,8 +450,8 @@ static struct ppp_auth_handler_t chap= static void chap_recv(struct ppp_handler_t *h) { - struct chap_auth_data_t *d = container_of(h, typeof(*d), h); - struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->buf; + struct chap_auth_data *d = container_of(h, typeof(*d), h); + struct chap_hdr *hdr = (struct chap_hdr *)d->ppp->buf; if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) > d->ppp->buf_size - 2) { log_ppp_warn("chap-md5: short packet received\n"); diff --git a/accel-pppd/auth/auth_mschap_v1.c b/accel-pppd/auth/auth_mschap_v1.c index 1576c837..d9232cc9 100644 --- a/accel-pppd/auth/auth_mschap_v1.c +++ b/accel-pppd/auth/auth_mschap_v1.c @@ -29,7 +29,7 @@ #define VALUE_SIZE 8 #define RESPONSE_VALUE_SIZE (24+24+1) -#define HDR_LEN (sizeof(struct chap_hdr_t)-2) +#define HDR_LEN (sizeof(struct chap_hdr)-2) static int conf_timeout = 5; static int conf_interval = 0; @@ -38,22 +38,22 @@ static int conf_any_login = 0; static char *conf_msg_failure = "E=691 R=0"; static char *conf_msg_success = "Authentication succeeded"; -struct chap_hdr_t { +struct chap_hdr { uint16_t proto; uint8_t code; uint8_t id; uint16_t len; } __attribute__((packed)); -struct chap_challenge_t { - struct chap_hdr_t hdr; +struct chap_challenge { + struct chap_hdr hdr; uint8_t val_size; uint8_t val[VALUE_SIZE]; char name[0]; } __attribute__((packed)); -struct chap_response_t { - struct chap_hdr_t hdr; +struct chap_response { + struct chap_hdr hdr; uint8_t val_size; uint8_t lm_hash[24]; uint8_t nt_hash[24]; @@ -61,7 +61,7 @@ struct chap_response_t { char name[0]; } __attribute__((packed)); -struct chap_auth_data_t { +struct chap_auth_data { struct auth_data_t auth; struct ppp_handler_t h; struct ppp_t *ppp; @@ -70,15 +70,17 @@ struct chap_auth_data_t { struct triton_timer_t timeout; struct triton_timer_t interval; int failure; + char *name; + char *mschap_error; int started:1; }; -static void chap_send_challenge(struct chap_auth_data_t *ad, int new); +static void chap_send_challenge(struct chap_auth_data *ad, int new); static void chap_recv(struct ppp_handler_t *h); -static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *res, const char *name); +static int chap_check_response(struct chap_auth_data *ad, struct chap_response *res, const char *name); static void chap_timeout_timer(struct triton_timer_t *t); static void chap_restart_timer(struct triton_timer_t *t); -static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash); +static void set_mppe_keys(struct chap_auth_data *ad, uint8_t *z_hash); static void print_buf(const uint8_t *buf,int size) { @@ -95,7 +97,7 @@ static void print_str(const char *buf, int size) static struct auth_data_t* auth_data_init(struct ppp_t *ppp) { - struct chap_auth_data_t *d = _malloc(sizeof(*d)); + struct chap_auth_data *d = _malloc(sizeof(*d)); memset(d, 0, sizeof(*d)); d->auth.proto = PPP_CHAP; @@ -106,7 +108,7 @@ static struct auth_data_t* auth_data_init(struct ppp_t *ppp) static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); @@ -119,7 +121,7 @@ static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); d->h.proto = PPP_CHAP; d->h.recv = chap_recv; @@ -128,6 +130,7 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) d->interval.expire = chap_restart_timer; d->interval.period = conf_interval * 1000; d->id = 1; + d->name = NULL; ppp_register_chan_handler(ppp, &d->h); @@ -138,7 +141,7 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); @@ -146,6 +149,9 @@ static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) if (d->interval.tpd) triton_timer_del(&d->interval); + if (d->name) + _free(d->name); + ppp_unregister_handler(ppp, &d->h); return 0; @@ -153,7 +159,7 @@ static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) static void chap_timeout_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + struct chap_auth_data *d = container_of(t, typeof(*d), timeout); if (conf_ppp_verbose) log_ppp_warn("mschap-v1: timeout\n"); @@ -169,7 +175,7 @@ static void chap_timeout_timer(struct triton_timer_t *t) static void chap_restart_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + struct chap_auth_data *d = container_of(t, typeof(*d), interval); chap_send_challenge(d, 1); } @@ -187,9 +193,9 @@ static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t * return LCP_OPT_NAK; } -static void chap_send_failure(struct chap_auth_data_t *ad, char *mschap_error) +static void chap_send_failure(struct chap_auth_data *ad, char *mschap_error) { - struct chap_hdr_t *hdr = _malloc(sizeof(*hdr) + strlen(mschap_error) + 1); + struct chap_hdr *hdr = _malloc(sizeof(*hdr) + strlen(mschap_error) + 1); hdr->proto = htons(PPP_CHAP); hdr->code = CHAP_FAILURE; hdr->id = ad->id; @@ -204,9 +210,9 @@ static void chap_send_failure(struct chap_auth_data_t *ad, char *mschap_error) _free(hdr); } -static void chap_send_success(struct chap_auth_data_t *ad, int id) +static void chap_send_success(struct chap_auth_data *ad, int id) { - struct chap_hdr_t *hdr = _malloc(sizeof(*hdr) + strlen(conf_msg_success) + 1); + struct chap_hdr *hdr = _malloc(sizeof(*hdr) + strlen(conf_msg_success) + 1); hdr->proto = htons(PPP_CHAP); hdr->code = CHAP_SUCCESS; hdr->id = id; @@ -221,9 +227,9 @@ static void chap_send_success(struct chap_auth_data_t *ad, int id) _free(hdr); } -static void chap_send_challenge(struct chap_auth_data_t *ad, int new) +static void chap_send_challenge(struct chap_auth_data *ad, int new) { - struct chap_challenge_t msg = { + struct chap_challenge msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_CHALLENGE, .hdr.id = ad->id, @@ -248,11 +254,46 @@ static void chap_send_challenge(struct chap_auth_data_t *ad, int new) triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->timeout, 0); } -static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +static void auth_result(struct chap_auth_data *ad, int res) +{ + char *name = ad->name; + + ad->name = NULL; + + if (res == PWDB_DENIED) { + chap_send_failure(ad, ad->mschap_error); + if (ad->started) + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + } else { + if (ppp_auth_succeeded(ad->ppp, name)) { + chap_send_failure(ad, ad->mschap_error); + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + } else { + chap_send_success(ad, ad->id); + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->interval, 0); + name = NULL; + } + } + + ad->id++; + + if (ad->mschap_error != conf_msg_failure) { + _free(ad->mschap_error); + ad->mschap_error = conf_msg_failure; + } + + if (name) + _free(name); +} + +static void chap_recv_response(struct chap_auth_data *ad, struct chap_hdr *hdr) { - struct chap_response_t *msg = (struct chap_response_t*)hdr; + struct chap_response *msg = (struct chap_response*)hdr; char *name; - char *mschap_error = conf_msg_failure; int r; if (ad->timeout.tpd) @@ -273,6 +314,9 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } + if (ad->name) + return; + if (msg->hdr.id != ad->id) { if (conf_ppp_verbose) log_ppp_warn("mschap-v1: id mismatch\n"); @@ -300,7 +344,7 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h if (conf_any_login) { if (ppp_auth_succeeded(ad->ppp, name)) { - chap_send_failure(ad, mschap_error); + chap_send_failure(ad, ad->mschap_error); ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); _free(name); return; @@ -311,24 +355,34 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } - r = pwdb_check(&ad->ppp->ses, name, PPP_CHAP, MSCHAP_V1, ad->id, ad->val, VALUE_SIZE, msg->lm_hash, msg->nt_hash, msg->flags, &mschap_error); + ad->mschap_error = conf_msg_failure; + + r = pwdb_check(&ad->ppp->ses, (pwdb_callback)auth_result, ad, name, PPP_CHAP, MSCHAP_V1, ad->id, ad->val, VALUE_SIZE, msg->lm_hash, msg->nt_hash, msg->flags, &ad->mschap_error); + + if (r == PWDB_WAIT) { + ad->name = name; + return; + } + if (r == PWDB_NO_IMPL) if (chap_check_response(ad, msg, name)) r = PWDB_DENIED; if (r == PWDB_DENIED) { - chap_send_failure(ad, mschap_error); + chap_send_failure(ad, ad->mschap_error); if (ad->started) ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); else ppp_auth_failed(ad->ppp, name); _free(name); - if (mschap_error != conf_msg_failure) - _free(mschap_error); + if (ad->mschap_error != conf_msg_failure) { + _free(ad->mschap_error); + ad->mschap_error = conf_msg_failure; + } } else { if (!ad->started) { if (ppp_auth_succeeded(ad->ppp, name)) { - chap_send_failure(ad, mschap_error); + chap_send_failure(ad, ad->mschap_error); ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); _free(name); } else { @@ -375,7 +429,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, const char *name) +static int chap_check_response(struct chap_auth_data *ad, struct chap_response *msg, const char *name) { MD4_CTX md4_ctx; uint8_t z_hash[21]; @@ -420,7 +474,7 @@ static int chap_check(uint8_t *ptr) return *ptr == MSCHAP_V1; } -static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash) +static void set_mppe_keys(struct chap_auth_data *ad, uint8_t *z_hash) { MD4_CTX md4_ctx; SHA_CTX sha_ctx; @@ -450,7 +504,7 @@ static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash) static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); chap_send_challenge(d, 1); @@ -471,8 +525,8 @@ static struct ppp_auth_handler_t chap = { static void chap_recv(struct ppp_handler_t *h) { - struct chap_auth_data_t *d = container_of(h, typeof(*d), h); - struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->buf; + struct chap_auth_data *d = container_of(h, typeof(*d), h); + struct chap_hdr *hdr = (struct chap_hdr *)d->ppp->buf; if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) > d->ppp->buf_size - 2) { log_ppp_warn("mschap-v1: short packet received\n"); diff --git a/accel-pppd/auth/auth_mschap_v2.c b/accel-pppd/auth/auth_mschap_v2.c index 29f37495..0235ddf0 100644 --- a/accel-pppd/auth/auth_mschap_v2.c +++ b/accel-pppd/auth/auth_mschap_v2.c @@ -29,7 +29,7 @@ #define VALUE_SIZE 16 #define RESPONSE_VALUE_SIZE (16+8+24+1) -#define HDR_LEN (sizeof(struct chap_hdr_t)-2) +#define HDR_LEN (sizeof(struct chap_hdr)-2) static int conf_timeout = 5; static int conf_interval = 0; @@ -38,7 +38,7 @@ static char *conf_msg_failure = "E=691 R=0 V=3"; static char *conf_msg_failure2 = "Authentication failure"; static char *conf_msg_success = "Authentication succeeded"; -struct chap_hdr_t { +struct chap_hdr { uint16_t proto; uint8_t code; uint8_t id; @@ -46,14 +46,14 @@ struct chap_hdr_t { } __attribute__((packed)); struct chap_challenge_t { - struct chap_hdr_t hdr; + struct chap_hdr hdr; uint8_t val_size; uint8_t val[VALUE_SIZE]; char name[0]; } __attribute__((packed)); -struct chap_response_t { - struct chap_hdr_t hdr; +struct chap_response { + struct chap_hdr hdr; uint8_t val_size; uint8_t peer_challenge[16]; uint8_t reserved[8]; @@ -62,7 +62,7 @@ struct chap_response_t { char name[0]; } __attribute__((packed)); -struct chap_auth_data_t { +struct chap_auth_data { struct auth_data_t auth; struct ppp_handler_t h; struct ppp_t *ppp; @@ -71,16 +71,19 @@ struct chap_auth_data_t { struct triton_timer_t timeout; struct triton_timer_t interval; char authenticator[41]; + char *name; + char *mschap_error; + char *reply_msg; int failure; int started:1; }; -static void chap_send_challenge(struct chap_auth_data_t *ad, int new); +static void chap_send_challenge(struct chap_auth_data *ad, int new); static void chap_recv(struct ppp_handler_t *h); -static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name); +static int chap_check_response(struct chap_auth_data *ad, struct chap_response *msg, const char *name); static void chap_timeout_timer(struct triton_timer_t *t); static void chap_restart_timer(struct triton_timer_t *t); -static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash, uint8_t *nt_hash); +static void set_mppe_keys(struct chap_auth_data *ad, uint8_t *z_hash, uint8_t *nt_hash); static void print_buf(const uint8_t *buf, int size) { @@ -98,7 +101,7 @@ static void print_str(const char *buf, int size) static struct auth_data_t* auth_data_init(struct ppp_t *ppp) { - struct chap_auth_data_t *d = _malloc(sizeof(*d)); + struct chap_auth_data *d = _malloc(sizeof(*d)); memset(d, 0, sizeof(*d)); d->auth.proto = PPP_CHAP; @@ -109,7 +112,7 @@ static struct auth_data_t* auth_data_init(struct ppp_t *ppp) static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); @@ -122,7 +125,7 @@ static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); d->h.proto = PPP_CHAP; d->h.recv = chap_recv; @@ -131,6 +134,7 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) d->interval.expire = chap_restart_timer; d->interval.period = conf_interval * 1000; d->id = 1; + d->name = NULL; ppp_register_chan_handler(ppp, &d->h); @@ -141,7 +145,7 @@ static int chap_start(struct ppp_t *ppp, struct auth_data_t *auth) static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); @@ -156,7 +160,7 @@ static int chap_finish(struct ppp_t *ppp, struct auth_data_t *auth) static void chap_timeout_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), timeout); + struct chap_auth_data *d = container_of(t, typeof(*d), timeout); if (conf_ppp_verbose) log_ppp_warn("mschap-v2: timeout\n"); @@ -172,7 +176,7 @@ static void chap_timeout_timer(struct triton_timer_t *t) static void chap_restart_timer(struct triton_timer_t *t) { - struct chap_auth_data_t *d = container_of(t, typeof(*d), interval); + struct chap_auth_data *d = container_of(t, typeof(*d), interval); chap_send_challenge(d, 1); } @@ -190,9 +194,9 @@ static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t * return LCP_OPT_NAK; } -static void chap_send_failure(struct chap_auth_data_t *ad, char *mschap_error, char *reply_msg) +static void chap_send_failure(struct chap_auth_data *ad, char *mschap_error, char *reply_msg) { - struct chap_hdr_t *hdr = _malloc(sizeof(*hdr) + strlen(mschap_error) + strlen(reply_msg) + 4); + struct chap_hdr *hdr = _malloc(sizeof(*hdr) + strlen(mschap_error) + strlen(reply_msg) + 4); hdr->proto = htons(PPP_CHAP); hdr->code = CHAP_FAILURE; hdr->id = ad->id; @@ -208,9 +212,9 @@ static void chap_send_failure(struct chap_auth_data_t *ad, char *mschap_error, c _free(hdr); } -static void chap_send_success(struct chap_auth_data_t *ad, int id, const char *authenticator) +static void chap_send_success(struct chap_auth_data *ad, int id, const char *authenticator) { - struct chap_hdr_t *hdr = _malloc(sizeof(*hdr) + strlen(conf_msg_success) + 1 + 45); + struct chap_hdr *hdr = _malloc(sizeof(*hdr) + strlen(conf_msg_success) + 1 + 45); hdr->proto = htons(PPP_CHAP), hdr->code = CHAP_SUCCESS, hdr->id = id, @@ -226,7 +230,7 @@ static void chap_send_success(struct chap_auth_data_t *ad, int id, const char *a _free(hdr); } -static int generate_response(struct chap_auth_data_t *ad, struct chap_response_t *msg, const char *name, char *authenticator) +static int generate_response(struct chap_auth_data *ad, struct chap_response *msg, const char *name, char *authenticator) { MD4_CTX md4_ctx; SHA_CTX sha_ctx; @@ -296,7 +300,7 @@ static int generate_response(struct chap_auth_data_t *ad, struct chap_response_t return 0; } -static void chap_send_challenge(struct chap_auth_data_t *ad, int new) +static void chap_send_challenge(struct chap_auth_data *ad, int new) { struct chap_challenge_t msg = { .hdr.proto = htons(PPP_CHAP), @@ -323,14 +327,54 @@ static void chap_send_challenge(struct chap_auth_data_t *ad, int new) triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->timeout, 0); } -static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) +static void auth_result(struct chap_auth_data *ad, int res) +{ + char *name = ad->name; + + ad->name = NULL; + + if (res == PWDB_DENIED) { + chap_send_failure(ad, ad->mschap_error, ad->reply_msg); + if (ad->started) + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(ad->ppp, name); + } else { + if (ppp_auth_succeeded(ad->ppp, name)) { + chap_send_failure(ad, ad->mschap_error, ad->reply_msg); + ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); + } else { + chap_send_success(ad, ad->id, ad->authenticator); + ad->started = 1; + if (conf_interval) + triton_timer_add(ad->ppp->ses.ctrl->ctx, &ad->interval, 0); + name = NULL; + } + } + + ad->id++; + + if (ad->mschap_error != conf_msg_failure) { + _free(ad->mschap_error); + ad->mschap_error = conf_msg_failure; + } + + if (ad->reply_msg != conf_msg_failure2) { + _free(ad->reply_msg); + ad->reply_msg = conf_msg_failure2; + } + + if (name) + _free(name); +} + + +static void chap_recv_response(struct chap_auth_data *ad, struct chap_hdr *hdr) { - struct chap_response_t *msg = (struct chap_response_t*)hdr; + struct chap_response *msg = (struct chap_response*)hdr; char *name; - char authenticator[41]; + char *authenticator = ad->authenticator; int r; - char *mschap_error = conf_msg_failure; - char *reply_msg = conf_msg_failure2; authenticator[40] = 0; @@ -352,6 +396,12 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } + if (ad->name) + return; + + ad->mschap_error = conf_msg_failure; + ad->reply_msg = conf_msg_failure2; + if (msg->hdr.id != ad->id) { if (conf_ppp_verbose) log_ppp_warn("mschap-v2: id mismatch\n"); @@ -360,7 +410,7 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h if (msg->val_size != RESPONSE_VALUE_SIZE) { log_ppp_error("mschap-v2: incorrect value-size (%i)\n", msg->val_size); - chap_send_failure(ad, mschap_error, reply_msg); + chap_send_failure(ad, ad->mschap_error, ad->reply_msg); if (ad->started) ap_session_terminate(&ad->ppp->ses, TERM_USER_ERROR, 0); else @@ -378,7 +428,12 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h return; } - r = pwdb_check(&ad->ppp->ses, name, PPP_CHAP, MSCHAP_V2, ad->id, ad->val, msg->peer_challenge, msg->reserved, msg->nt_hash, msg->flags, authenticator, &mschap_error, &reply_msg); + r = pwdb_check(&ad->ppp->ses, (pwdb_callback)auth_result, ad, name, PPP_CHAP, MSCHAP_V2, ad->id, ad->val, msg->peer_challenge, msg->reserved, msg->nt_hash, msg->flags, authenticator, &ad->mschap_error, &ad->reply_msg); + + if (r == PWDB_WAIT) { + ad->name = name; + return; + } if (r == PWDB_NO_IMPL) { r = chap_check_response(ad, msg, name); @@ -389,20 +444,27 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h } if (r == PWDB_DENIED) { - chap_send_failure(ad, mschap_error, reply_msg); + chap_send_failure(ad, ad->mschap_error, ad->reply_msg); if (ad->started) ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); else ppp_auth_failed(ad->ppp, name); + _free(name); - if (mschap_error != conf_msg_failure) - _free(mschap_error); - if (reply_msg != conf_msg_failure2) - _free(reply_msg); + + if (ad->mschap_error != conf_msg_failure) { + _free(ad->mschap_error); + ad->mschap_error = conf_msg_failure; + } + + if (ad->reply_msg != conf_msg_failure2) { + _free(ad->reply_msg); + ad->reply_msg = conf_msg_failure2; + } } else { if (!ad->started) { if (ppp_auth_succeeded(ad->ppp, name)) { - chap_send_failure(ad, mschap_error, reply_msg); + chap_send_failure(ad, ad->mschap_error, ad->reply_msg); ap_session_terminate(&ad->ppp->ses, TERM_AUTH_ERROR, 0); _free(name); } else { @@ -416,8 +478,6 @@ static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *h _free(name); } - memcpy(ad->authenticator, authenticator, 41); - ad->id++; } } @@ -451,7 +511,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, const char *name) +static int chap_check_response(struct chap_auth_data *ad, struct chap_response *msg, const char *name) { MD4_CTX md4_ctx; SHA_CTX sha_ctx; @@ -499,7 +559,7 @@ static int chap_check_response(struct chap_auth_data_t *ad, struct chap_response return memcmp(nt_hash, msg->nt_hash, 24); } -static void set_mppe_keys(struct chap_auth_data_t *ad, uint8_t *z_hash, uint8_t *nt_hash) +static void set_mppe_keys(struct chap_auth_data *ad, uint8_t *z_hash, uint8_t *nt_hash) { MD4_CTX md4_ctx; SHA_CTX sha_ctx; @@ -591,7 +651,7 @@ static int chap_check(uint8_t *ptr) static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) { - struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct chap_auth_data *d = container_of(auth, typeof(*d), auth); chap_send_challenge(d, 1); @@ -613,8 +673,8 @@ static struct ppp_auth_handler_t chap= static void chap_recv(struct ppp_handler_t *h) { - struct chap_auth_data_t *d = container_of(h, typeof(*d), h); - struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->buf; + struct chap_auth_data *d = container_of(h, typeof(*d), h); + struct chap_hdr *hdr = (struct chap_hdr *)d->ppp->buf; if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) > d->ppp->buf_size - 2) { log_ppp_warn("mschap-v2: short packet received\n"); diff --git a/accel-pppd/auth/auth_pap.c b/accel-pppd/auth/auth_pap.c index 5f073370..9aab3775 100644 --- a/accel-pppd/auth/auth_pap.c +++ b/accel-pppd/auth/auth_pap.c @@ -15,12 +15,14 @@ #define MSG_FAILED "Authentication failed" #define MSG_SUCCESSED "Authentication succeeded" -#define HDR_LEN (sizeof(struct pap_hdr_t)-2) +#define HDR_LEN (sizeof(struct pap_hdr)-2) #define PAP_REQ 1 #define PAP_ACK 2 #define PAP_NAK 3 +struct pap_auth_data; + static int conf_timeout = 5; static int conf_any_login = 0; @@ -32,33 +34,32 @@ static int pap_start(struct ppp_t*, struct auth_data_t*); static int pap_finish(struct ppp_t*, struct auth_data_t*); static void pap_recv(struct ppp_handler_t*h); static void pap_timeout(struct triton_timer_t *t); +static void pap_auth_result(struct pap_auth_data *, int); -struct pap_auth_data_t -{ +struct pap_auth_data { struct auth_data_t auth; struct ppp_handler_t h; struct ppp_t *ppp; - int started:1; struct triton_timer_t timeout; + char *peer_id; + int req_id; + int started:1; }; -struct pap_hdr_t -{ +struct pap_hdr { uint16_t proto; uint8_t code; uint8_t id; uint16_t len; } __attribute__((packed)); -struct pap_ack_t -{ - struct pap_hdr_t hdr; +struct pap_ack { + struct pap_hdr hdr; uint8_t msg_len; char msg[0]; } __attribute__((packed)); -static struct ppp_auth_handler_t pap= -{ +static struct ppp_auth_handler_t pap= { .name = "PAP", .init = auth_data_init, .free = auth_data_free, @@ -70,7 +71,7 @@ static struct ppp_auth_handler_t pap= static struct auth_data_t* auth_data_init(struct ppp_t *ppp) { - struct pap_auth_data_t *d = _malloc(sizeof(*d)); + struct pap_auth_data *d = _malloc(sizeof(*d)); memset(d, 0, sizeof(*d)); d->auth.proto = PPP_PAP; @@ -81,14 +82,14 @@ static struct auth_data_t* auth_data_init(struct ppp_t *ppp) static void auth_data_free(struct ppp_t *ppp, struct auth_data_t *auth) { - struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct pap_auth_data *d = container_of(auth, typeof(*d), auth); _free(d); } static int pap_start(struct ppp_t *ppp, struct auth_data_t *auth) { - struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct pap_auth_data *d = container_of(auth, typeof(*d), auth); d->h.proto = PPP_PAP; d->h.recv = pap_recv; @@ -103,10 +104,13 @@ static int pap_start(struct ppp_t *ppp, struct auth_data_t *auth) } static int pap_finish(struct ppp_t *ppp, struct auth_data_t *auth) { - struct pap_auth_data_t *d = container_of(auth, typeof(*d), auth); + struct pap_auth_data *d = container_of(auth, typeof(*d), auth); if (d->timeout.tpd) triton_timer_del(&d->timeout); + + if (d->peer_id) + _free(d->peer_id); ppp_unregister_handler(ppp, &d->h); @@ -115,7 +119,7 @@ static int pap_finish(struct ppp_t *ppp, struct auth_data_t *auth) static void pap_timeout(struct triton_timer_t *t) { - struct pap_auth_data_t *d = container_of(t, typeof(*d), timeout); + struct pap_auth_data *d = container_of(t, typeof(*d), timeout); if (conf_ppp_verbose) log_ppp_warn("pap: timeout\n"); @@ -133,10 +137,10 @@ static int lcp_recv_conf_req(struct ppp_t *ppp, struct auth_data_t *d, uint8_t * return LCP_OPT_ACK; } -static void pap_send_ack(struct pap_auth_data_t *p, int id) +static void pap_send_ack(struct pap_auth_data *p, int id) { uint8_t buf[128]; - struct pap_ack_t *msg = (struct pap_ack_t*)buf; + struct pap_ack *msg = (struct pap_ack*)buf; msg->hdr.proto = htons(PPP_PAP); msg->hdr.code = PAP_ACK; msg->hdr.id = id; @@ -150,10 +154,10 @@ static void pap_send_ack(struct pap_auth_data_t *p, int id) ppp_chan_send(p->ppp, msg, ntohs(msg->hdr.len) + 2); } -static void pap_send_nak(struct pap_auth_data_t *p, int id) +static void pap_send_nak(struct pap_auth_data *p, int id) { uint8_t buf[128]; - struct pap_ack_t *msg = (struct pap_ack_t*)buf; + struct pap_ack *msg = (struct pap_ack*)buf; msg->hdr.proto = htons(PPP_PAP); msg->hdr.code = PAP_NAK; msg->hdr.id = id; @@ -167,7 +171,33 @@ static void pap_send_nak(struct pap_auth_data_t *p, int id) ppp_chan_send(p->ppp, msg, ntohs(msg->hdr.len) + 2); } -static int pap_recv_req(struct pap_auth_data_t *p, struct pap_hdr_t *hdr) +static void pap_auth_result(struct pap_auth_data *p, int res) +{ + char *peer_id = p->peer_id; + + p->peer_id = NULL; + + if (res == PWDB_DENIED) { + pap_send_nak(p, p->req_id); + if (p->started) + ap_session_terminate(&p->ppp->ses, TERM_AUTH_ERROR, 0); + else + ppp_auth_failed(p->ppp, peer_id); + } else { + if (ppp_auth_succeeded(p->ppp, peer_id)) { + pap_send_nak(p, p->req_id); + ap_session_terminate(&p->ppp->ses, TERM_AUTH_ERROR, 0); + } else { + pap_send_ack(p, p->req_id); + p->started = 1; + return; + } + } + + _free(peer_id); +} + +static int pap_recv_req(struct pap_auth_data *p, struct pap_hdr *hdr) { int ret, r; char *peer_id; @@ -182,17 +212,21 @@ static int pap_recv_req(struct pap_auth_data_t *p, struct pap_hdr_t *hdr) if (conf_ppp_verbose) log_ppp_info2("recv [PAP AuthReq id=%x]\n", hdr->id); - + if (p->started) { pap_send_ack(p, hdr->id); return 0; } + if (p->peer_id) + return 0; + peer_id_len = *(uint8_t*)ptr; ptr++; if (peer_id_len > ntohs(hdr->len) - sizeof(*hdr) + 2 - 1) { log_ppp_warn("PAP: short packet received\n"); return -1; } + peer_id = (char*)ptr; ptr += peer_id_len; passwd_len = *(uint8_t*)ptr; ptr++; @@ -217,7 +251,14 @@ static int pap_recv_req(struct pap_auth_data_t *p, struct pap_hdr_t *hdr) passwd = _strndup((const char*)ptr, passwd_len); - r = pwdb_check(&p->ppp->ses, peer_id, PPP_PAP, passwd); + r = pwdb_check(&p->ppp->ses, (pwdb_callback)pap_auth_result, p, peer_id, PPP_PAP, passwd); + if (r == PWDB_WAIT) { + p->peer_id = peer_id; + p->req_id = hdr->id; + _free(passwd); + return 0; + } + if (r == PWDB_NO_IMPL) { passwd2 = pwdb_get_passwd(&p->ppp->ses, peer_id); if (!passwd2) { @@ -268,8 +309,8 @@ failed: static void pap_recv(struct ppp_handler_t *h) { - struct pap_auth_data_t *d = container_of(h, typeof(*d), h); - struct pap_hdr_t *hdr = (struct pap_hdr_t *)d->ppp->buf; + struct pap_auth_data *d = container_of(h, typeof(*d), h); + struct pap_hdr *hdr = (struct pap_hdr *)d->ppp->buf; if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->buf_size - 2) { log_ppp_warn("PAP: short packet received\n"); diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 9c6075e1..f30d46fd 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -498,6 +498,52 @@ static int ipoe_create_interface(struct ipoe_session *ses) return 0; } +static void auth_result(struct ipoe_session *ses, int r) +{ + char *username = ses->username; + + ses->username = NULL; + + if (r == PWDB_DENIED) { + pthread_rwlock_wrlock(&ses_lock); + ses->ses.username = username; + ses->ses.terminate_cause = TERM_AUTH_ERROR; + pthread_rwlock_unlock(&ses_lock); + if (conf_ppp_verbose) + log_ppp_warn("authentication failed\n"); + if (conf_l4_redirect_on_reject && !ses->dhcpv4_request) + l4_redirect_list_add(ses->yiaddr); + ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0); + return; + } + + ap_session_set_username(&ses->ses, username); + log_ppp_info1("%s: authentication succeeded\n", ses->ses.username); + triton_event_fire(EV_SES_AUTHORIZED, &ses->ses); + + if (ses->serv->opt_nat) + ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses); + + if (ses->serv->opt_shared == 0 && (!ses->ses.ipv4 || ses->ses.ipv4->peer_addr == ses->yiaddr)) { + strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN); + ses->ses.ifindex = ses->serv->ifindex; + } else if (ses->ifindex == -1) { + if (ipoe_create_interface(ses)) + return; + } + + ap_session_set_ifindex(&ses->ses); + + if (ses->dhcpv4_request && ses->serv->dhcpv4_relay) { + dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id); + + ses->timer.expire = ipoe_relay_timeout; + ses->timer.period = conf_relay_timeout * 1000; + triton_timer_add(&ses->ctx, &ses->timer, 0); + } else + __ipoe_session_start(ses); +} + static void ipoe_session_start(struct ipoe_session *ses) { int r; @@ -524,7 +570,9 @@ static void ipoe_session_start(struct ipoe_session *ses) ap_session_starting(&ses->ses); - if (!conf_noauth) { + if (conf_noauth) + r = PWDB_SUCCESS; + else { if (ses->serv->opt_shared && ipoe_create_interface(ses)) return; @@ -536,7 +584,12 @@ static void ipoe_session_start(struct ipoe_session *ses) } #endif - r = pwdb_check(&ses->ses, username, PPP_PAP, conf_password ? conf_password : username); + ses->username = username; + r = pwdb_check(&ses->ses, (pwdb_callback)auth_result, ses, username, PPP_PAP, conf_password ? conf_password : username); + + if (r == PWDB_WAIT) + return; + if (r == PWDB_NO_IMPL) { passwd = pwdb_get_passwd(&ses->ses, ses->ses.username); if (!passwd) @@ -546,46 +599,9 @@ static void ipoe_session_start(struct ipoe_session *ses) _free(passwd); } } - - if (r == PWDB_DENIED) { - pthread_rwlock_wrlock(&ses_lock); - ses->ses.username = username; - ses->ses.terminate_cause = TERM_AUTH_ERROR; - pthread_rwlock_unlock(&ses_lock); - if (conf_ppp_verbose) - log_ppp_warn("authentication failed\n"); - if (conf_l4_redirect_on_reject && !ses->dhcpv4_request) - l4_redirect_list_add(ses->yiaddr); - ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0); - return; - } } - - ap_session_set_username(&ses->ses, username); - log_ppp_info1("%s: authentication succeeded\n", ses->ses.username); - triton_event_fire(EV_SES_AUTHORIZED, &ses->ses); - - if (ses->serv->opt_nat) - ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses); - if (ses->serv->opt_shared == 0 && (!ses->ses.ipv4 || ses->ses.ipv4->peer_addr == ses->yiaddr)) { - strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN); - ses->ses.ifindex = ses->serv->ifindex; - } else if (ses->ifindex == -1) { - if (ipoe_create_interface(ses)) - return; - } - - ap_session_set_ifindex(&ses->ses); - - if (ses->dhcpv4_request && ses->serv->dhcpv4_relay) { - dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id); - - ses->timer.expire = ipoe_relay_timeout; - ses->timer.period = conf_relay_timeout * 1000; - triton_timer_add(&ses->ctx, &ses->timer, 0); - } else - __ipoe_session_start(ses); + auth_result(ses, r); } static void find_gw_addr(struct ipoe_session *ses) diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 7b572c71..b06aa8b5 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -80,6 +80,7 @@ struct ipoe_session { struct dhcpv4_packet *dhcpv4_relay_reply; int relay_retransmit; int ifindex; + char *username; struct ipv4db_item_t ipv4; #ifdef RADIUS struct rad_plugin_t radius; diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index b1445c24..c1cbdb7b 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -33,7 +33,7 @@ #include "memdebug.h" -#define SID_MAX 128 +#define SID_MAX 65536 struct pppoe_conn_t { struct list_head entry; @@ -141,7 +141,6 @@ static void disconnect(struct pppoe_conn_t *conn) close(conn->disc_sock); - triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); log_ppp_info1("disconnected\n"); @@ -365,6 +364,7 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui pthread_mutex_lock(&serv->lock); list_add_tail(&conn->entry, &serv->conn_list); + serv->conn_cnt++; pthread_mutex_unlock(&serv->lock); return conn; diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c index 21edcbdb..d48ecf6b 100644 --- a/accel-pppd/extra/chap-secrets.c +++ b/accel-pppd/extra/chap-secrets.c @@ -618,7 +618,7 @@ int auth_mschap_v2(struct ap_session *ses, struct cs_pd_t *pd, const char *usern return PWDB_SUCCESS; } -static int check_passwd(struct pwdb_t *pwdb, struct ap_session *ses, const char *username, int type, va_list _args) +static int check_passwd(struct pwdb_t *pwdb, struct ap_session *ses, pwdb_callback cb, void *cb_arg, const char *username, int type, va_list _args) { va_list args; int r = PWDB_NO_IMPL; diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index d3a8006c..c48011ec 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -55,7 +55,6 @@ static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_add *(uint64_t *)(addr->s6_addr + 8) |= intf_id & ((1 << (128 - a->prefix_len)) - 1); } -static void ifup_continue(struct ap_session *ses); void ap_session_ifup(struct ap_session *ses) { if (ses->ifname_rename) { @@ -66,12 +65,19 @@ void ap_session_ifup(struct ap_session *ses) _free(ses->ifname_rename); ses->ifname_rename = NULL; } - + triton_event_fire(EV_SES_ACCT_START, ses); - triton_context_call(ses->ctrl->ctx, (triton_event_func)ifup_continue, ses); + + if (ses->stop_time) + return; + + if (!ses->acct_start) { + ses->acct_start = 1; + ap_session_accounting_started(ses); + } } -static void ifup_continue(struct ap_session *ses) +void __export ap_session_accounting_started(struct ap_session *ses) { struct ipv6db_addr_t *a; struct ifreq ifr; @@ -84,10 +90,13 @@ static void ifup_continue(struct ap_session *ses) if (ses->stop_time) return; + if (--ses->acct_start) + return; + triton_event_fire(EV_SES_PRE_UP, ses); if (ses->stop_time) return; - + memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, ses->ifname); diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index f6d92d78..263e2656 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -103,6 +103,7 @@ struct ap_session uint32_t acct_tx_packets_i; uint32_t acct_rx_bytes_i; uint32_t acct_tx_bytes_i; + int acct_start; }; struct ap_session_stat @@ -127,6 +128,7 @@ int ap_session_starting(struct ap_session *ses); void ap_session_finished(struct ap_session *ses); void ap_session_terminate(struct ap_session *ses, int cause, int hard); void ap_session_activate(struct ap_session *ses); +void ap_session_accounting_started(struct ap_session *ses); int ap_session_set_username(struct ap_session *ses, char *username); void ap_session_ifup(struct ap_session *ses); diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c index 6e024805..fd572590 100644 --- a/accel-pppd/ppp/ppp.c +++ b/accel-pppd/ppp/ppp.c @@ -115,7 +115,7 @@ int __export establish_ppp(struct ppp_t *ppp) log_ppp_error("open(unit) /dev/ppp: %s\n", strerror(errno)); goto exit_close_chan; } - + fcntl(ppp->unit_fd, F_SETFD, fcntl(ppp->unit_fd, F_GETFD) | FD_CLOEXEC); ppp->ses.unit_idx = -1; @@ -283,7 +283,7 @@ cont: list_for_each_entry(ppp_h, &ppp->chan_handlers, entry) { if (ppp_h->proto == proto) { ppp_h->recv(ppp_h); - if (ppp->chan_fd == -1) { + if (ppp->fd == -1) { //ppp->ses.ctrl->finished(ppp); return 1; } @@ -331,7 +331,7 @@ cont: list_for_each_entry(ppp_h, &ppp->unit_handlers, entry) { if (ppp_h->proto == proto) { ppp_h->recv(ppp_h); - if (ppp->unit_fd == -1) { + if (ppp->fd == -1) { //ppp->ses.ctrl->finished(ppp); return 1; } diff --git a/accel-pppd/pwdb.c b/accel-pppd/pwdb.c index 5626c2c9..f42a3a88 100644 --- a/accel-pppd/pwdb.c +++ b/accel-pppd/pwdb.c @@ -8,7 +8,7 @@ static LIST_HEAD(pwdb_handlers); -int __export pwdb_check(struct ap_session *ses, const char *username, int type, ...) +int __export pwdb_check(struct ap_session *ses, pwdb_callback cb, void *cb_arg, const char *username, int type, ...) { struct pwdb_t *pwdb; int r, res = PWDB_NO_IMPL; @@ -19,11 +19,11 @@ int __export pwdb_check(struct ap_session *ses, const char *username, int type, list_for_each_entry(pwdb, &pwdb_handlers, entry) { if (!pwdb->check) continue; - r = pwdb->check(pwdb, ses, username, type, args); + r = pwdb->check(pwdb, ses, cb, cb_arg, username, type, args); if (r == PWDB_NO_IMPL) continue; res = r; - if (r == PWDB_SUCCESS) + if (r == PWDB_SUCCESS || r == PWDB_WAIT) break; } diff --git a/accel-pppd/pwdb.h b/accel-pppd/pwdb.h index f7d62d6a..7618bbc6 100644 --- a/accel-pppd/pwdb.h +++ b/accel-pppd/pwdb.h @@ -12,16 +12,18 @@ struct ap_session; #define PWDB_SUCCESS 0 #define PWDB_DENIED 1 -#define PWDB_NO_IMPL 2 +#define PWDB_WAIT 2 +#define PWDB_NO_IMPL 3 -struct pwdb_t -{ +typedef void (*pwdb_callback)(void *arg, int res); + +struct pwdb_t { struct list_head entry; - int (*check)(struct pwdb_t *, struct ap_session *, const char *username, int type, va_list args); + int (*check)(struct pwdb_t *, struct ap_session *, pwdb_callback cb, void *cb_arg, const char *username, int type, va_list args); char* (*get_passwd)(struct pwdb_t *, struct ap_session *, const char *username); }; -int pwdb_check(struct ap_session *, const char *username, int type, ...); +int pwdb_check(struct ap_session *, pwdb_callback cb, void *cb_arg, const char *username, int type, ...); char *pwdb_get_passwd(struct ap_session *, const char *username); void pwdb_register(struct pwdb_t *); diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c index 9a5e549e..f9919453 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -18,7 +18,6 @@ #include "memdebug.h" -#define STAT_UPDATE_INTERVAL (10 * 60 * 1000) #define INTERIM_SAFE_TIME 10 static int req_set_RA(struct rad_req_t *req, const char *secret) @@ -40,13 +39,13 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) { struct rtnl_link_stats stats; struct radius_pd_t *rpd = req->rpd; - time_t stop_time; + struct timespec ts; int ret = 0; if (ses->stop_time) - stop_time = ses->stop_time; + ts.tv_sec = ses->stop_time; else - time(&stop_time); + clock_gettime(CLOCK_MONOTONIC, &ts); if (ap_session_read_stats(ses, &stats) == 0) { rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", stats.rx_bytes); @@ -58,99 +57,56 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) } else ret = -1; - rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ses->start_time); + rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", ts.tv_sec - ses->start_time); return ret; } -static int rad_acct_read(struct triton_md_handler_t *h) +static void rad_acct_sent(struct rad_req_t *req, int res) { - struct rad_req_t *req = container_of(h, typeof(*req), hnd); - struct rad_packet_t *pack; - int r; - unsigned int dt; - - if (req->reply) { - rad_packet_free(req->reply); - req->reply = NULL; + if (res) { + if (conf_acct_timeout) + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); + else + triton_timer_del(&req->timeout); + return; } - - while (1) { - r = rad_packet_recv(h->fd, &pack, NULL); - - if (pack) { - rad_server_reply(req->serv); - if (req->reply) - rad_packet_free(req->reply); - req->reply = pack; - if (conf_interim_verbose) { - log_ppp_info2("recv "); - rad_packet_print(req->reply, req->serv, log_ppp_info2); - } - } - - if (r) - break; + + __sync_add_and_fetch(&req->serv->stat_interim_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); } - if (!req->reply) - return 0; - - if (req->reply->id != req->pack->id) - return 0; - - rad_server_req_exit(req); + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} - dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + +static void rad_acct_recv(struct rad_req_t *req) +{ + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; stat_accm_add(req->serv->stat_interim_query_1m, dt); stat_accm_add(req->serv->stat_interim_query_5m, dt); - if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) { - rad_packet_free(req->reply); - req->reply = NULL; - } else { - if (req->timeout.tpd) - triton_timer_del(&req->timeout); - } - - triton_md_unregister_handler(h, 1); - - return 1; -} - -static int __rad_req_send(struct rad_req_t *req) -{ - while (1) { - if (rad_server_req_enter(req)) { - if (rad_server_realloc(req)) - return -1; - continue; - } - - if (rad_req_send(req, conf_interim_verbose ? log_ppp_info2 : NULL)) { - rad_server_req_exit(req); - rad_server_fail(req->serv); - continue; - } - - if (!req->hnd.tpd) { - triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); - triton_md_enable_handler(&req->hnd, MD_MODE_READ); - } + triton_timer_del(&req->timeout); - break; - } - - return 0; + triton_md_unregister_handler(&req->hnd, 1); + + rad_packet_free(req->reply); + req->reply = NULL; } static void rad_acct_timeout(struct triton_timer_t *t) { struct rad_req_t *req = container_of(t, typeof(*req), timeout); - time_t ts, dt; - + time_t dt; + struct timespec ts; + rad_server_req_exit(req); rad_server_timeout(req->serv); @@ -164,9 +120,9 @@ static void rad_acct_timeout(struct triton_timer_t *t) return; } - time(&ts); + clock_gettime(CLOCK_MONOTONIC, &ts); - dt = ts - req->rpd->acct_timestamp; + dt = ts.tv_sec - req->ts; if (dt > conf_acct_timeout) { rad_server_fail(req->serv); @@ -176,42 +132,30 @@ static void rad_acct_timeout(struct triton_timer_t *t) ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); return; } - time(&req->rpd->acct_timestamp); } - if (dt > conf_acct_timeout / 2) { - req->timeout.period += 1000; - triton_timer_mod(&req->timeout, 0); - } else if (dt > conf_acct_timeout / 3) { - if (req->timeout.period != conf_timeout * 2000) { - req->timeout.period = conf_timeout * 2000; - triton_timer_mod(&req->timeout, 0); - } + if (dt > conf_acct_timeout / 2) + req->timeout.expire_tv.tv_sec++; + else if (dt > conf_acct_timeout / 4) { + if (req->timeout.expire_tv.tv_sec < conf_timeout * 2) + req->timeout.expire_tv.tv_sec = conf_timeout * 2; } - if (conf_acct_delay_time) { + if (conf_acct_delay_time) req->pack->id++; - rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", dt); - req_set_RA(req, req->serv->secret); - } - - if (__rad_req_send(req)) { - triton_timer_del(t); - - if (conf_acct_timeout) { - log_ppp_warn("radius:acct: no servers available, terminating session...\n"); - ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); - } + + req->try = 0; - return; + if (rad_req_send(req) && conf_acct_timeout) { + log_ppp_warn("radius:acct: no servers available, terminating session...\n"); + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); } - - __sync_add_and_fetch(&req->serv->stat_interim_sent, 1); } static void rad_acct_interim_update(struct triton_timer_t *t) { struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer); + struct timespec ts; if (rpd->acct_req->timeout.tpd) return; @@ -228,281 +172,313 @@ static void rad_acct_interim_update(struct triton_timer_t *t) if (!rpd->acct_interim_interval) return; - time(&rpd->acct_timestamp); + clock_gettime(CLOCK_MONOTONIC, &ts); + rpd->acct_req->ts = ts.tv_sec; rpd->acct_req->pack->id++; - rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Interim-Update"); - if (conf_acct_delay_time) - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", 0); - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + if (!rpd->acct_req->before_send) + req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + + rpd->acct_req->timeout.expire_tv.tv_sec = conf_timeout; + rpd->acct_req->try = 0; - if (__rad_req_send(rpd->acct_req)) - return; + if (rad_req_send(rpd->acct_req) && conf_acct_timeout) { + log_ppp_warn("radius:acct: no servers available, terminating session...\n"); + ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0); + } +} - /* The above call may set rpd->acct_req to NULL in the following chain of events: - 1. __rad_req_send fails (on rad_server_realloc) and calls ppp_terminate; - 2. As a result, an EV_PPP_FINISHING event is fired; - 3. ppp_finishing calls rad_acct_stop that cleans up the request. */ - if (!rpd->acct_req) - return; +static int rad_acct_before_send(struct rad_req_t *req) +{ + struct timespec ts; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_interim_sent, 1); + clock_gettime(CLOCK_MONOTONIC, &ts); + + rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", ts.tv_sec - req->ts); + req_set_RA(req, req->serv->secret); - rpd->acct_req->timeout.period = conf_timeout * 1000; - triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_req->timeout, 0); + return 0; } -int rad_acct_start(struct radius_pd_t *rpd) +static void rad_acct_start_sent(struct rad_req_t *req, int res) { - int i; - time_t ts; - unsigned int dt; + if (res) { + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); + return; + } - if (!conf_accounting) - return 0; + __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); - if (!rpd->acct_req) - rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } - if (!rpd->acct_req) - return -1; + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} - if (rad_req_acct_fill(rpd->acct_req)) { - log_ppp_error("radius:acct: failed to fill accounting attributes\n"); - goto out_err; - } +static void rad_acct_start_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + + stat_accm_add(req->serv->stat_acct_query_1m, dt); + stat_accm_add(req->serv->stat_acct_query_5m, dt); - //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->ses->ionid, PPP_SESSIONID_LEN, 1)) - // goto out_err; + triton_timer_del(&req->timeout); - if (rpd->acct_req->reply) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; + triton_md_unregister_handler(&req->hnd, 1); + + if (rpd->acct_interim_interval) { + rad_packet_free(req->reply); + req->reply = NULL; + + rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Interim-Update"); + rpd->acct_interim_timer.expire = rad_acct_interim_update; + rpd->acct_interim_timer.period = rpd->acct_interim_interval * 1000; + triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0); + + req->timeout.expire = rad_acct_timeout; + req->recv = rad_acct_recv; + req->sent = rad_acct_sent; + req->log = conf_interim_verbose ? log_ppp_info2 : NULL; + } else { + rad_req_free(rpd->acct_req); + rpd->acct_req = NULL; } - time(&rpd->acct_timestamp); + rpd->acct_started = 1; - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; + ap_session_accounting_started(rpd->ses); +} -#ifdef USE_BACKUP - if (rpd->ses->state != AP_STATE_RESTORE || !rpd->ses->backup->internal) { -#endif - while (1) { - - if (rad_server_req_enter(rpd->acct_req)) { - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_start: no servers available\n"); - goto out_err; - } - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; - continue; - } - - for (i = 0; i < conf_max_try; i++) { - if (conf_acct_delay_time) { - time(&ts); - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp); - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) { - rad_server_req_exit(rpd->acct_req); - goto out_err; - } - } - - if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; - - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1); - - rad_req_wait(rpd->acct_req, conf_timeout); - - if (!rpd->acct_req->reply) { - if (conf_acct_delay_time) - rpd->acct_req->pack->id++; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - continue; - } - - dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 + - (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt); - stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt); - - 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; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - } else - break; - } - -out: - rad_server_req_exit(rpd->acct_req); - - if (rpd->acct_req->reply) - break; - - rad_server_fail(rpd->acct_req->serv); - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_start: no servers available\n"); - goto out_err; - } - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; - } -#ifdef USE_BACKUP +static void rad_acct_start_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); + stat_accm_add(req->serv->stat_acct_lost_1m, 1); + stat_accm_add(req->serv->stat_acct_lost_5m, 1); + + if (req->before_send) + req->pack->id++; + + if (rad_req_send(req)) + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); +} + +int rad_acct_start(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + + if (!req) + return -1; + + if (rad_req_acct_fill(req)) { + log_ppp_error("radius:acct: failed to fill accounting attributes\n"); + goto out_err; } -#endif - close(rpd->acct_req->hnd.fd); - rpd->acct_req->hnd.fd = -1; - rpd->acct_req->hnd.read = rad_acct_read; + if (conf_acct_delay_time) + req->before_send = rad_acct_before_send; + else if (req_set_RA(req, req->serv->secret)) + goto out_err; + + req->recv = rad_acct_start_recv; + req->timeout.expire = rad_acct_start_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->sent = rad_acct_start_sent; + req->log = conf_verbose ? log_ppp_info1 : NULL; - rpd->acct_req->timeout.expire = rad_acct_timeout; - rpd->acct_req->timeout.period = conf_timeout * 1000; + if (rad_req_send(req)) + goto out_err; + + rpd->acct_req = req; - rpd->acct_interim_timer.expire = rad_acct_interim_update; - rpd->acct_interim_timer.period = rpd->acct_interim_interval ? rpd->acct_interim_interval * 1000 : STAT_UPDATE_INTERVAL; - if (rpd->acct_interim_interval) - triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0); return 0; out_err: - rad_req_free(rpd->acct_req); - rpd->acct_req = NULL; + rad_req_free(req); return -1; } -void rad_acct_stop(struct radius_pd_t *rpd) +static void rad_acct_stop_sent(struct rad_req_t *req, int res) { - int i; - time_t ts; - unsigned int dt; - - if (!rpd->acct_req || !rpd->acct_req->serv) + if (res) { + if (req->rpd) + rad_acct_stop_defer(req->rpd); + else { + if (ap_shutdown) + rad_req_free(req); + else + req->try = 0; + } + return; + } + + __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } - if (rpd->acct_interim_timer.tpd) - triton_timer_del(&rpd->acct_interim_timer); + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->timeout, 0); +} - if (rpd->acct_req->timeout.tpd) - rad_server_req_exit(rpd->acct_req); +static void rad_acct_stop_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + + stat_accm_add(req->serv->stat_acct_query_1m, dt); + stat_accm_add(req->serv->stat_acct_query_5m, dt); + + rad_req_free(req); - if (rpd->acct_req->hnd.tpd) - triton_md_unregister_handler(&rpd->acct_req->hnd, 0); + if (rpd) + rpd->acct_req = NULL; +} + +static void rad_acct_stop_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + if (req->active) { + rad_server_req_exit(req); + rad_server_timeout(req->serv); + + __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); + stat_accm_add(req->serv->stat_acct_lost_1m, 1); + stat_accm_add(req->serv->stat_acct_lost_5m, 1); - if (rpd->acct_req->timeout.tpd) - triton_timer_del(&rpd->acct_req->timeout); - - switch (rpd->ses->terminate_cause) { - case TERM_USER_REQUEST: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Request"); - break; - case TERM_SESSION_TIMEOUT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout"); - break; - case TERM_ADMIN_RESET: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset"); - break; - case TERM_USER_ERROR: - case TERM_AUTH_ERROR: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Error"); - break; - case TERM_NAS_ERROR: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error"); - break; - case TERM_NAS_REQUEST: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request"); - break; - case TERM_NAS_REBOOT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot"); - break; - case TERM_LOST_CARRIER: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier"); - break; - case TERM_IDLE_TIMEOUT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout"); - break; + if (req->before_send) + req->pack->id++; + } + + if (req->try == conf_max_try) { + rad_req_free(req); + return; + } + + if (rad_req_send(req)) { + if (ap_shutdown) { + rad_req_free(req); + return; } - rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Stop"); - req_set_stat(rpd->acct_req, rpd->ses); - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); - /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", ""); + req->try = 0; + } +} + +static void start_deferred(struct rad_req_t *req) +{ + if (req->hnd.fd != -1) { + triton_md_register_handler(NULL, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + if (rad_req_read(&req->hnd)) + return; + } + + triton_timer_add(NULL, &req->timeout, 0); +} + +void rad_acct_stop_defer(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rpd->acct_req; + rad_server_req_cancel(req); + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 0); + rpd->acct_req = NULL; + + req->rpd = NULL; + req->log = conf_verbose ? log_info1 : NULL; + req->timeout.expire = rad_acct_stop_timeout; + + triton_context_call(NULL, (triton_event_func)start_deferred, req); +} + +int rad_acct_stop(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rpd->acct_req; + struct timespec ts; + + if (req) { + triton_timer_del(&rpd->acct_interim_timer); - if (rpd->acct_req->reply) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; - } + rad_server_req_cancel(req); + + clock_gettime(CLOCK_MONOTONIC, &ts); + req->ts = ts.tv_sec; + req->try = 0; + } else { + req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + if (!req) + return -1; - time(&rpd->acct_timestamp); - - while (1) { - - if (rad_server_req_enter(rpd->acct_req)) { - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_stop: no servers available\n"); - break; - } - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); - continue; - } - - for(i = 0; i < conf_max_try; i++) { - if (conf_acct_delay_time) { - time(&ts); - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp); - rpd->acct_req->pack->id++; - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - break; - } - if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1); - rad_req_wait(rpd->acct_req, conf_timeout); - if (!rpd->acct_req->reply) { - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - continue; - } - - dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 + - (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt); - stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt); - - 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; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - } else - break; - } - -out: - rad_server_req_exit(rpd->acct_req); - - if (rpd->acct_req->reply) - break; - - rad_server_fail(rpd->acct_req->serv); - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_stop: no servers available\n"); - break; - } - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + if (rad_req_acct_fill(req)) { + log_ppp_error("radius:acct: failed to fill accounting attributes\n"); + rad_req_free(req); + return -1; } - rad_req_free(rpd->acct_req); - rpd->acct_req = NULL; + rpd->acct_req = req; + } + + switch (rpd->ses->terminate_cause) { + case TERM_USER_REQUEST: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Request"); + break; + case TERM_SESSION_TIMEOUT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout"); + break; + case TERM_ADMIN_RESET: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset"); + break; + case TERM_USER_ERROR: + case TERM_AUTH_ERROR: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Error"); + break; + case TERM_NAS_ERROR: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error"); + break; + case TERM_NAS_REQUEST: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request"); + break; + case TERM_NAS_REBOOT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot"); + break; + case TERM_LOST_CARRIER: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier"); + break; + case TERM_IDLE_TIMEOUT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout"); + break; + } + + rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Stop"); + req_set_stat(req, rpd->ses); + req_set_RA(req, req->serv->secret); + + req->recv = rad_acct_stop_recv; + req->timeout.expire = rad_acct_start_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->sent = rad_acct_stop_sent; + req->log = conf_verbose ? log_ppp_info1 : NULL; + + if (rad_req_send(req)) { + rad_acct_stop_defer(rpd); + return -1; + } + + return 0; } diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c index f4efe3b9..b73f2597 100644 --- a/accel-pppd/radius/auth.c +++ b/accel-pppd/radius/auth.c @@ -4,6 +4,7 @@ #include "crypto.h" #include "triton.h" +#include "mempool.h" #include "events.h" #include "log.h" #include "pwdb.h" @@ -142,193 +143,179 @@ static uint8_t* encrypt_password(const char *passwd, const char *secret, const u return epasswd; } -static int rad_auth_send(struct rad_req_t *req) +static void rad_auth_finalize(struct radius_pd_t *rpd, int r) { - int i; - struct timespec tv, tv2; + hold_pd(rpd); + + rpd->auth_ctx->cb(rpd->auth_ctx->cb_arg, r); + + if (rpd->auth_ctx) { + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } + + release_pd(rpd); +} + +static void rad_auth_recv(struct rad_req_t *req) +{ + struct rad_packet_t *pack = req->reply; unsigned int dt; - int timeout; - while (1) { - if (rad_server_req_enter(req)) { - if (rad_server_realloc(req)) { - log_ppp_warn("radius: no available servers\n"); - break; - } - continue; + triton_timer_del(&req->timeout); + + dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + stat_accm_add(req->serv->stat_auth_query_1m, dt); + stat_accm_add(req->serv->stat_auth_query_5m, dt); + + if (pack->code == CODE_ACCESS_ACCEPT) { + if (rad_proc_attrs(req)) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; } + + struct ev_radius_t ev = { + .ses = req->rpd->ses, + .request = req->pack, + .reply = pack, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } + + if (req->rpd->auth_ctx->recv && req->rpd->auth_ctx->recv(req)) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; + } + + req->rpd->authenticated = 1; + + rad_auth_finalize(req->rpd, PWDB_SUCCESS); +} - for(i = 0; i < conf_max_try; i++) { - __sync_add_and_fetch(&req->serv->stat_auth_sent, 1); - clock_gettime(CLOCK_MONOTONIC, &tv); - if (rad_req_send(req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; +static void rad_auth_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + __sync_add_and_fetch(&req->serv->stat_auth_lost, 1); + stat_accm_add(req->serv->stat_auth_lost_1m, 1); + stat_accm_add(req->serv->stat_auth_lost_5m, 1); - timeout = conf_timeout; + if (rad_req_send(req)) + rad_auth_finalize(req->rpd, PWDB_DENIED); +} - while (timeout > 0) { +static void rad_auth_sent(struct rad_req_t *req, int res) +{ + if (res) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; + } + + __sync_add_and_fetch(&req->serv->stat_auth_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } + + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} + +static struct rad_req_t *rad_auth_req_alloc(struct radius_pd_t *rpd, const char *username, int (*recv)(struct rad_req_t *)) +{ + struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + + if (!req) + return NULL; + + if (conf_sid_in_auth) { + if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) + goto out; + } - rad_req_wait(req, timeout); + if (rpd->attr_state) { + if (rad_packet_add_octets(req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) + goto out; + } - if (req->reply) { - if (req->reply->id != req->pack->id) { - rad_packet_free(req->reply); - req->reply = NULL; - clock_gettime(CLOCK_MONOTONIC, &tv2); - timeout = conf_timeout - ((tv2.tv_sec - tv.tv_sec) * 1000 + (tv2.tv_nsec - tv.tv_nsec) / 1000000); - } else - break; - } else - break; - } + req->hnd.read = rad_req_read; + req->timeout.expire = rad_auth_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->recv = rad_auth_recv; + req->sent = rad_auth_sent; + if (conf_verbose) + req->log = log_ppp_info1; - if (req->reply) { - dt = (req->reply->tv.tv_sec - tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_auth_query_1m, dt); - stat_accm_add(req->serv->stat_auth_query_5m, dt); - break; - } else { - __sync_add_and_fetch(&req->serv->stat_auth_lost, 1); - stat_accm_add(req->serv->stat_auth_lost_1m, 1); - stat_accm_add(req->serv->stat_auth_lost_5m, 1); - } - } -out: - rad_server_req_exit(req); + rpd->auth_ctx->recv = recv; + rpd->auth_ctx->req = req; - if (!req->reply) { - rad_server_fail(req->serv); - if (rad_server_realloc(req)) { - log_ppp_warn("radius: no available servers\n"); - break; - } - } else { - if (req->reply->code == CODE_ACCESS_ACCEPT) { - if (rad_proc_attrs(req)) - return PWDB_DENIED; - return PWDB_SUCCESS; - } else - break; - } - } + return req; - return PWDB_DENIED; +out: + rad_req_free(req); + return NULL; } int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) { - struct rad_req_t *req; - int r = PWDB_DENIED; - //int id = va_arg(args, int); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); + int r; 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, req->serv->secret, req->RA, &epasswd_len); if (!epasswd) - goto out; - - if (rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len)) { - if (epasswd_len) - _free(epasswd); - goto out; - } + return PWDB_DENIED; + r = rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len); if (epasswd_len) _free(epasswd); + + if (r) + return PWDB_DENIED; - if (conf_sid_in_auth) - if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - return -1; - - r = rad_auth_send(req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = req->pack, - .reply = req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - } - -out: - rad_req_free(req); + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); uint8_t chap_password[17]; - int id = va_arg(args, int); uint8_t *challenge = va_arg(args, uint8_t *); int challenge_len = va_arg(args, int); uint8_t *response = va_arg(args, uint8_t *); + + if (!req) + return PWDB_DENIED; chap_password[0] = id; memcpy(chap_password + 1, response, 16); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (challenge_len == 16) - memcpy(rpd->auth_req->RA, challenge, 16); - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) - goto out; + if (challenge_len == 16) + memcpy(req->RA, challenge, 16); - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17)) - goto out; - } else { - if (challenge_len == 16) - memcpy(rpd->auth_req->RA, challenge, 16); - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) - goto out; + if (rad_packet_add_octets(req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) + return PWDB_DENIED; - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17)) - goto out; - - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } - - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } + if (rad_packet_add_octets(req->pack, NULL, "CHAP-Password", chap_password, 17)) + return PWDB_DENIED; - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; - - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - rpd->auth_req->pack->id++; - } - -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge) @@ -376,11 +363,26 @@ static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge) triton_event_fire(EV_MPPE_KEYS, &ev_mppe); } +static int rad_auth_mschap_v1_recv(struct rad_req_t *req) +{ + if (req->reply->code == CODE_ACCESS_ACCEPT) + setup_mppe(req, req->rpd->auth_ctx->challenge); + else { + struct rad_attr_t *ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error"); + if (ra) { + char **mschap_error = req->rpd->auth_ctx->mschap_error; + *mschap_error = _malloc(ra->len + 1); + memcpy(*mschap_error, ra->val.string, ra->len); + (*mschap_error)[ra->len] = 0; + } + } + + return 0; +} + int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; uint8_t response[50]; - struct rad_attr_t *ra; int id = va_arg(args, int); const uint8_t *challenge = va_arg(args, const uint8_t *); @@ -388,80 +390,70 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar 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); - char **mschap_error = va_arg(args, char **); + rpd->auth_ctx->mschap_error = va_arg(args, char **); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v1_recv); + + if (!req) + return PWDB_DENIED; + + rpd->auth_ctx->challenge = challenge; response[0] = id; response[1] = flags; memcpy(response + 2, lm_response, 24); memcpy(response + 2 + 24, nt_response, 24); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) - goto out; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) - goto out; - } else { - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) - goto out; - - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) - goto out; + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) + return PWDB_DENIED; + + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) + return PWDB_DENIED; + + if (rad_req_send(req)) + return PWDB_DENIED; - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } - - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } + return PWDB_WAIT; +} - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; +static int rad_auth_mschap_v2_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + struct rad_attr_t *ra; + if (req->reply->code == CODE_ACCESS_ACCEPT) { + ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP2-Success"); + if (!ra) { + log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n"); + return -1; + } else + memcpy(rpd->auth_ctx->authenticator, ra->val.octets + 3, 40); - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - setup_mppe(rpd->auth_req, challenge); - rpd->auth_req->pack->id++; - } else if (rpd->auth_req->reply) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error"); + setup_mppe(rpd->auth_ctx->req, NULL); + } else { + ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error"); if (ra) { + char **mschap_error = req->rpd->auth_ctx->mschap_error; *mschap_error = _malloc(ra->len + 1); memcpy(*mschap_error, ra->val.string, ra->len); (*mschap_error)[ra->len] = 0; } - } -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + ra = rad_packet_find_attr(req->reply, NULL, "Reply-Message"); + if (ra) { + char **reply_msg = req->rpd->auth_ctx->reply_msg; + *reply_msg = _malloc(ra->len + 1); + memcpy(*reply_msg, ra->val.string, ra->len); + (*reply_msg)[ra->len] = 0; + } + } - return r; + return 0; } int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; - struct rad_attr_t *ra; uint8_t mschap_response[50]; + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v2_recv); int id = va_arg(args, int); const uint8_t *challenge = va_arg(args, const uint8_t *); @@ -469,9 +461,12 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar const uint8_t *reserved = 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 *); - char **mschap_error = va_arg(args, char **); - char **reply_msg = va_arg(args, char **); + rpd->auth_ctx->authenticator = va_arg(args, uint8_t *); + rpd->auth_ctx->mschap_error = va_arg(args, char **); + rpd->auth_ctx->reply_msg = va_arg(args, char **); + + if (!req) + return PWDB_DENIED; mschap_response[0] = id; mschap_response[1] = flags; @@ -479,107 +474,28 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar memcpy(mschap_response + 2 + 16, reserved, 8); memcpy(mschap_response + 2 + 16 + 8, response, 24); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) - goto out; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) - goto out; - } else { - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) - goto out; + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) + return PWDB_DENIED; - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) - goto out; - - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) + return PWDB_DENIED; - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } - - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; - - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP2-Success"); - if (!ra) { - log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n"); - r = PWDB_DENIED; - } else - memcpy(authenticator, ra->val.octets + 3, 40); - } - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - setup_mppe(rpd->auth_req, NULL); - rpd->auth_req->pack->id++; - } else if (rpd->auth_req->reply) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error"); - if (ra) { - *mschap_error = _malloc(ra->len + 1); - memcpy(*mschap_error, ra->val.string, ra->len); - (*mschap_error)[ra->len] = 0; - } - ra = rad_packet_find_attr(rpd->auth_req->reply, NULL, "Reply-Message"); - if (ra) { - *reply_msg = _malloc(ra->len + 1); - memcpy(*reply_msg, ra->val.string, ra->len); - (*reply_msg)[ra->len] = 0; - } - } - -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } - int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args) { - struct rad_req_t *req; - int r = PWDB_DENIED; - - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); + if (!req) return PWDB_DENIED; - - if (conf_sid_in_auth) - if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - return -1; - r = rad_auth_send(req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = req->pack, - .reply = req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - } - - rad_req_free(req); + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c index 5bff60af..87c337fe 100644 --- a/accel-pppd/radius/packet.c +++ b/accel-pppd/radius/packet.c @@ -143,13 +143,14 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) else n = read(fd, pack->buf, REQ_LENGTH_MAX); if (n < 0) { - if (errno == EAGAIN) { - rad_packet_free(pack); - return -1; - } + rad_packet_free(pack); + if (errno == EAGAIN) + return 1; + if (errno != ECONNREFUSED) log_ppp_error("radius:packet:read: %s\n", strerror(errno)); - goto out_err; + + return -1; } break; } diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index a3b211ea..ec7d9119 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -54,6 +54,7 @@ static void *pd_key; static struct ipdb_t ipdb; static mempool_t rpd_pool; +static mempool_t auth_ctx_pool; int rad_proc_attrs(struct rad_req_t *req) { @@ -159,7 +160,7 @@ int rad_proc_attrs(struct rad_req_t *req) return res; } -static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const char *username, int type, va_list _args) +static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, pwdb_callback cb, void *cb_arg, const char *username, int type, va_list _args) { int r = PWDB_NO_IMPL; va_list args; @@ -180,6 +181,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha username1[len + 1 + conf_default_realm_len] = 0; username = username1; } + + rpd->auth_ctx = mempool_alloc(auth_ctx_pool); + memset(rpd->auth_ctx, 0, sizeof(rpd->auth_ctx)); + + rpd->auth_ctx->cb = cb; + rpd->auth_ctx->cb_arg = cb_arg; va_copy(args, _args); @@ -208,8 +215,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha va_end(args); - if (r == PWDB_SUCCESS) - rpd->authenticated = 1; + if (r == PWDB_DENIED) { + if (rpd->auth_ctx->req) + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } return r; } @@ -247,8 +258,6 @@ static struct ipv6db_prefix_t *get_ipv6_prefix(struct ap_session *ses) return NULL; } - - static void session_timeout(struct triton_timer_t *t) { struct radius_pd_t *rpd = container_of(t, typeof(*rpd), session_timeout); @@ -290,6 +299,7 @@ static void ses_starting(struct ap_session *ses) memset(rpd, 0, sizeof(*rpd)); rpd->pd.key = &pd_key; rpd->ses = ses; + rpd->refs = 1; pthread_mutex_init(&rpd->lock, NULL); INIT_LIST_HEAD(&rpd->plugin_list); INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list); @@ -315,6 +325,9 @@ static void ses_acct_start(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); + if (!conf_accounting) + return; + if (!rpd->authenticated) return; @@ -322,26 +335,35 @@ static void ses_acct_start(struct ap_session *ses) ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0); return; } - + + ses->acct_start++; +} + +static void ses_started(struct ap_session *ses) +{ + struct radius_pd_t *rpd = find_pd(ses); + if (rpd->session_timeout.expire_tv.tv_sec) { rpd->session_timeout.expire = session_timeout; triton_timer_add(ses->ctrl->ctx, &rpd->session_timeout, 0); } - + if (rpd->idle_timeout.period) { rpd->idle_timeout.expire = idle_timeout; triton_timer_add(ses->ctrl->ctx, &rpd->idle_timeout, 0); } } + static void ses_finishing(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); - if (!rpd->authenticated) + if (!rpd->acct_started) return; rad_acct_stop(rpd); } + static void ses_finished(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); @@ -353,11 +375,19 @@ static void ses_finished(struct ap_session *ses) pthread_mutex_unlock(&rpd->lock); pthread_rwlock_unlock(&sessions_lock); - if (rpd->auth_req) - rad_req_free(rpd->auth_req); + if (rpd->auth_ctx) { + rad_server_req_cancel(rpd->auth_ctx->req); + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } - if (rpd->acct_req) - rad_req_free(rpd->acct_req); + if (rpd->acct_req) { + if (rpd->acct_started) + rad_acct_stop_defer(rpd); + else + rad_req_free(rpd->acct_req); + } if (rpd->dm_coa_req) dm_coa_cancel(rpd); @@ -373,7 +403,7 @@ static void ses_finished(struct ap_session *ses) if (rpd->attr_state) _free(rpd->attr_state); - + while (!list_empty(&rpd->ipv6_addr.addr_list)) { a = list_entry(rpd->ipv6_addr.addr_list.next, typeof(*a), entry); list_del(&a->entry); @@ -388,7 +418,7 @@ static void ses_finished(struct ap_session *ses) list_del(&rpd->pd.entry); - mempool_free(rpd); + release_pd(rpd); } struct radius_pd_t *find_pd(struct ap_session *ses) @@ -406,6 +436,16 @@ struct radius_pd_t *find_pd(struct ap_session *ses) abort(); } +void hold_pd(struct radius_pd_t *rpd) +{ + rpd->refs++; +} + +void release_pd(struct radius_pd_t *rpd) +{ + if (--rpd->refs == 0) + mempool_free(rpd); +} struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, const char *port_id, int port, in_addr_t ipaddr, const char *csid) { @@ -650,6 +690,7 @@ static void radius_init(void) struct conf_option_t *opt1; rpd_pool = mempool_create(sizeof(struct radius_pd_t)); + auth_ctx_pool = mempool_create(sizeof(struct radius_auth_ctx)); if (load_config()) _exit(EXIT_FAILURE); @@ -670,6 +711,7 @@ static void radius_init(void) ipdb_register(&ipdb); triton_event_register_handler(EV_SES_STARTING, (triton_event_func)ses_starting); + triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ses_started); triton_event_register_handler(EV_SES_ACCT_START, (triton_event_func)ses_acct_start); triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ses_finishing); triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ses_finished); diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h index 8ad69da0..cfb92cd6 100644 --- a/accel-pppd/radius/radius_p.h +++ b/accel-pppd/radius/radius_p.h @@ -9,18 +9,32 @@ #include "radius.h" #include "ppp.h" #include "ipdb.h" +#include "pwdb.h" struct rad_server_t; +struct radius_auth_ctx { + struct rad_req_t *req; + pwdb_callback cb; + void *cb_arg; + int (*recv)(struct rad_req_t *); + + const uint8_t *challenge; + uint8_t *authenticator; + char **mschap_error; + char **reply_msg; +}; + struct radius_pd_t { struct list_head entry; struct ap_private pd; struct ap_session *ses; pthread_mutex_t lock; + int refs:8; int authenticated:1; + int acct_started:1; int ipv6_dp_assigned:1; - struct rad_req_t *auth_req; struct rad_req_t *acct_req; struct triton_timer_t acct_interim_timer; @@ -34,7 +48,6 @@ struct radius_pd_t { struct ipv6db_item_t ipv6_addr; struct ipv6db_prefix_t ipv6_dp; int acct_interim_interval; - time_t acct_timestamp; uint8_t *attr_class; int attr_class_len; @@ -42,12 +55,13 @@ struct radius_pd_t { int attr_state_len; int termination_action; + struct radius_auth_ctx *auth_ctx; + struct list_head plugin_list; }; struct rad_req_t { struct list_head entry; - struct triton_context_t ctx; struct triton_md_handler_t hnd; struct triton_timer_t timeout; uint8_t RA[16]; @@ -56,11 +70,21 @@ struct rad_req_t { struct radius_pd_t *rpd; struct rad_server_t *serv; - struct triton_context_t *wait_ctx; in_addr_t server_addr; - int server_port; - int type; + + int server_port:16; + int type:8; + int try:6; + int active:1; + int async:1; + + time_t ts; + + void (*recv)(struct rad_req_t *); + int (*before_send)(struct rad_req_t *); + int (*send)(struct rad_req_t *, int async); + void (*sent)(struct rad_req_t *, int res); void (*log)(const char *fmt, ...); }; @@ -149,13 +173,16 @@ void rad_dict_free(struct rad_dict_t *dict); struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username); struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port); +struct rad_req_t *rad_req_alloc_empty(); 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 *req, void (*log)(const char *fmt, ...)); -int rad_req_wait(struct rad_req_t *, int); +int rad_req_send(struct rad_req_t *req); +int rad_req_read(struct triton_md_handler_t *h); struct radius_pd_t *find_pd(struct ap_session *ses); int rad_proc_attrs(struct rad_req_t *req); +void hold_pd(struct radius_pd_t *rpd); +void release_pd(struct radius_pd_t *rpd); 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); @@ -164,7 +191,8 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar int rad_auth_null(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); +int rad_acct_stop(struct radius_pd_t *rpd); +void rad_acct_stop_defer(struct radius_pd_t *rpd); struct rad_packet_t *rad_packet_alloc(int code); int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA); @@ -180,6 +208,7 @@ struct rad_server_t *rad_server_get2(int, in_addr_t, int); void rad_server_put(struct rad_server_t *, int); int rad_server_req_enter(struct rad_req_t *); void rad_server_req_exit(struct rad_req_t *); +int rad_server_req_cancel(struct rad_req_t *); int rad_server_realloc(struct rad_req_t *); void rad_server_fail(struct rad_server_t *); void rad_server_timeout(struct rad_server_t *); diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c index 27a33f25..172fb1c9 100644 --- a/accel-pppd/radius/req.c +++ b/accel-pppd/radius/req.c @@ -4,25 +4,26 @@ #include <errno.h> #include <fcntl.h> #include <unistd.h> -#include <sched.h> +#include <assert.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "log.h" #include "radius_p.h" +#include "mempool.h" #include "memdebug.h" -static int rad_req_read(struct triton_md_handler_t *h); -static void rad_req_timeout(struct triton_timer_t *t); static int make_socket(struct rad_req_t *req); +static mempool_t req_pool; static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port) { struct rad_plugin_t *plugin; struct ppp_t *ppp = NULL; - struct rad_req_t *req = _malloc(sizeof(*req)); + struct rad_req_t *req = mempool_alloc(req_pool); + struct timespec ts; if (!req) { log_emerg("radius: out of memory\n"); @@ -32,10 +33,13 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons if (rpd->ses->ctrl->ppp) ppp = container_of(rpd->ses, typeof(*ppp), ses); + clock_gettime(CLOCK_MONOTONIC, &ts); + memset(req, 0, sizeof(*req)); req->rpd = rpd; req->hnd.fd = -1; - req->ctx.before_switch = log_switch; + req->hnd.read = rad_req_read; + req->ts = ts.tv_sec; req->type = code == CODE_ACCESS_REQUEST ? RAD_SERV_AUTH : RAD_SERV_ACCT; @@ -161,6 +165,21 @@ struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char * return req; } +struct rad_req_t *rad_req_alloc_empty() +{ + struct rad_req_t *req = mempool_alloc(req_pool); + + if (!req) { + log_emerg("radius: out of memory\n"); + return NULL; + } + + memset(req, 0, sizeof(*req)); + req->hnd.fd = -1; + + return req; +} + int rad_req_acct_fill(struct rad_req_t *req) { struct ipv6db_addr_t *a; @@ -211,15 +230,26 @@ int rad_req_acct_fill(struct rad_req_t *req) void rad_req_free(struct rad_req_t *req) { + assert(!req->active); + if (req->serv) rad_server_put(req->serv, req->type); - if (req->hnd.fd >= 0 ) + + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 1); + else if (req->hnd.fd != -1) close(req->hnd.fd); + + if (req->timeout.tpd) + triton_timer_del(&req->timeout); + if (req->pack) rad_packet_free(req->pack); + if (req->reply) rad_packet_free(req->reply); - _free(req); + + mempool_free(req); } static int make_socket(struct rad_req_t *req) @@ -231,7 +261,7 @@ static int make_socket(struct rad_req_t *req) log_ppp_error("radius:socket: %s\n", strerror(errno)); return -1; } - + fcntl(req->hnd.fd, F_SETFD, fcntl(req->hnd.fd, F_GETFD) | FD_CLOEXEC); memset(&addr, 0, sizeof(addr)); @@ -270,95 +300,120 @@ out_err: return -1; } -int rad_req_send(struct rad_req_t *req, void (*log)(const char *fmt, ...)) +static int __rad_req_send(struct rad_req_t *req, int async) { + if (async == -1) { + req->try = conf_max_try - 1; + rad_req_send(req); + return 0; + } + if (req->hnd.fd == -1 && make_socket(req)) return -1; + + if (req->before_send && req->before_send(req)) + goto out_err; if (!req->pack->buf && rad_packet_build(req->pack, req->RA)) goto out_err; - if (log) { - log("send "); - rad_packet_print(req->pack, req->serv, log); + if (req->log) { + req->log("send "); + rad_packet_print(req->pack, req->serv, req->log); } + + if (req->sent) + req->sent(req, 0); rad_packet_send(req->pack, req->hnd.fd, NULL); return 0; out_err: - close(req->hnd.fd); - req->hnd.fd = -1; + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 1); + else { + close(req->hnd.fd); + req->hnd.fd = -1; + } + + if (async && req->sent) + req->sent(req, -1); + return -1; } -static void req_wakeup(struct rad_req_t *req) -{ - struct triton_context_t *ctx = req->wait_ctx; - if (req->timeout.tpd) - triton_timer_del(&req->timeout); - triton_md_unregister_handler(&req->hnd, 0); - triton_context_unregister(&req->ctx); - triton_context_wakeup(ctx); -} -static int rad_req_read(struct triton_md_handler_t *h) +int rad_req_send(struct rad_req_t *req) { - struct rad_req_t *req = container_of(h, typeof(*req), hnd); - struct rad_packet_t *pack; int r; - while (1) { - r = rad_packet_recv(h->fd, &pack, NULL); - - if (pack) { - if (req->reply) - rad_packet_free(req->reply); - req->reply = pack; + req->send = __rad_req_send; + + if (req->try++ == conf_max_try) { + rad_server_req_exit(req); + rad_server_fail(req->serv); + + if (rad_server_realloc(req)) { + if (req->rpd) + log_ppp_warn("radius: no available servers\n"); + return -1; } - if (r) - break; + req->try = 1; } - req_wakeup(req); - - return 1; -} -static void rad_req_timeout(struct triton_timer_t *t) -{ - struct rad_req_t *req = container_of(t, typeof(*req), timeout); - - req_wakeup(req); + if (!req->active) { + while (1) { + r = rad_server_req_enter(req); + + if (r >= 0) + break; + + if (rad_server_realloc(req)) { + if (req->rpd) + log_ppp_warn("radius: no available servers\n"); + return -1; + } + } + } else + r = __rad_req_send(req, 0); + + return r; } -int rad_req_wait(struct rad_req_t *req, int timeout) +int rad_req_read(struct triton_md_handler_t *h) { - req->wait_ctx = triton_context_self(); - req->hnd.read = rad_req_read; - req->timeout.expire = rad_req_timeout; - - triton_context_register(&req->ctx, req->rpd ? req->rpd->ses : NULL); - triton_context_set_priority(&req->ctx, 1); - triton_md_register_handler(&req->ctx, &req->hnd); - triton_md_enable_handler(&req->hnd, MD_MODE_READ); + struct rad_req_t *req = container_of(h, typeof(*req), hnd); + struct rad_packet_t *pack; - req->timeout.period = timeout * 1000; - triton_timer_add(&req->ctx, &req->timeout, 0); + while (1) { + if (rad_packet_recv(h->fd, &pack, NULL)) + return 0; + + if (pack->id == req->pack->id) + break; + + rad_packet_free(req->reply); + } - triton_context_wakeup(&req->ctx); + req->reply = pack; - triton_context_schedule(); + rad_server_req_exit(req); - if (req->log && req->reply) { + if (req->log) { req->log("recv "); rad_packet_print(req->reply, req->serv, req->log); } - return 0; + + if (req->recv) + req->recv(req); + + return 1; } static void req_init(void) { + req_pool = mempool_create(sizeof(struct rad_req_t)); } DEFINE_INIT(50, req_init); diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c index 0910314a..6c01a886 100644 --- a/accel-pppd/radius/serv.c +++ b/accel-pppd/radius/serv.c @@ -100,6 +100,48 @@ void rad_server_put(struct rad_server_t *s, int type) } } +static void req_wakeup(struct rad_req_t *req) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + pthread_mutex_lock(&req->serv->lock); + + if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) { + req->active = 0; + req->serv->req_cnt--; + pthread_mutex_unlock(&req->serv->lock); + + req->send(req, -1); + + return; + } + pthread_mutex_unlock(&req->serv->lock); + + req->send(req, 1); +} + +int rad_server_req_cancel(struct rad_req_t *req) +{ + int r = 0; + + pthread_mutex_lock(&req->serv->lock); + if (req->entry.next) { + list_del(&req->entry); + req->serv->queue_cnt--; + r = 1; + } + pthread_mutex_unlock(&req->serv->lock); + + rad_server_req_exit(req); + + if (req->timeout.tpd) + triton_timer_del(&req->timeout); + + return r; +} + int rad_server_req_enter(struct rad_req_t *req) { struct timespec ts; @@ -112,8 +154,13 @@ int rad_server_req_enter(struct rad_req_t *req) if (ts.tv_sec < req->serv->fail_time) return -1; - if (!req->serv->req_limit) + if (!req->serv->req_limit) { + if (req->send) + return req->send(req, 0); return 0; + } + + assert(!req->active); pthread_mutex_lock(&req->serv->lock); @@ -123,46 +170,47 @@ int rad_server_req_enter(struct rad_req_t *req) } if (req->serv->req_cnt >= req->serv->req_limit) { - list_add_tail(&req->entry, &req->serv->req_queue); - req->serv->queue_cnt++; - - pthread_mutex_unlock(&req->serv->lock); - triton_context_schedule(); - pthread_mutex_lock(&req->serv->lock); - - req->serv->queue_cnt--; - if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) { + if (req->send) { + list_add_tail(&req->entry, &req->serv->req_queue); + req->serv->queue_cnt++; pthread_mutex_unlock(&req->serv->lock); - return -1; + return 0; } + + pthread_mutex_unlock(&req->serv->lock); + return 1; } req->serv->req_cnt++; log_ppp_debug("radius(%i): req_enter %i\n", req->serv->id, req->serv->req_cnt); pthread_mutex_unlock(&req->serv->lock); + + req->active = 1; return 0; } void rad_server_req_exit(struct rad_req_t *req) { - struct rad_req_t *r = NULL; - if (!req->serv->req_limit) return; + assert(req->active); + + req->active = 0; + pthread_mutex_lock(&req->serv->lock); req->serv->req_cnt--; log_ppp_debug("radius(%i): req_exit %i\n", req->serv->id, req->serv->req_cnt); assert(req->serv->req_cnt >= 0); if (req->serv->req_cnt < req->serv->req_limit && !list_empty(&req->serv->req_queue)) { - r = list_entry(req->serv->req_queue.next, typeof(*r), entry); + struct rad_req_t *r = list_entry(req->serv->req_queue.next, typeof(*r), entry); list_del(&r->entry); + req->serv->queue_cnt--; + req->active = 1; + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } pthread_mutex_unlock(&req->serv->lock); - - if (r) - triton_context_wakeup(r->rpd->ses->ctrl->ctx); } int rad_server_realloc(struct rad_req_t *req) @@ -214,7 +262,7 @@ void rad_server_fail(struct rad_server_t *s) while (!list_empty(&s->req_queue)) { r = list_entry(s->req_queue.next, typeof(*r), entry); list_del(&r->entry); - triton_context_wakeup(r->rpd->ses->ctrl->ctx); + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } } @@ -223,7 +271,7 @@ void rad_server_fail(struct rad_server_t *s) void rad_server_timeout(struct rad_server_t *s) { - if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try) + if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try * 3) rad_server_fail(s); } @@ -248,13 +296,49 @@ static int req_set_RA(struct rad_req_t *req, const char *secret) return 0; } +static void acct_on_sent(struct rad_req_t *req, int res) +{ + if (!res && !req->hnd.tpd) { + triton_md_register_handler(&req->serv->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } +} + +static void acct_on_recv(struct rad_req_t *req) +{ + struct rad_server_t *s = req->serv; + + rad_req_free(req); + + if (req->serv->starting) { + req->serv->starting = 0; + req->serv->acct_on = 1; + } else + __free_server(s); +} + +static void acct_on_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + struct rad_server_t *s = req->serv; + + if (!s->starting && ++req->serv->req_cnt == conf_max_try) { + rad_req_free(req); + __free_server(s); + return; + } + + req->try = 1; + + rad_req_send(req); +} + static void send_acct_on(struct rad_server_t *s) { struct rad_req_t *req = _malloc(sizeof(*req)); - int i; if (!req) - goto out_err; + return; memset(req, 0, sizeof(*req)); req->hnd.fd = -1; @@ -262,6 +346,12 @@ static void send_acct_on(struct rad_server_t *s) req->server_addr = s->addr; req->server_port = s->acct_port; req->serv = s; + req->sent = acct_on_sent; + req->recv = acct_on_recv; + req->hnd.read = rad_req_read; + req->timeout.expire = acct_on_timeout; + req->timeout.period = conf_timeout * 1000; + req->try = 1; __sync_add_and_fetch(&s->client_cnt[req->type], 1); if (conf_verbose) req->log = log_info1; @@ -284,55 +374,14 @@ static void send_acct_on(struct rad_server_t *s) if (req_set_RA(req, s->secret)) goto out_err; - for (i = 0; i < conf_max_try; i++) { - if (rad_req_send(req, conf_verbose ? log_info1 : NULL)) - goto out_err; - - rad_req_wait(req, conf_timeout); - - if (!s->starting) - break; + rad_req_send(req); - if (!req->reply) - continue; - - if (req->reply->id == req->pack->id && req->reply->code == CODE_ACCOUNTING_RESPONSE) { - s->starting = 0; - s->acct_on = 1; - break; - } - - rad_packet_free(req->reply); - req->reply = NULL; - } - - if (!s->starting) { - if (s->timer.tpd) - triton_timer_del(&s->timer); - - if (!s->acct_on) - triton_context_unregister(&s->ctx); - - rad_req_free(req); + triton_timer_add(&s->ctx, &req->timeout, 0); - return; - } + return; out_err: - if (req) - rad_req_free(req); - - if (s->timer.tpd) - triton_timer_mod(&s->timer, 0); - else - triton_timer_add(&s->ctx, &s->timer, 0); -} - -static void restart_acct_on(struct triton_timer_t *t) -{ - struct rad_server_t *s = container_of(t, typeof(*s), timer); - - send_acct_on(s); + rad_req_free(req); } static void serv_ctx_close(struct triton_context_t *ctx) @@ -444,6 +493,14 @@ static void __add_server(struct rad_server_t *s) s->stat_interim_lost_5m = stat_accm_create(5 * 60); s->stat_interim_query_1m = stat_accm_create(60); s->stat_interim_query_5m = stat_accm_create(5 * 60); + + s->ctx.close = serv_ctx_close; + + triton_context_register(&s->ctx, NULL); + triton_context_set_priority(&s->ctx, 1); + if (conf_acct_on) + triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s); + triton_context_wakeup(&s->ctx); } static void __free_server(struct rad_server_t *s) @@ -465,6 +522,8 @@ static void __free_server(struct rad_server_t *s) stat_accm_free(s->stat_interim_query_1m); stat_accm_free(s->stat_interim_query_5m); + triton_context_unregister(&s->ctx); + _free(s); } @@ -732,7 +791,7 @@ static void load_config(void) while (!list_empty(&s->req_queue)) { r = list_entry(s->req_queue.next, typeof(*r), entry); list_del(&r->entry); - triton_context_wakeup(r->rpd->ses->ctrl->ctx); + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } if (!s->client_cnt[0] && !s->client_cnt[1]) { @@ -756,18 +815,8 @@ static void load_config(void) list_for_each_entry(s, &serv_list, entry) { if (s->starting) { - if (!conf_accounting || !s->acct_port) + if (!conf_accounting || !s->auth_port) s->starting = 0; - else { - s->ctx.close = serv_ctx_close; - s->timer.expire = restart_acct_on; - s->timer.expire_tv.tv_sec = 10; - - triton_context_register(&s->ctx, NULL); - triton_context_set_priority(&s->ctx, 1); - triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s); - triton_context_wakeup(&s->ctx); - } } } } diff --git a/accel-pppd/session.c b/accel-pppd/session.c index cff5b302..6616f684 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -227,7 +227,7 @@ void __export ap_session_terminate(struct ap_session *ses, int cause, int hard) ap_session_read_stats(ses, NULL); triton_event_fire(EV_SES_FINISHING, ses); - + ses->ctrl->terminate(ses, hard); } diff --git a/accel-pppd/triton/mempool.c b/accel-pppd/triton/mempool.c index 4a3ec8b0..7e5a4ce2 100644 --- a/accel-pppd/triton/mempool.c +++ b/accel-pppd/triton/mempool.c @@ -15,7 +15,7 @@ #define DELAY 5 #endif -//#define MEMPOOL_DISABLE +#define MEMPOOL_DISABLE #define MAGIC1 0x2233445566778899llu #define PAGE_ORDER 5 @@ -136,72 +136,6 @@ void __export *mempool_alloc(mempool_t *pool) return it->ptr; } -#else - -void __export *mempool_alloc_md(mempool_t *pool, const char *fname, int line) -{ - struct _mempool_t *p = (struct _mempool_t *)pool; - struct _item_t *it; - uint32_t size = sizeof(*it) + p->size + 8; - - spin_lock(&p->lock); - if (!list_empty(&p->items)) { - it = list_entry(p->items.next, typeof(*it), entry); -#ifdef VALGRIND - if (it->timestamp + DELAY < time(NULL)) { - VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp)); - VALGRIND_MAKE_MEM_UNDEFINED(it->ptr, p->size); -#endif - list_del(&it->entry); - list_add(&it->entry, &p->ditems); - spin_unlock(&p->lock); - - it->fname = fname; - it->line = line; - - --p->objects; - __sync_sub_and_fetch(&triton_stat.mempool_available, size); - - it->magic1 = MAGIC1; - - return it->ptr; -#ifdef VALGRIND - } -#endif - } - spin_unlock(&p->lock); - - if (p->mmap) { - spin_lock(&mmap_lock); - if (mmap_ptr + size >= mmap_endptr) - mmap_grow(); - it = (struct _item_t *)mmap_ptr; - mmap_ptr += size; - spin_unlock(&mmap_lock); - __sync_sub_and_fetch(&triton_stat.mempool_available, size); - } else { - it = md_malloc(size, fname, line); - __sync_add_and_fetch(&triton_stat.mempool_allocated, size); - } - - if (!it) { - triton_log_error("mempool: out of memory"); - return NULL; - } - it->owner = p; - it->magic2 = p->magic; - it->magic1 = MAGIC1; - it->fname = fname; - it->line = line; - *(uint64_t*)(it->ptr + p->size) = it->magic2; - - spin_lock(&p->lock); - list_add(&it->entry, &p->ditems); - spin_unlock(&p->lock); - - return it->ptr; -} -#endif void __export mempool_free(void *ptr) { @@ -258,6 +192,18 @@ void __export mempool_free(void *ptr) } + +#else + +void __export *md_mempool_alloc(mempool_t *pool, const char *fname, int line) +{ + struct _mempool_t *p = (struct _mempool_t *)pool; + + return md_malloc(p->size, fname, line); +} +#endif + + #ifdef MEMDEBUG void __export mempool_show(mempool_t *pool) { diff --git a/accel-pppd/triton/mempool.h b/accel-pppd/triton/mempool.h index bdb3e712..53eebfb7 100644 --- a/accel-pppd/triton/mempool.h +++ b/accel-pppd/triton/mempool.h @@ -12,14 +12,15 @@ struct mempool_stat_t typedef void * mempool_t; mempool_t *mempool_create(int size); mempool_t *mempool_create2(int size); -void mempool_free(void*); struct mempool_stat_t mempool_get_stat(void); #ifdef MEMDEBUG -void *mempool_alloc_md(mempool_t*, const char *fname, int line); -#define mempool_alloc(pool) mempool_alloc_md(pool, __FILE__, __LINE__) +void *md_mempool_alloc(mempool_t*, const char *fname, int line); +#define mempool_alloc(pool) md_mempool_alloc(pool, __FILE__, __LINE__) +#define mempool_free(ptr) md_free(ptr, __FILE__, __LINE__) #else void *mempool_alloc(mempool_t*); +void mempool_free(void*); #endif #endif diff --git a/accel-pppd/triton/triton.c b/accel-pppd/triton/triton.c index 3c4de31d..5d6f31d1 100644 --- a/accel-pppd/triton/triton.c +++ b/accel-pppd/triton/triton.c @@ -569,7 +569,7 @@ static void ru_update(struct triton_timer_t *t) void __export triton_register_init(int order, void (*func)(void)) { - struct _triton_init_t *i1, *i = _malloc(sizeof(*i)); + struct _triton_init_t *i1, *i = malloc(sizeof(*i)); struct list_head *p = init_list.next; @@ -624,7 +624,7 @@ int __export triton_load_modules(const char *mod_sect) i = list_entry(init_list.next, typeof(*i), entry); i->func(); list_del(&i->entry); - _free(i); + free(i); } return 0; |