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