summaryrefslogtreecommitdiff
path: root/accel-pptpd/radius/radius.c
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2010-09-08 15:51:29 +0400
committerKozlov Dmitry <dima@server>2010-09-08 15:51:29 +0400
commit4c6469a9fd820db713251a645ac2499782f796ed (patch)
treefd7c4926eb2a3e2aa047bd14da429f3d6a5f8e6f /accel-pptpd/radius/radius.c
parentec759f72fcf7d517fdfe8d043c75d0218363bc78 (diff)
downloadaccel-ppp-xebd-4c6469a9fd820db713251a645ac2499782f796ed.tar.gz
accel-ppp-xebd-4c6469a9fd820db713251a645ac2499782f796ed.zip
radius: implemented packet exchange
radius: implemented PAP authorization radius: implemented IP assigning triton: implemented userspace context switching and other stuff
Diffstat (limited to 'accel-pptpd/radius/radius.c')
-rw-r--r--accel-pptpd/radius/radius.c202
1 files changed, 184 insertions, 18 deletions
diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c
index 2e444de..a786dea 100644
--- a/accel-pptpd/radius/radius.c
+++ b/accel-pptpd/radius/radius.c
@@ -3,43 +3,124 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <arpa/inet.h>
+#include <openssl/md5.h>
+
+#include "log.h"
#include "ppp.h"
#include "pwdb.h"
+#include "ipdb.h"
+
#include "radius.h"
int conf_max_try = 3;
int conf_timeout = 3;
char *conf_nas_identifier = "accel-pptpd";
char *conf_nas_ip_address;
+char *conf_gw_ip_address;
+int conf_verbose = 0;
+
+char *conf_auth_server;
+int conf_auth_server_port = 1812;
+char *conf_auth_server_secret;
+
+char *conf_acct_server;
+int conf_acct_server_port = 1813;
+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)
+{
+ struct rad_req_attr_t *attr;
+
+ list_for_each_entry(attr, &req->reply->attrs, entry) {
+ 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;
- if (rad_req_add_str(req, "User-Password", passwd, strlen(passwd)))
+ 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;
- if (rad_req_wait(req, conf_timeout))
- 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);
@@ -79,15 +160,7 @@ static int check(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username, i
int r = PWDB_NO_IMPL;
va_list args;
int chap_type;
- struct ppp_pd_t *pd;
- struct radius_pd_t *rpd = NULL;
-
- list_for_each_entry(pd, &ppp->pd_list, entry) {
- if (pd->key == &notified) {
- rpd = container_of(pd, typeof(*rpd), pd);
- break;
- }
- }
+ struct radius_pd_t *rpd = find_pd(ppp);
va_copy(args, _args);
@@ -116,6 +189,22 @@ static int check(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username, i
return r;
}
+static int get_ip(struct ppp_t *ppp, in_addr_t *addr, in_addr_t *peer_addr)
+{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ if (rpd->ipaddr) {
+ if (!conf_gw_ip_address) {
+ log_warn("radius: gw-ip-address not specified, cann't assign IP address...\n");
+ return -1;
+ }
+ *peer_addr = rpd->ipaddr;
+ *addr = inet_addr(conf_gw_ip_address);
+ return 0;
+ }
+ return -1;
+}
+
static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp)
{
struct radius_pd_t *pd = malloc(sizeof(*pd));
@@ -128,19 +217,32 @@ static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp)
static void ppp_finished(struct ppp_notified_t *n, struct ppp_t *ppp)
{
+ struct radius_pd_t *rpd = find_pd(ppp);
+
+ list_del(&rpd->pd.entry);
+ free(rpd);
+}
+
+static struct radius_pd_t *find_pd(struct ppp_t *ppp)
+{
struct ppp_pd_t *pd;
struct radius_pd_t *rpd;
list_for_each_entry(pd, &ppp->pd_list, entry) {
if (pd->key == &notified) {
rpd = container_of(pd, typeof(*rpd), pd);
- list_del(&pd->entry);
- free(rpd);
- return;
+ return rpd;
}
}
+ log_error("radius:BUG: rpd not found\n");
+ abort();
}
+
+static struct ipdb_t ipdb = {
+ .get = get_ip,
+};
+
static struct pwdb_t pwdb = {
.check = check,
};
@@ -150,17 +252,81 @@ static struct ppp_notified_t notified = {
.finished = ppp_finished,
};
+static int parse_server(const char *opt, char **name, int *port, char **secret)
+{
+ char *str = strdup(opt);
+ char *p1, *p2;
+
+ p1 = strstr(str, ":");
+ p2 = strstr(str, ",");
+
+ if (p1)
+ *p1 = 0;
+ if (p2)
+ *p2 = 0;
+ else
+ return -1;
+
+ *name = str;
+ if (p1) {
+ *port = atoi(p1 + 1);
+ if (*port <=0 )
+ return -1;
+ }
+ *secret = p2 + 1;
+
+ return 0;
+}
+
static void __init radius_init(void)
{
- char *dict = conf_get_opt("radius", "dictionary");
- if (!dict) {
+ char *opt;
+
+ opt = conf_get_opt("radius", "max-try");
+ if (opt && atoi(opt) > 0)
+ conf_max_try = atoi(opt);
+
+ opt = conf_get_opt("radius", "timeout");
+ if (opt && atoi(opt) > 0)
+ conf_timeout = atoi(opt);
+
+ opt = conf_get_opt("radius", "verbose");
+ if (opt && atoi(opt) > 0)
+ conf_verbose = 1;
+
+ opt = conf_get_opt("radius", "nas-ip-address");
+ if (opt)
+ conf_nas_ip_address = opt;
+
+ opt = conf_get_opt("radius", "gw-ip-address");
+ if (opt)
+ conf_gw_ip_address = opt;
+
+ opt = conf_get_opt("radius", "auth_server");
+ if (!opt) {
+ log_error("radius: auth_server not specified\n");
+ _exit(EXIT_FAILURE);
+ } else if (parse_server(opt, &conf_auth_server, &conf_auth_server_port, &conf_auth_server_secret)) {
+ log_error("radius: failed to parse auth_server\n");
+ _exit(EXIT_FAILURE);
+ }
+
+ opt = conf_get_opt("radius", "acct_server");
+ if (opt && parse_server(opt, &conf_acct_server, &conf_acct_server_port, &conf_acct_server_secret)) {
+ log_error("radius: failed to parse acct_server\n");
+ _exit(EXIT_FAILURE);
+ }
+
+ opt = conf_get_opt("radius", "dictionary");
+ if (!opt) {
fprintf(stderr, "radius: dictionary not specified\n");
_exit(EXIT_FAILURE);
}
- if (!rad_dict_load(dict))
+ if (rad_dict_load(opt))
_exit(EXIT_FAILURE);
pwdb_register(&pwdb);
+ ipdb_register(&ipdb);
ppp_register_notified(&notified);
}