From d860a4beaf5f99d5045d03b931b4829426a2f7b0 Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Tue, 14 Sep 2010 15:56:31 +0400 Subject: extra: implemented module 'pppd_compat' which starts pppd compatible scripts ip-up, ip-down, and newly introduced - ip-change, when radius CoA request received, also this module manages pppd compatible radattr.pppX files core: implemented module 'sigchld' which handles SIGCHLD signal, waits child processes to terminate and manages pid terminate handlers --- accel-pptpd/CMakeLists.txt | 6 +- accel-pptpd/accel-pptpd.conf | 8 + accel-pptpd/extra/CMakeLists.txt | 2 + accel-pptpd/extra/pppd_compat.c | 375 ++++++++++++++++++++++++++++++++++++++ accel-pptpd/include/events.h | 12 ++ accel-pptpd/include/radius.h | 1 + accel-pptpd/include/sigchld.h | 1 + accel-pptpd/include/utils.h | 1 + accel-pptpd/log.c | 2 - accel-pptpd/ppp/ipcp_opt_ipaddr.c | 3 + accel-pptpd/ppp/ppp.h | 3 + accel-pptpd/radius/acct.c | 2 +- accel-pptpd/radius/auth.c | 40 +++- accel-pptpd/radius/dict.c | 16 +- accel-pptpd/radius/dm_coa.c | 27 ++- accel-pptpd/radius/packet.c | 21 ++- accel-pptpd/radius/radius.c | 2 +- accel-pptpd/radius/radius.h | 81 -------- accel-pptpd/radius/radius_p.h | 90 +++++++++ accel-pptpd/radius/req.c | 2 +- accel-pptpd/sigchld.c | 134 ++++++++++++++ accel-pptpd/sigchld.h | 21 +++ accel-pptpd/triton/triton.c | 11 ++ accel-pptpd/triton/triton.h | 7 + accel-pptpd/utils.c | 10 + accel-pptpd/utils.h | 8 + 26 files changed, 775 insertions(+), 111 deletions(-) create mode 100644 accel-pptpd/extra/CMakeLists.txt create mode 100644 accel-pptpd/extra/pppd_compat.c create mode 120000 accel-pptpd/include/radius.h create mode 120000 accel-pptpd/include/sigchld.h create mode 120000 accel-pptpd/include/utils.h create mode 100644 accel-pptpd/radius/radius_p.h create mode 100644 accel-pptpd/sigchld.c create mode 100644 accel-pptpd/sigchld.h create mode 100644 accel-pptpd/utils.c create mode 100644 accel-pptpd/utils.h (limited to 'accel-pptpd') diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt index 1621e35..b27302c 100644 --- a/accel-pptpd/CMakeLists.txt +++ b/accel-pptpd/CMakeLists.txt @@ -10,6 +10,7 @@ ADD_SUBDIRECTORY(ctrl) ADD_SUBDIRECTORY(auth) ADD_SUBDIRECTORY(radius) ADD_SUBDIRECTORY(logs) +ADD_SUBDIRECTORY(extra) ADD_EXECUTABLE(pptpd ppp/ppp.c @@ -30,7 +31,10 @@ ADD_EXECUTABLE(pptpd iprange.c ippool.c - + + utils.c + sigchld.c + log.c main.c ) diff --git a/accel-pptpd/accel-pptpd.conf b/accel-pptpd/accel-pptpd.conf index eaa4daf..5ebff71 100644 --- a/accel-pptpd/accel-pptpd.conf +++ b/accel-pptpd/accel-pptpd.conf @@ -7,6 +7,7 @@ ./libauth_mschap_v1.so ./libauth_mschap_v2.so ./libradius.so +./libpppd_compat.so [core] log-error=/dev/stderr @@ -52,3 +53,10 @@ log-emerg=/dev/stderr [log-pgsql] conninfo=user=log log-table=log + +[pppd-compat] +ip-up=./ip-up.sh +ip-down=./ip-down.sh +ip-change=./ip-change.sh +radattr-prefix=./radattr +verbose=1 diff --git a/accel-pptpd/extra/CMakeLists.txt b/accel-pptpd/extra/CMakeLists.txt new file mode 100644 index 0000000..7b4b69b --- /dev/null +++ b/accel-pptpd/extra/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_LIBRARY(pppd_compat SHARED pppd_compat.c) + diff --git a/accel-pptpd/extra/pppd_compat.c b/accel-pptpd/extra/pppd_compat.c new file mode 100644 index 0000000..1cf6741 --- /dev/null +++ b/accel-pptpd/extra/pppd_compat.c @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "triton.h" + +#include "events.h" +#include "ppp.h" +#include "log.h" +#include "radius.h" +#include "utils.h" +#include "sigchld.h" + +static char *conf_ip_up = "/etc/ppp/ip-up"; +static char *conf_ip_down = "/etc/ppp/ip-down"; +static char *conf_ip_change = "/etc/ppp/ip-change"; +static char *conf_radattr_prefix = "/var/run/radattr."; +static int conf_verbose = 0; + +static void *pd_key; + +struct pppd_compat_pd_t +{ + struct ppp_pd_t pd; + struct ppp_t *ppp; + struct sigchld_handler_t ip_up_hnd; + struct sigchld_handler_t ip_change_hnd; + struct sigchld_handler_t ip_down_hnd; + int radattr_saved:1; + int started:1; + int ip_change_res; +}; + +static void remove_radattr(struct ppp_t *ppp); +static struct pppd_compat_pd_t *find_pd(struct ppp_t *ppp); +static void fill_argv(char **argv, struct ppp_t *ppp, char *path); +static void write_radattr(struct ppp_t *ppp, struct rad_packet_t *pack, int save_old); + +static void ip_up_handler(struct sigchld_handler_t *h, int status) +{ + struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_up_hnd); + if (conf_verbose) { + log_switch(NULL, pd->ppp); + log_ppp_debug("pppd_compat: ip-up finished (%i)\n", status); + } +} + +static void ip_down_handler(struct sigchld_handler_t *h, int status) +{ + struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_down_hnd); + if (conf_verbose) { + log_switch(NULL, pd->ppp); + log_ppp_debug("pppd_compat: ip-down finished (%i)\n", status); + } + sched_yield(); + triton_context_wakeup(pd->ppp->ctrl->ctx); +} + +static void ip_change_handler(struct sigchld_handler_t *h, int status) +{ + struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_change_hnd); + if (conf_verbose) { + log_switch(NULL, pd->ppp); + log_ppp_debug("pppd_compat: ip-change finished (%i)\n", status); + } + sched_yield(); + pd->ip_change_res = status; + triton_context_wakeup(pd->ppp->ctrl->ctx); +} + +static void ev_ppp_starting(struct ppp_t *ppp) +{ + struct pppd_compat_pd_t *pd = malloc(sizeof(*pd)); + + if (!pd) { + log_emerg("pppd_compat: out of memory\n"); + return; + } + + memset(pd, 0, sizeof(*pd)); + pd->pd.key = &pd_key; + pd->ppp = ppp; + pd->ip_up_hnd.handler = ip_up_handler; + pd->ip_down_hnd.handler = ip_down_handler; + pd->ip_change_hnd.handler = ip_change_handler; + list_add_tail(&pd->pd.entry, &ppp->pd_list); +} +static void ev_ppp_started(struct ppp_t *ppp) +{ + pid_t pid; + char *argv[8]; + char ipaddr[16]; + char peer_ipaddr[16]; + struct pppd_compat_pd_t *pd = find_pd(ppp); + + if (!pd) + return; + + argv[4] = ipaddr; + argv[5] = peer_ipaddr; + fill_argv(argv, ppp, conf_ip_up); + + sigchld_lock(); + pid = fork(); + if (pid > 0) { + pd->ip_up_hnd.pid = pid; + sigchld_register_handler(&pd->ip_up_hnd); + if (conf_verbose) + log_ppp_debug("pppd_compat: ip-up started (pid %i)\n", pid); + sigchld_unlock(); + } else if (pid == 0) { + execv(conf_ip_up, argv); + log_error("pppd_compat: exec '%s': %s\n", conf_ip_up, strerror(errno)); + _exit(EXIT_FAILURE); + } else + log_error("pppd_compat: fork: %s\n", strerror(errno)); + + pd->started = 1; +} + +static void ev_ppp_finished(struct ppp_t *ppp) +{ + pid_t pid; + char *argv[8]; + char ipaddr[16]; + char peer_ipaddr[16]; + struct pppd_compat_pd_t *pd = find_pd(ppp); + + if (!pd) + return; + + if (pd->started) { + pthread_mutex_lock(&pd->ip_up_hnd.lock); + if (pd->ip_up_hnd.pid) { + log_ppp_warn("pppd_compat: ip-up is not yet finished, terminating it ...\n"); + kill(pd->ip_up_hnd.pid, SIGTERM); + pthread_mutex_unlock(&pd->ip_up_hnd.lock); + } + } + + argv[4] = ipaddr; + argv[5] = peer_ipaddr; + fill_argv(argv, pd->ppp, conf_ip_down); + + sigchld_lock(); + pid = fork(); + if (pid > 0) { + pd->ip_down_hnd.pid = pid; + sigchld_register_handler(&pd->ip_down_hnd); + if (conf_verbose) + log_ppp_debug("pppd_compat: ip-down started (pid %i)\n", pid); + sigchld_unlock(); + triton_context_schedule(pd->ppp->ctrl->ctx); + } else if (pid == 0) { + execv(conf_ip_down, argv); + log_error("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno)); + _exit(EXIT_FAILURE); + } else + log_error("pppd_compat: fork: %s\n", strerror(errno)); + + if (pd->started) { + pthread_mutex_lock(&pd->ip_up_hnd.lock); + if (pd->ip_up_hnd.pid) { + log_ppp_warn("pppd_compat: ip-up is not yet finished, killing it ...\n"); + kill(pd->ip_up_hnd.pid, SIGKILL); + pthread_mutex_unlock(&pd->ip_up_hnd.lock); + sigchld_unregister_handler(&pd->ip_up_hnd); + } else + pthread_mutex_unlock(&pd->ip_up_hnd.lock); + } + + if (pd->radattr_saved) + remove_radattr(ppp); + + list_del(&pd->pd.entry); + free(pd); +} + +static void ev_radius_access_accept(struct ev_radius_t *ev) +{ + struct pppd_compat_pd_t *pd = find_pd(ev->ppp); + + write_radattr(ev->ppp, ev->reply, 0); + + pd->radattr_saved = 1; +} + +static void ev_radius_coa(struct ev_radius_t *ev) +{ + pid_t pid; + char *argv[8]; + char ipaddr[16]; + char peer_ipaddr[16]; + struct pppd_compat_pd_t *pd = find_pd(ev->ppp); + + if (!pd) + return; + + write_radattr(ev->ppp, ev->request, 1); + + argv[4] = ipaddr; + argv[5] = peer_ipaddr; + fill_argv(argv, pd->ppp, conf_ip_change); + + sigchld_lock(); + pid = fork(); + if (pid > 0) { + pd->ip_change_hnd.pid = pid; + sigchld_register_handler(&pd->ip_change_hnd); + sigchld_unlock(); + if (conf_verbose) + log_ppp_debug("pppd_compat: ip-change started (pid %i)\n", pid); + triton_context_schedule(pd->ppp->ctrl->ctx); + if (!ev->res) + ev->res = pd->ip_change_res; + } else if (pid == 0) { + execv(conf_ip_change, argv); + log_error("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno)); + _exit(EXIT_FAILURE); + } else + log_error("pppd_compat: fork: %s\n", strerror(errno)); +} + +static void remove_radattr(struct ppp_t *ppp) +{ + char *fname; + + fname = malloc(PATH_MAX); + if (!fname) { + log_emerg("pppd_compat: out of memory\n"); + return; + } + + sprintf(fname, "%s.%s", conf_radattr_prefix, ppp->ifname); + if (unlink(fname)) { + log_ppp_warn("pppd_compat: failed to remove '%s': %s\n", fname, strerror(errno)); + } + sprintf(fname, "%s_old.%s", conf_radattr_prefix, ppp->ifname); + unlink(fname); + + free(fname); +} + +static void write_radattr(struct ppp_t *ppp, struct rad_packet_t *pack, int save_old) +{ + struct rad_attr_t *attr; + struct rad_dict_value_t *val; + FILE *f; + char *fname1, *fname2; + int i; + + fname1 = malloc(PATH_MAX); + if (!fname1) { + log_emerg("pppd_compat: out of memory\n"); + return; + } + + if (save_old) { + fname2 = malloc(PATH_MAX); + if (!fname2) { + log_emerg("pppd_compat: out of memory\n"); + free(fname1); + return; + } + } + + sprintf(fname1, "%s.%s", conf_radattr_prefix, ppp->ifname); + if (save_old) { + sprintf(fname2, "%s_old.%s", conf_radattr_prefix, ppp->ifname); + if (rename(fname1, fname2)) { + log_ppp_warn("pppd_compat: rename: %s\n", strerror(errno)); + } + } + + f = fopen(fname1, "w"); + if (f) { + list_for_each_entry(attr, &pack->attrs, entry) { + fprintf(f, "%s ", attr->attr->name); + switch (attr->attr->type) { + case ATTR_TYPE_INTEGER: + val = rad_dict_find_val(attr->attr, attr->val); + if (val) + fprintf(f, "%s\n", val->name); + else + fprintf(f, "%i\n", attr->val.integer); + break; + case ATTR_TYPE_STRING: + fprintf(f, "%s\n", attr->val.string); + break; + case ATTR_TYPE_OCTETS: + for (i = 0; i < attr->len; i++) + fprintf(f, "%02X", attr->val.octets[i]); + fprintf(f, "\n"); + break; + case ATTR_TYPE_IPADDR: + fprintf(f, "%i.%i.%i.%i\n", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff); + break; + case ATTR_TYPE_DATE: + fprintf(f, "%lu\n", attr->val.date); + break; + } + } + fclose(f); + } else + log_ppp_warn("pppd_compat: failed to create '%s': %s\n", fname1, strerror(errno)); + + free(fname1); + if (save_old) + free(fname2); +} + +static struct pppd_compat_pd_t *find_pd(struct ppp_t *ppp) +{ + struct ppp_pd_t *pd; + struct pppd_compat_pd_t *cpd; + + list_for_each_entry(pd, &ppp->pd_list, entry) { + if (pd->key == &pd_key) { + cpd = container_of(pd, typeof(*cpd), pd); + return cpd; + } + } + + log_ppp_warn("pppd_compat: pd not found\n"); + return NULL; +} + +static void fill_argv(char **argv, struct ppp_t *ppp, char *path) +{ + argv[0] = path; + argv[1] = ppp->ifname; + argv[2] = "none"; + argv[3] = "0"; + u_inet_ntoa(ppp->ipaddr, argv[4]); + u_inet_ntoa(ppp->peer_ipaddr, argv[5]); + argv[6] = "none"; + argv[7] = NULL; +} + +static void __init init(void) +{ + char *opt; + + opt = conf_get_opt("pppd-compat", "ip-up"); + if (opt) + conf_ip_up = opt; + + opt = conf_get_opt("pppd-compat", "ip-down"); + if (opt) + conf_ip_down = opt; + + opt = conf_get_opt("pppd-compat", "ip-change"); + if (opt) + conf_ip_change = opt; + + opt = conf_get_opt("pppd-compat", "radattr-prefix"); + if (opt) + conf_radattr_prefix = opt; + + opt = conf_get_opt("pppd-compat", "verbose"); + if (opt && atoi(opt) > 0) + conf_verbose = 1; + + triton_event_register_handler(EV_PPP_STARTING, (triton_event_func)ev_ppp_starting); + triton_event_register_handler(EV_PPP_STARTED, (triton_event_func)ev_ppp_started); + triton_event_register_handler(EV_PPP_FINISHED, (triton_event_func)ev_ppp_finished); + triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); + triton_event_register_handler(EV_RADIUS_COA, (triton_event_func)ev_radius_coa); +} + diff --git a/accel-pptpd/include/events.h b/accel-pptpd/include/events.h index 332b4e3..0b37d0f 100644 --- a/accel-pptpd/include/events.h +++ b/accel-pptpd/include/events.h @@ -11,6 +11,18 @@ #define EV_CTRL_FINISHED 8 #define EV_IP_CHANGED 100 #define EV_SHAPE_CHANGED 101 +#define EV_RADIUS_ACCESS_ACCEPT 200 +#define EV_RADIUS_COA 201 + +struct ppp_t; +struct rad_packet_t; +struct ev_radius_t +{ + struct ppp_t *ppp; + struct rad_packet_t *request; + struct rad_packet_t *reply; + int res; +}; #endif diff --git a/accel-pptpd/include/radius.h b/accel-pptpd/include/radius.h new file mode 120000 index 0000000..e1465f1 --- /dev/null +++ b/accel-pptpd/include/radius.h @@ -0,0 +1 @@ +../radius/radius.h \ No newline at end of file diff --git a/accel-pptpd/include/sigchld.h b/accel-pptpd/include/sigchld.h new file mode 120000 index 0000000..166c77e --- /dev/null +++ b/accel-pptpd/include/sigchld.h @@ -0,0 +1 @@ +../sigchld.h \ No newline at end of file diff --git a/accel-pptpd/include/utils.h b/accel-pptpd/include/utils.h new file mode 120000 index 0000000..6cd5d4f --- /dev/null +++ b/accel-pptpd/include/utils.h @@ -0,0 +1 @@ +../utils.h \ No newline at end of file diff --git a/accel-pptpd/log.c b/accel-pptpd/log.c index 5012cba..fbd5067 100644 --- a/accel-pptpd/log.c +++ b/accel-pptpd/log.c @@ -300,8 +300,6 @@ static struct log_pd_t *find_pd(struct ppp_t *ppp) return lpd; } } - list_for_each_entry(pd, &ppp->pd_list, entry) - printf("%p %p\n", pd->key, &pd_key); log_emerg("log:BUG: pd not found\n"); abort(); } diff --git a/accel-pptpd/ppp/ipcp_opt_ipaddr.c b/accel-pptpd/ppp/ipcp_opt_ipaddr.c index b7f8636..1f9af3e 100644 --- a/accel-pptpd/ppp/ipcp_opt_ipaddr.c +++ b/accel-pptpd/ppp/ipcp_opt_ipaddr.c @@ -113,6 +113,9 @@ static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *o return IPCP_OPT_NAK; ack: + ipcp->ppp->ipaddr = ipaddr_opt->ip->addr; + ipcp->ppp->peer_ipaddr = ipaddr_opt->ip->peer_addr; + memset(&ifr, 0, sizeof(ifr)); memset(&addr, 0, sizeof(addr)); diff --git a/accel-pptpd/ppp/ppp.h b/accel-pptpd/ppp/ppp.h index 76b379f..641a74b 100644 --- a/accel-pptpd/ppp/ppp.h +++ b/accel-pptpd/ppp/ppp.h @@ -3,6 +3,7 @@ #include #include +#include #include "triton.h" #include "list.h" @@ -76,6 +77,8 @@ struct ppp_t char sessionid[PPP_SESSIONID_LEN+1]; time_t start_time; char *username; + in_addr_t ipaddr; + in_addr_t peer_ipaddr; struct ppp_ctrl_t *ctrl; diff --git a/accel-pptpd/radius/acct.c b/accel-pptpd/radius/acct.c index 785eab3..72e6df3 100644 --- a/accel-pptpd/radius/acct.c +++ b/accel-pptpd/radius/acct.c @@ -8,7 +8,7 @@ #include #include "log.h" -#include "radius.h" +#include "radius_p.h" static int req_set_RA(struct rad_req_t *req, const char *secret) { diff --git a/accel-pptpd/radius/auth.c b/accel-pptpd/radius/auth.c index 29c6efd..92406b3 100644 --- a/accel-pptpd/radius/auth.c +++ b/accel-pptpd/radius/auth.c @@ -2,10 +2,12 @@ #include #include +#include "triton.h" +#include "events.h" #include "log.h" #include "pwdb.h" -#include "radius.h" +#include "radius_p.h" static uint8_t* encrypt_password(const char *passwd, const char *secret, const uint8_t *RA, int *epasswd_len) @@ -97,7 +99,15 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) free(epasswd); - rad_auth_send(req); + r = rad_auth_send(req); + if (r == PWDB_SUCCESS) { + struct ev_radius_t ev = { + .ppp = rpd->ppp, + .request = req->pack, + .reply = req->reply, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } out: rad_req_free(req); @@ -134,6 +144,14 @@ int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list arg goto out; r = rad_auth_send(req); + if (r == PWDB_SUCCESS) { + struct ev_radius_t ev = { + .ppp = rpd->ppp, + .request = req->pack, + .reply = req->reply, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } out: rad_req_free(req); @@ -154,7 +172,7 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar const uint8_t *nt_response = va_arg(args, const uint8_t *); int flags = va_arg(args, int); - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + req = rad_req_alloc(rpd, CODE_ACCESS_ACCEPT, username); if (!req) return PWDB_DENIED; @@ -170,6 +188,14 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar goto out; r = rad_auth_send(req); + if (r == PWDB_SUCCESS) { + struct ev_radius_t ev = { + .ppp = rpd->ppp, + .request = req->pack, + .reply = req->reply, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } out: rad_req_free(req); @@ -217,6 +243,14 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar } else memcpy(authenticator, ra->val.octets + 3, 40); } + if (r == PWDB_SUCCESS) { + struct ev_radius_t ev = { + .ppp = rpd->ppp, + .request = req->pack, + .reply = req->reply, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } out: rad_req_free(req); diff --git a/accel-pptpd/radius/dict.c b/accel-pptpd/radius/dict.c index 6db7781..bd7a4ef 100644 --- a/accel-pptpd/radius/dict.c +++ b/accel-pptpd/radius/dict.c @@ -5,7 +5,7 @@ #include #include "list.h" -#include "radius.h" +#include "radius_p.h" #include "log.h" static struct rad_dict_t *dict; @@ -281,12 +281,12 @@ static struct rad_dict_attr_t *dict_find_attr(struct list_head *items, const cha return NULL; } -struct rad_dict_attr_t *rad_dict_find_attr(const char *name) +__export struct rad_dict_attr_t *rad_dict_find_attr(const char *name) { return dict_find_attr(&dict->items, name); } -struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int id) +__export struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int id) { struct rad_dict_attr_t *attr; struct list_head *items = vendor ? &vendor->items : &dict->items; @@ -298,7 +298,7 @@ struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, return NULL; } -struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, const char *name) +__export 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; @@ -309,7 +309,7 @@ struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, co return NULL; } -struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_value_t v) +__export 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; @@ -323,7 +323,7 @@ struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_val return NULL; } -struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name) +__export struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name) { struct rad_dict_vendor_t *vendor; @@ -335,7 +335,7 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name) return NULL; } -struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id) +__export struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id) { struct rad_dict_vendor_t *vendor; @@ -347,7 +347,7 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id) return NULL; } -struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name) +__export struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name) { return dict_find_attr(&vendor->items, name); } diff --git a/accel-pptpd/radius/dm_coa.c b/accel-pptpd/radius/dm_coa.c index 784ad82..f515f87 100644 --- a/accel-pptpd/radius/dm_coa.c +++ b/accel-pptpd/radius/dm_coa.c @@ -12,9 +12,10 @@ #include #include "triton.h" +#include "events.h" #include "log.h" -#include "radius.h" +#include "radius_p.h" #define PD_COA_PORT 3799 @@ -98,7 +99,8 @@ static int dm_coa_send_nak(int fd, struct rad_packet_t *req, struct sockaddr_in reply->id = req->id; - rad_packet_add_int(reply, "Error-Cause", err_code); + if (err_code) + rad_packet_add_int(reply, "Error-Cause", err_code); if (rad_packet_build(reply, RA)) { rad_packet_free(reply); @@ -137,14 +139,28 @@ static void disconnect_request(struct radius_pd_t *rpd) static void coa_request(struct radius_pd_t *rpd) { + struct ev_radius_t ev = { + .ppp = rpd->ppp, + .request = rpd->dm_coa_req, + }; + if (conf_verbose) { log_ppp_debug("recv "); rad_packet_print(rpd->dm_coa_req, log_ppp_debug); } -/// TODO: CoA handling + + triton_event_fire(EV_RADIUS_COA, &ev); + + if (ev.res) + dm_coa_send_nak(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr, 0); + else + dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr); rad_packet_free(rpd->dm_coa_req); + + pthread_mutex_lock(&rpd->lock); rpd->dm_coa_req = NULL; + pthread_mutex_unlock(&rpd->lock); } static int dm_coa_read(struct triton_md_handler_t *h) @@ -187,6 +203,11 @@ static int dm_coa_read(struct triton_md_handler_t *h) goto out_err; } + if (rpd->dm_coa_req) { + pthread_mutex_unlock(&rpd->lock); + goto out_err_no_reply; + } + rpd->dm_coa_req = pack; memcpy(&rpd->dm_coa_addr, &addr, sizeof(addr)); diff --git a/accel-pptpd/radius/packet.c b/accel-pptpd/radius/packet.c index 0aeafa5..9e7df01 100644 --- a/accel-pptpd/radius/packet.c +++ b/accel-pptpd/radius/packet.c @@ -8,7 +8,7 @@ #include "log.h" -#include "radius.h" +#include "radius_p.h" struct rad_packet_t *rad_packet_alloc(int code) { @@ -165,7 +165,8 @@ struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr) n -= 2 + len; } else log_ppp_warn("radius:packet: vendor %s not found\n", id); - } + } else + vendor = NULL; da = rad_dict_find_attr_id(vendor, id); if (da) { attr = malloc(sizeof(*attr)); @@ -257,28 +258,28 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, print("Access-Reject"); break; case CODE_ACCOUNTING_REQUEST: - printf("Accounting-Request"); + print("Accounting-Request"); break; case CODE_ACCOUNTING_RESPONSE: - printf("Accounting-Response"); + print("Accounting-Response"); break; case CODE_DISCONNECT_REQUEST: - printf("Disconnect-Request"); + print("Disconnect-Request"); break; case CODE_DISCONNECT_ACK: - printf("Disconnect-ACK"); + print("Disconnect-ACK"); break; case CODE_DISCONNECT_NAK: - printf("Disconnect-NAK"); + print("Disconnect-NAK"); break; case CODE_COA_REQUEST: - printf("CoA-Request"); + print("CoA-Request"); break; case CODE_COA_ACK: - printf("CoA-ACK"); + print("CoA-ACK"); break; case CODE_COA_NAK: - printf("CoA-NAK"); + print("CoA-NAK"); break; default: print("Unknown (%i)", pack->code); diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c index 133ed29..04e4133 100644 --- a/accel-pptpd/radius/radius.c +++ b/accel-pptpd/radius/radius.c @@ -11,7 +11,7 @@ #include "pwdb.h" #include "ipdb.h" -#include "radius.h" +#include "radius_p.h" #define CHAP_MD5 5 #define MSCHAP_V1 0x80 diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h index 8403b33..dca93d4 100644 --- a/accel-pptpd/radius/radius.h +++ b/accel-pptpd/radius/radius.h @@ -2,12 +2,6 @@ #define __RADIUS_H #include -#include -#include - -#include "triton.h" -#include "ppp.h" -#include "ipdb.h" #define REQ_LENGTH_MAX 4096 @@ -32,23 +26,6 @@ #define CODE_COA_ACK 44 #define CODE_COA_NAK 45 -struct radius_pd_t -{ - struct list_head entry; - struct ppp_pd_t pd; - struct ppp_t *ppp; - pthread_mutex_t lock; - - struct rad_req_t *acct_req; - struct triton_timer_t acct_interim_timer; - - struct rad_packet_t *dm_coa_req; - struct sockaddr_in dm_coa_addr; - - struct ipdb_item_t ipaddr; - int acct_interim_interval; -}; - typedef union { int integer; @@ -106,41 +83,7 @@ struct rad_packet_t struct list_head attrs; void *buf; }; -struct rad_req_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; - struct triton_timer_t timeout; - uint8_t RA[16]; - struct rad_packet_t *pack; - struct rad_packet_t *reply; - const char *server_name; - int server_port; - - struct radius_pd_t *rpd; -}; - -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_gw_ip_address; -extern char *conf_auth_server; -extern char *conf_auth_secret; -extern int conf_auth_server_port; -extern char *conf_acct_server; -extern char *conf_acct_secret; -extern int conf_acct_server_port; -extern char *conf_dm_coa_secret; - -int rad_check_nas_pack(struct rad_packet_t *pack); -struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr); -struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack); - -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_id(struct rad_dict_vendor_t *vendor, int type); struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *, const char *name); @@ -149,12 +92,6 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name); struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id); struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name); -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_attr_t *rad_packet_find_attr(struct rad_packet_t *pack, const char *name); int rad_packet_add_int(struct rad_packet_t *pack, const char *name, int val); int rad_packet_add_val(struct rad_packet_t *pack, const char *name, const char *val); @@ -165,23 +102,5 @@ int rad_packet_change_val(struct rad_packet_t *pack, const char *name, const cha int rad_packet_add_vendor_octets(struct rad_packet_t *pack, const char *vendor_name, const char *name, const uint8_t *val, int len); struct rad_attr_t *rad_packet_find_vendor_attr(struct rad_packet_t *pack, const char *vendor_name, const char *name); -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, struct sockaddr_in *addr); -void rad_packet_free(struct rad_packet_t *); -void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...)); -int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr); - -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/radius_p.h b/accel-pptpd/radius/radius_p.h new file mode 100644 index 0000000..3aa5406 --- /dev/null +++ b/accel-pptpd/radius/radius_p.h @@ -0,0 +1,90 @@ +#ifndef __RADIUS_P_H +#define __RADIUS_P_H + +#include +#include + +#include "triton.h" +#include "radius.h" +#include "ppp.h" +#include "ipdb.h" + +struct radius_pd_t +{ + struct list_head entry; + struct ppp_pd_t pd; + struct ppp_t *ppp; + pthread_mutex_t lock; + + struct rad_req_t *acct_req; + struct triton_timer_t acct_interim_timer; + + struct rad_packet_t *dm_coa_req; + struct sockaddr_in dm_coa_addr; + + struct ipdb_item_t ipaddr; + int acct_interim_interval; +}; + +struct rad_req_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + struct triton_timer_t timeout; + uint8_t RA[16]; + struct rad_packet_t *pack; + struct rad_packet_t *reply; + const char *server_name; + int server_port; + + struct radius_pd_t *rpd; +}; + +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_gw_ip_address; +extern char *conf_auth_server; +extern char *conf_auth_secret; +extern int conf_auth_server_port; +extern char *conf_acct_server; +extern char *conf_acct_secret; +extern int conf_acct_server_port; +extern char *conf_dm_coa_secret; + +int rad_check_nas_pack(struct rad_packet_t *pack); +struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr); +struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack); + +int rad_dict_load(const char *fname); +void rad_dict_free(struct rad_dict_t *dict); + +struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username); +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 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); + +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, struct sockaddr_in *addr); +void rad_packet_free(struct rad_packet_t *); +void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...)); +int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr); + + +#endif + diff --git a/accel-pptpd/radius/req.c b/accel-pptpd/radius/req.c index e6f29c5..a9192bb 100644 --- a/accel-pptpd/radius/req.c +++ b/accel-pptpd/radius/req.c @@ -9,7 +9,7 @@ #include #include "log.h" -#include "radius.h" +#include "radius_p.h" static int urandom_fd; diff --git a/accel-pptpd/sigchld.c b/accel-pptpd/sigchld.c new file mode 100644 index 0000000..478f44c --- /dev/null +++ b/accel-pptpd/sigchld.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include + +#include "triton.h" +#include "spinlock.h" +#include "log.h" + +#include "sigchld.h" + +static LIST_HEAD(handlers); +static int refs; +static int sleeping = 1; +static pthread_mutex_t handlers_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t refs_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct triton_context_t sigchld_ctx; + +static void sigchld_handler(void *arg) +{ + struct sigchld_handler_t *h, *h0; + pid_t pid; + int status; + + while (1) { + pid = waitpid(0, &status, WNOHANG); + pthread_mutex_lock(&handlers_lock); + if (pid == 0 || (pid == -1 && errno == ECHILD)) { + sleeping = 1; + pthread_mutex_unlock(&handlers_lock); + return; + } else if (pid < 0) { + pthread_mutex_unlock(&handlers_lock); + log_error("sigchld: waitpid: %s\n", strerror(errno)); + return; + } + h0 = NULL; + list_for_each_entry(h, &handlers, entry) { + if (h->pid == pid) { + h0 = h; + pthread_mutex_lock(&h0->lock); + break; + } + } + pthread_mutex_unlock(&handlers_lock); + if (h0) { + h0->handler(h0, WEXITSTATUS(status)); + list_del(&h0->entry); + h0->pid = 0; + pthread_mutex_unlock(&h0->lock); + } + } +} + +void __export sigchld_register_handler(struct sigchld_handler_t *h) +{ + pthread_mutex_init(&h->lock, NULL); + + pthread_mutex_lock(&handlers_lock); + list_add_tail(&h->entry, &handlers); + pthread_mutex_unlock(&handlers_lock); +} + +void __export sigchld_unregister_handler(struct sigchld_handler_t *h) +{ + pthread_mutex_lock(&handlers_lock); + pthread_mutex_lock(&h->lock); + if (h->pid) { + list_del(&h->entry); + h->pid = 0; + } + pthread_mutex_unlock(&h->lock); + pthread_mutex_unlock(&handlers_lock); +} + +void __export sigchld_lock() +{ + sigset_t set; + + pthread_mutex_lock(&refs_lock); + if (refs == 0) { + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, NULL); + } + ++refs; + pthread_mutex_unlock(&refs_lock); +} + +void __export sigchld_unlock() +{ + sigset_t set; + + pthread_mutex_lock(&refs_lock); + if (refs == 1) { + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + --refs; + pthread_mutex_unlock(&refs_lock); + +} + +static void sigchld(int num) +{ + int s; + + pthread_mutex_lock(&handlers_lock); + s = sleeping; + sleeping = 0; + pthread_mutex_unlock(&handlers_lock); + + if (s) + triton_context_call(&sigchld_ctx, sigchld_handler, NULL); +} + +static void __init init(void) +{ + struct sigaction sa_sigchld = { + .sa_handler = sigchld, + .sa_flags = SA_NOCLDSTOP, + }; + + if (sigaction(SIGCHLD, &sa_sigchld, NULL)) { + fprintf(stderr, "sigchld: sigaction: %s\n", strerror(errno)); + return; + } + + triton_context_register(&sigchld_ctx, NULL); +} diff --git a/accel-pptpd/sigchld.h b/accel-pptpd/sigchld.h new file mode 100644 index 0000000..27d1adf --- /dev/null +++ b/accel-pptpd/sigchld.h @@ -0,0 +1,21 @@ +#ifndef __SIGCHLD_H +#define __SIGCHLD_H + +#include +#include "list.h" + +struct sigchld_handler_t +{ + struct list_head entry; + pthread_mutex_t lock; + pid_t pid; + void (*handler)(struct sigchld_handler_t *, int status); +}; + +void sigchld_register_handler(struct sigchld_handler_t *); +void sigchld_unregister_handler(struct sigchld_handler_t *); +void sigchld_lock(); +void sigchld_unlock(); + +#endif + diff --git a/accel-pptpd/triton/triton.c b/accel-pptpd/triton/triton.c index b0aedbc..9b9fd75 100644 --- a/accel-pptpd/triton/triton.c +++ b/accel-pptpd/triton/triton.c @@ -35,6 +35,17 @@ static void* triton_thread(struct _triton_thread_t *thread) sigset_t set; int sig; + sigfillset(&set); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + sigdelset(&set, SIGUSR1); + sigdelset(&set, SIGQUIT); + sigdelset(&set, SIGSEGV); + sigdelset(&set, SIGFPE); + sigdelset(&set, SIGILL); + sigdelset(&set, SIGBUS); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); + sigemptyset(&set); sigaddset(&set, SIGUSR1); sigaddset(&set, SIGQUIT); diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h index b1df497..8510a51 100644 --- a/accel-pptpd/triton/triton.h +++ b/accel-pptpd/triton/triton.h @@ -29,6 +29,13 @@ struct triton_timer_t void (*expire)(struct triton_timer_t *); }; +struct triton_sigchld_handler_t +{ + void *tpd; + int pid; + void (*handler)(struct triton_sigchld_handler_t *h, int status); +}; + struct conf_option_t { struct list_head entry; diff --git a/accel-pptpd/utils.c b/accel-pptpd/utils.c new file mode 100644 index 0000000..fd59b00 --- /dev/null +++ b/accel-pptpd/utils.c @@ -0,0 +1,10 @@ +#include + +#include "triton.h" +#include "utils.h" + + +void __export u_inet_ntoa(in_addr_t addr, char *str) +{ + sprintf(str, "%i.%i.%i.%i", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff); +} diff --git a/accel-pptpd/utils.h b/accel-pptpd/utils.h new file mode 100644 index 0000000..27d4d05 --- /dev/null +++ b/accel-pptpd/utils.h @@ -0,0 +1,8 @@ +#ifndef __UTILS_H +#define __UTILS_H + +#include + +void u_inet_ntoa(in_addr_t, char *str); + +#endif -- cgit v1.2.3