summaryrefslogtreecommitdiff
path: root/accel-pptpd/radius
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
parentec759f72fcf7d517fdfe8d043c75d0218363bc78 (diff)
downloadaccel-ppp-4c6469a9fd820db713251a645ac2499782f796ed.tar.gz
accel-ppp-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')
-rw-r--r--accel-pptpd/radius/dict.c26
-rw-r--r--accel-pptpd/radius/packet.c169
-rw-r--r--accel-pptpd/radius/radius.c202
-rw-r--r--accel-pptpd/radius/radius.h26
-rw-r--r--accel-pptpd/radius/req.c145
5 files changed, 451 insertions, 117 deletions
diff --git a/accel-pptpd/radius/dict.c b/accel-pptpd/radius/dict.c
index 00f67af7..d76c2c39 100644
--- a/accel-pptpd/radius/dict.c
+++ b/accel-pptpd/radius/dict.c
@@ -210,7 +210,17 @@ struct rad_dict_attr_t *rad_dict_find_attr(const char *name)
return NULL;
}
-struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, const char *name)
+struct rad_dict_attr_t *rad_dict_find_attr_id(int id)
+{
+ struct rad_dict_attr_t *attr;
+
+ list_for_each_entry(attr, &dict->items, entry)
+ if (attr->id == id)
+ return attr;
+
+ return NULL;
+}
+struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, const char *name)
{
struct rad_dict_value_t *val;
@@ -220,3 +230,17 @@ struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, const c
return NULL;
}
+
+struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_value_t v)
+{
+ struct rad_dict_value_t *val;
+
+ if (attr->type != ATTR_TYPE_INTEGER)
+ return NULL;
+
+ list_for_each_entry(val, &attr->values, entry)
+ if (val->val.integer == v.integer)
+ return val;
+
+ return NULL;
+}
diff --git a/accel-pptpd/radius/packet.c b/accel-pptpd/radius/packet.c
index f1b4ebea..627b6c5e 100644
--- a/accel-pptpd/radius/packet.c
+++ b/accel-pptpd/radius/packet.c
@@ -4,14 +4,40 @@
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
+#include <fcntl.h>
#include "log.h"
#include "radius.h"
-static int urandom_fd;
+struct rad_packet_t *rad_packet_alloc(int code)
+{
+ struct rad_packet_t *pack;
+
+ pack = malloc(sizeof(*pack));
+ if (!pack) {
+ log_error("radius:packet: out of memory\n");
+ return NULL;
+ }
+
+ memset(pack, 0, sizeof(*pack));
+ pack->code = code;
+ pack->len = 20;
+ pack->id = 1;
+ INIT_LIST_HEAD(&pack->attrs);
+
+ return pack;
+}
-int rad_packet_build(struct rad_packet_t *pack)
+void print_buf(uint8_t *buf,int size)
+{
+ int i;
+ for(i=0;i<size;i++)
+ printf("%x ",buf[i]);
+ printf("\n");
+}
+
+int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
{
struct rad_req_attr_t *attr;
uint8_t *ptr;
@@ -22,26 +48,18 @@ int rad_packet_build(struct rad_packet_t *pack)
return -1;
}
+ pack->buf = ptr;
*ptr = pack->code; ptr++;
*ptr = pack->id; ptr++;
- *(uint16_t*)ptr = pack->len; ptr+= 2;
- while (1) {
- if (read(urandom_fd, ptr, 16) != 16) {
- if (errno == EINTR)
- continue;
- log_error("radius:packet:read urandom: %s\n", strerror(errno));
- goto out_err;
- }
- break;
- }
- ptr+=16;
+ *(uint16_t*)ptr = htons(pack->len); ptr+= 2;
+ memcpy(ptr, RA, 16); ptr+=16;
list_for_each_entry(attr, &pack->attrs, entry) {
- *ptr = attr->attr->type; ptr++;
- *ptr = attr->len; ptr++;
+ *ptr = attr->attr->id; ptr++;
+ *ptr = attr->len + 2; ptr++;
switch(attr->attr->type) {
case ATTR_TYPE_INTEGER:
- *(uint32_t*)ptr = attr->val.integer;
+ *(uint32_t*)ptr = htonl(attr->val.integer);
break;
case ATTR_TYPE_STRING:
memcpy(ptr, attr->val.string, attr->len);
@@ -50,20 +68,18 @@ int rad_packet_build(struct rad_packet_t *pack)
*(in_addr_t*)ptr = attr->val.ipaddr;
break;
case ATTR_TYPE_DATE:
- *(uint32_t*)ptr = attr->val.date;
+ *(uint32_t*)ptr = htonl(attr->val.date);
break;
default:
- log_error("radius:packet: unknown attribute type\n");
+ log_error("radius:packet:BUG: unknown attribute type\n");
abort();
}
ptr += attr->len;
}
- return 0;
+ print_buf(pack->buf, pack->len);
-out_err:
- free(ptr);
- return -1;
+ return 0;
}
struct rad_packet_t *rad_packet_recv(int fd)
@@ -72,22 +88,16 @@ struct rad_packet_t *rad_packet_recv(int fd)
struct rad_req_attr_t *attr;
struct rad_dict_attr_t *da;
uint8_t *ptr;
- int n, type, len;
-
- pack = malloc(sizeof(*pack));
- if (!pack) {
- log_error("radius:packet: out of memory\n");
- return NULL;
- }
+ int n, id, len;
- memset(pack, 0, sizeof(*pack));
- INIT_LIST_HEAD(&pack->attrs);
+ pack = rad_packet_alloc(0);
+ if (!pack)
+ return NULL;
pack->buf = malloc(REQ_LENGTH_MAX);
if (!pack->buf) {
log_error("radius:packet: out of memory\n");
- free(pack);
- return NULL;
+ goto out_err;
}
while (1) {
@@ -110,7 +120,7 @@ struct rad_packet_t *rad_packet_recv(int fd)
pack->code = *ptr; ptr++;
pack->id = *ptr; ptr++;
- pack->len = *(uint16_t*)ptr; ptr += 2;
+ pack->len = ntohs(*(uint16_t*)ptr); ptr += 2;
if (pack->len > n) {
log_warn("radius:packet: short packet received %i, expected %i\n", pack->len, n);
@@ -121,13 +131,17 @@ struct rad_packet_t *rad_packet_recv(int fd)
n -= 20;
while (n>0) {
- type = *ptr; ptr++;
- len = *ptr; ptr++;
+ id = *ptr; ptr++;
+ len = *ptr - 2; ptr++;
+ if (len < 0) {
+ log_warn("radius:packet short attribute len received\n");
+ goto out_err;
+ }
if (2 + len > n) {
- log_error("radius:packet: too long attribute received (%i, %i)\n", type, len);
+ log_warn("radius:packet: too long attribute received (%i, %i)\n", id, len);
goto out_err;
}
- da = rad_dict_find_attr_type(type);
+ da = rad_dict_find_attr_id(id);
if (da) {
attr = malloc(sizeof(*attr));
if (!attr) {
@@ -136,18 +150,28 @@ struct rad_packet_t *rad_packet_recv(int fd)
}
attr->attr = da;
attr->len = len;
- if (type == ATTR_TYPE_STRING) {
- attr->val.string = malloc(len);
- if (!attr->val.string) {
- log_error("radius:packet: out of memory\n");
- free(attr);
- goto out_err;
- }
- } else
- memcpy(&attr->val.integer, ptr, 4);
+ switch (da->type) {
+ case ATTR_TYPE_STRING:
+ attr->val.string = malloc(len+1);
+ if (!attr->val.string) {
+ log_error("radius:packet: out of memory\n");
+ free(attr);
+ goto out_err;
+ }
+ memcpy(attr->val.string, ptr, len);
+ attr->val.string[len] = 0;
+ break;
+ case ATTR_TYPE_DATE:
+ case ATTR_TYPE_INTEGER:
+ attr->val.integer = ntohl(*(uint32_t*)ptr);
+ break;
+ case ATTR_TYPE_IPADDR:
+ attr->val.integer = *(uint32_t*)ptr;
+ break;
+ }
list_add_tail(&attr->entry, &pack->attrs);
} else
- log_warn("radius:packet: unknown attribute type received (%i)\n", type);
+ log_warn("radius:packet: unknown attribute received (%i)\n", id);
ptr += len;
n -= 2 + len;
}
@@ -176,3 +200,52 @@ void rad_packet_free(struct rad_packet_t *pack)
free(pack);
}
+
+void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...))
+{
+ struct rad_req_attr_t *attr;
+ struct rad_dict_value_t *val;
+
+ print("[RADIUS ");
+ switch(pack->code) {
+ case CODE_ACCESS_REQUEST:
+ print("Access-Request");
+ break;
+ case CODE_ACCESS_CHALLENGE:
+ print("Access-Challenge");
+ break;
+ case CODE_ACCESS_ACCEPT:
+ print("Access-Accept");
+ break;
+ case CODE_ACCESS_REJECT:
+ print("Access-Reject");
+ break;
+ default:
+ print("Unknown (%i)", pack->code);
+ }
+ print(" id=%x", pack->id);
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ print(" <%s ", attr->attr->name);
+ if (attr->printable) {
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ val = rad_dict_find_val(attr->attr, attr->val);
+ if (val)
+ print("%s", val->name);
+ else
+ print("%i", attr->val.integer);
+ break;
+ case ATTR_TYPE_STRING:
+ print("\"%s\"", attr->val.string);
+ break;
+ case ATTR_TYPE_IPADDR:
+ print("%i.%i.%i.%i", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff);
+ break;
+ }
+ }
+ print(">");
+ }
+ print("]\n");
+}
+
diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c
index 2e444ded..a786dea5 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);
}
diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h
index 109981a6..40b83201 100644
--- a/accel-pptpd/radius/radius.h
+++ b/accel-pptpd/radius/radius.h
@@ -1,6 +1,7 @@
#ifndef __RADIUS_H
#define __RADIUS_H
+#include <stdint.h>
#include <netinet/in.h>
#include "triton.h"
#include "ppp.h"
@@ -13,17 +14,21 @@
#define ATTR_TYPE_IPADDR 3
#define CODE_ACCESS_REQUEST 1
+#define CODE_ACCESS_ACCEPT 2
+#define CODE_ACCESS_REJECT 3
+#define CODE_ACCESS_CHALLENGE 11
struct radius_pd_t
{
struct ppp_pd_t pd;
struct ppp_t *ppp;
+ in_addr_t ipaddr;
};
typedef union
{
int integer;
- const char *string;
+ char *string;
time_t date;
in_addr_t ipaddr;
} rad_value_t;
@@ -56,6 +61,7 @@ struct rad_req_attr_t
//struct rad_dict_value_t *val;
rad_value_t val;
int len;
+ int printable:1;
};
struct rad_packet_t
@@ -68,9 +74,11 @@ struct rad_packet_t
};
struct rad_req_t
{
+ struct triton_context_t ctx;
struct triton_md_handler_t hnd;
struct triton_timer_t timeout;
- struct rad_packet_t pack;
+ uint8_t RA[16];
+ struct rad_packet_t *pack;
struct rad_packet_t *reply;
const char *server_name;
int server_port;
@@ -81,14 +89,18 @@ struct rad_req_t
extern int conf_max_try;
extern int conf_timeout;
+extern int conf_verbose;
extern char *conf_nas_identifier;
extern char *conf_nas_ip_address;
+extern char *conf_auth_server;
+extern char *conf_acct_server;
int rad_dict_load(const char *fname);
void rad_dict_free(struct rad_dict_t *dict);
struct rad_dict_attr_t *rad_dict_find_attr(const char *name);
-struct rad_dict_attr_t *rad_dict_find_attr_type(int type);
-struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *, const char *name);
+struct rad_dict_attr_t *rad_dict_find_attr_id(int type);
+struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *, const char *name);
+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);
void rad_req_free(struct rad_req_t *);
@@ -96,11 +108,13 @@ int rad_req_send(struct rad_req_t *);
int rad_req_wait(struct rad_req_t *, int);
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 rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, int len, int printable);
-int rad_packet_build(struct rad_packet_t *pack);
+struct rad_packet_t *rad_packet_alloc(int code);
+int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
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, ...));
#endif
diff --git a/accel-pptpd/radius/req.c b/accel-pptpd/radius/req.c
index ae761547..cc59a431 100644
--- a/accel-pptpd/radius/req.c
+++ b/accel-pptpd/radius/req.c
@@ -11,11 +11,12 @@
#include "log.h"
#include "radius.h"
+static int urandom_fd;
static int rad_req_read(struct triton_md_handler_t *h);
static void rad_req_timeout(struct triton_timer_t *t);
-struct rad_req_t *rad_rec_alloc(struct radius_pd_t *rpd, int code, const char *username)
+struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
{
struct rad_req_t *req = malloc(sizeof(*req));
@@ -23,26 +24,37 @@ struct rad_req_t *rad_rec_alloc(struct radius_pd_t *rpd, int code, const char *u
return NULL;
memset(req, 0, sizeof(*req));
- INIT_LIST_HEAD(&req->pack.attrs);
req->rpd = rpd;
- req->pack.code = code;
- req->pack.len = 20;
req->hnd.fd = -1;
req->hnd.read = rad_req_read;
req->timeout.expire = rad_req_timeout;
- if (rad_req_add_str(req, "User-Name", username, strlen(username)))
+ while (1) {
+ if (read(urandom_fd, req->RA, 16) != 16) {
+ if (errno == EINTR)
+ continue;
+ log_error("radius:req:read urandom: %s\n", strerror(errno));
+ goto out_err;
+ }
+ break;
+ }
+
+ req->pack = rad_packet_alloc(code);
+ if (!req->pack)
+ goto out_err;
+
+ if (rad_req_add_str(req, "User-Name", username, strlen(username), 1))
goto out_err;
if (conf_nas_identifier)
- if (rad_req_add_str(req, "NAS-Identifier", conf_nas_identifier, strlen(conf_nas_identifier)))
+ if (rad_req_add_str(req, "NAS-Identifier", conf_nas_identifier, strlen(conf_nas_identifier), 1))
goto out_err;
if (rad_req_add_int(req, "NAS-Port-Id", rpd->ppp->unit_idx))
goto out_err;
- if (rad_req_add_str(req, "NAS-Port-Type", "Sync", 4))
+ if (rad_req_add_val(req, "NAS-Port-Type", "Sync", 4))
goto out_err;
- if (rad_req_add_str(req, "Service-Type", "Framed-User", 11))
+ if (rad_req_add_val(req, "Service-Type", "Framed-User", 4))
goto out_err;
- if (rad_req_add_str(req, "Framed-Protocol", "PPP", 3))
+ if (rad_req_add_val(req, "Framed-Protocol", "PPP", 4))
goto out_err;
return req;
@@ -52,9 +64,15 @@ out_err:
return NULL;
}
-void rad_rec_free(struct rad_req_t *req)
+void rad_req_free(struct rad_req_t *req)
{
-
+ if (req->hnd.fd >= 0 )
+ close(req->hnd.fd);
+ if (req->pack)
+ rad_packet_free(req->pack);
+ if (req->reply)
+ rad_packet_free(req->reply);
+ free(req);
}
int rad_req_send(struct rad_req_t *req)
@@ -63,22 +81,24 @@ int rad_req_send(struct rad_req_t *req)
int n;
if (req->hnd.fd == -1) {
- req->hnd.fd = socket(PF_INET, SOCK_DGRAM ,0);
- if (!req->hnd.fd) {
+ 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_family = AF_INET;
- addr.sin_addr.s_addr = htonl(inet_addr(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;
}
}
- addr.sin_addr.s_addr = htonl(inet_addr(req->server_name));
+ addr.sin_addr.s_addr = inet_addr(req->server_name);
addr.sin_port = htons(req->server_port);
if (connect(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) {
@@ -91,28 +111,32 @@ int rad_req_send(struct rad_req_t *req)
goto out_err;
}
- if (rad_packet_build(&req->pack))
+ if (rad_packet_build(req->pack, req->RA))
goto out_err;
}
+ if (conf_verbose) {
+ log_debug("send ");
+ rad_packet_print(req->pack, log_debug);
+ }
+
while (1) {
- n = write(req->hnd.fd, req->pack.buf, req->pack.len);
+ n = write(req->hnd.fd, req->pack->buf, req->pack->len);
+ //n = sendto(req->hnd.fd, req->pack->buf, req->pack->len, 0, &addr, sizeof(addr));
if (n < 0) {
if (errno == EINTR)
continue;
log_error("radius:write: %s\n", strerror(errno));
- goto out_err_free_pack;
- } else if (n != req->pack.len) {
- log_error("radius:write: short write %i, excpected %i\n", n, req->pack.len);
- goto out_err_free_pack;
+ goto out_err;
+ } else if (n != req->pack->len) {
+ log_error("radius:write: short write %i, excpected %i\n", n, req->pack->len);
+ goto out_err;
}
break;
}
return 0;
-out_err_free_pack:
- rad_packet_free(&req->pack);
out_err:
close(req->hnd.fd);
req->hnd.fd = -1;
@@ -124,7 +148,7 @@ int rad_req_add_int(struct rad_req_t *req, const char *name, int val)
struct rad_req_attr_t *ra;
struct rad_dict_attr_t *attr;
- if (req->pack.len + 2 + 4 >= REQ_LENGTH_MAX)
+ if (req->pack->len + 2 + 4 >= REQ_LENGTH_MAX)
return -1;
attr = rad_dict_find_attr(name);
@@ -138,18 +162,19 @@ int rad_req_add_int(struct rad_req_t *req, const char *name, int val)
ra->attr = attr;
ra->len = 4;
ra->val.integer = val;
- list_add_tail(&ra->entry, &req->pack.attrs);
- req->pack.len += 2 + 4;
+ ra->printable = 1;
+ list_add_tail(&ra->entry, &req->pack->attrs);
+ req->pack->len += 2 + 4;
return 0;
}
-int rad_req_add_str(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)
{
struct rad_req_attr_t *ra;
struct rad_dict_attr_t *attr;
- if (req->pack.len + 2 + len >= REQ_LENGTH_MAX)
+ if (req->pack->len + 2 + len >= REQ_LENGTH_MAX)
return -1;
attr = rad_dict_find_attr(name);
@@ -157,14 +182,24 @@ int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, in
return -1;
ra = malloc(sizeof(*ra));
- if (!ra)
+ if (!ra) {
+ log_error("radius: aout of memory\n");
return -1;
+ }
ra->attr = attr;
ra->len = len;
- ra->val.string = strdup(val);
- list_add_tail(&ra->entry, &req->pack.attrs);
- req->pack.len += 2 + len;
+ ra->val.string = malloc(len+1);
+ if (!ra->val.string) {
+ log_error("radius: out of memory\n");
+ free(ra);
+ return -1;
+ }
+ memcpy(ra->val.string, val, len);
+ ra->val.string[len] = 0;
+ ra->printable = printable;
+ list_add_tail(&ra->entry, &req->pack->attrs);
+ req->pack->len += 2 + len;
return 0;
}
@@ -175,14 +210,14 @@ int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, in
struct rad_dict_attr_t *attr;
struct rad_dict_value_t *v;
- if (req->pack.len + 2 + len >= REQ_LENGTH_MAX)
+ if (req->pack->len + 2 + len >= REQ_LENGTH_MAX)
return -1;
attr = rad_dict_find_attr(name);
if (!attr)
return -1;
- v = rad_dict_find_val(attr, val);
+ v = rad_dict_find_val_name(attr, val);
if (!v)
return -1;
@@ -193,39 +228,61 @@ int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, in
ra->attr = attr;
ra->len = len;
ra->val = v->val;
- list_add_tail(&ra->entry, &req->pack.attrs);
- req->pack.len += 2 + len;
+ ra->printable = 1;
+ list_add_tail(&ra->entry, &req->pack->attrs);
+ req->pack->len += 2 + len;
return 0;
}
+static void req_wakeup(struct rad_req_t *req)
+{
+ triton_context_wakeup(req->rpd->ppp->ctrl->ctx);
+ triton_timer_del(&req->timeout);
+ triton_md_unregister_handler(&req->hnd);
+ triton_context_unregister(&req->ctx);
+}
static int rad_req_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);
-
+ req_wakeup(req);
+
return 0;
}
static void rad_req_timeout(struct triton_timer_t *t)
{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+
+ req_wakeup(req);
}
int rad_req_wait(struct rad_req_t *req, int timeout)
{
- triton_md_register_handler(req->rpd->ppp->ctrl->ctx, &req->hnd);
+ triton_context_register(&req->ctx);
+ triton_md_register_handler(&req->ctx, &req->hnd);
if (triton_md_enable_handler(&req->hnd, MD_MODE_READ))
return -1;
req->timeout.period = timeout * 1000;
- if (triton_timer_add(req->rpd->ppp->ctrl->ctx, &req->timeout, 0))
+ if (triton_timer_add(&req->ctx, &req->timeout, 0))
return -1;
- triton_ctx_schedule(&req->hnd, &req->timeout);
-
- triton_timer_del(&req->timeout);
- triton_md_unregister_handler(&req->hnd);
+ triton_context_schedule(req->rpd->ppp->ctrl->ctx);
+ if (conf_verbose && req->reply) {
+ log_debug("recv ");
+ rad_packet_print(req->reply, log_debug);
+ }
return 0;
}
+void __init req_init(void)
+{
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (!urandom_fd) {
+ perror("radius:req: open /dev/urandom");
+ _exit(EXIT_FAILURE);
+ }
+}