summaryrefslogtreecommitdiff
path: root/accel-pptpd/radius
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 /accel-pptpd/radius
parent4dcca9422c5c001789b17c3266f3db8e0590568d (diff)
downloadaccel-ppp-xebd-29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5.tar.gz
accel-ppp-xebd-29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5.zip
radius: implemented accounting (start/stop/interim-update)
Diffstat (limited to 'accel-pptpd/radius')
-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
8 files changed, 572 insertions, 205 deletions
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))