From 8365449e9b304a94cdcf713f87325e8826c784da Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 8 Dec 2014 10:48:25 +0100 Subject: [PATCH 01/14] deprecated ipv6_netmask --- src/common.h | 16 ++++++++++++++++ src/config.c | 8 +++----- src/ip-lease.c | 10 ++++++---- src/main-auth.c | 1 - src/sup-config/file.c | 4 +--- src/vpn.h | 2 -- src/worker-auth.c | 6 ------ src/worker-misc.c | 1 - 8 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/common.h b/src/common.h index 856fd824..f9c71f08 100644 --- a/src/common.h +++ b/src/common.h @@ -42,6 +42,22 @@ ssize_t force_read_timeout(int sockfd, void *buf, size_t len, unsigned sec); ssize_t recv_timeout(int sockfd, void *buf, size_t len, unsigned sec); int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n); char* ipv6_prefix_to_mask(void *pool, unsigned prefix); +inline static int valid_ipv6_prefix(unsigned prefix) +{ + switch (prefix) { + case 16: + case 32: + case 48: + case 64: + case 80: + case 96: + case 112: + case 128: + return 1; + default: + return 0; + } +} typedef size_t (*pack_func)(const void*, uint8_t *); typedef size_t (*pack_size_func)(const void*); diff --git a/src/config.c b/src/config.c index 0b7e029b..8cbfbe44 100644 --- a/src/config.c +++ b/src/config.c @@ -561,10 +561,9 @@ unsigned force_cert_auth; READ_NUMERIC("ipv6-prefix", prefix); if (prefix > 0) { - config->network.ipv6_netmask = ipv6_prefix_to_mask(config, prefix); config->network.ipv6_prefix = prefix; - if (config->network.ipv6_netmask == NULL) { + if (valid_ipv6_prefix(prefix) == 0) { fprintf(stderr, "invalid IPv6 prefix: %u\n", prefix); exit(1); } @@ -642,8 +641,8 @@ static void check_cfg(struct cfg_st *config) exit(1); } - if (config->network.ipv6 != NULL && config->network.ipv6_netmask == NULL) { - fprintf(stderr, "No mask found for IPv6 network.\n"); + if (config->network.ipv6 != NULL && config->network.ipv6_prefix == 0) { + fprintf(stderr, "No prefix found for IPv6 network.\n"); exit(1); } @@ -775,7 +774,6 @@ unsigned i; DEL(config->network.ipv4); DEL(config->network.ipv4_netmask); DEL(config->network.ipv6); - DEL(config->network.ipv6_netmask); for (i=0;inetwork.routes_size;i++) DEL(config->network.routes[i]); DEL(config->network.routes); diff --git a/src/ip-lease.c b/src/ip-lease.c index 8f95b2c8..24a09f7f 100644 --- a/src/ip-lease.c +++ b/src/ip-lease.c @@ -273,15 +273,16 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc) struct sockaddr_storage tmp, mask, network, rnd; unsigned i, max_loops = MAX_IP_TRIES; int ret; - const char* c_network, *c_netmask; + const char* c_network; + char *c_netmask = NULL; char buf[64]; - if (proc->config.ipv6_network && proc->config.ipv6_netmask) { + if (proc->config.ipv6_network && proc->config.ipv6_prefix) { c_network = proc->config.ipv6_network; - c_netmask = proc->config.ipv6_netmask; + c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix); } else { c_network = s->config->network.ipv6; - c_netmask = s->config->network.ipv6_netmask; + c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix); } if (c_network && c_netmask) { @@ -392,6 +393,7 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc) return 0; fail: talloc_free(proc->ipv6); + talloc_free(c_netmask); proc->ipv6 = NULL; return ret; diff --git a/src/main-auth.c b/src/main-auth.c index e5dd214f..f08f1eed 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -85,7 +85,6 @@ int send_cookie_auth_reply(main_server_st* s, struct proc_st* proc, } msg.ipv4_netmask = proc->config.ipv4_netmask; - msg.ipv6_netmask = proc->config.ipv6_netmask; msg.ipv4_network = proc->config.ipv4_network; msg.ipv6_network = proc->config.ipv6_network; diff --git a/src/sup-config/file.c b/src/sup-config/file.c index c91138f5..e6a13757 100644 --- a/src/sup-config/file.c +++ b/src/sup-config/file.c @@ -199,10 +199,9 @@ struct group_cfg_st *sconfig = &proc->config; READ_RAW_NUMERIC("ipv6-prefix", prefix); if (prefix > 0) { - sconfig->ipv6_netmask = ipv6_prefix_to_mask(proc, prefix); sconfig->ipv6_prefix = prefix; - if (sconfig->ipv6_netmask == NULL) { + if (valid_ipv6_prefix(prefix) == 0) { syslog(LOG_ERR, "unknown ipv6-prefix '%u' in %s", prefix, file); } } @@ -307,7 +306,6 @@ unsigned i; talloc_free(config->ipv4_network); talloc_free(config->ipv6_network); talloc_free(config->ipv4_netmask); - talloc_free(config->ipv6_netmask); safe_memset(config, 0, sizeof(*config)); } diff --git a/src/vpn.h b/src/vpn.h index 03721e12..0809ffc4 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -145,7 +145,6 @@ struct group_cfg_st { char *ipv6_network; unsigned ipv6_prefix; char *ipv4_netmask; - char *ipv6_netmask; char *cgroup; @@ -166,7 +165,6 @@ struct vpn_st { char *ipv4_network; char *ipv4; char *ipv4_local; /* local IPv4 address */ - char *ipv6_netmask; char *ipv6_network; unsigned ipv6_prefix; diff --git a/src/worker-auth.c b/src/worker-auth.c index 4351e3d1..d87aa977 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -548,12 +548,6 @@ static int recv_cookie_auth_reply(worker_st * ws) talloc_strdup(ws, msg->ipv4_netmask); } - if (msg->ipv6_netmask != NULL) { - talloc_free(ws->config->network.ipv6_netmask); - ws->config->network.ipv6_netmask = - talloc_strdup(ws, msg->ipv6_netmask); - } - if (msg->ipv4_network != NULL) { talloc_free(ws->config->network.ipv4_network); ws->config->network.ipv4_network = diff --git a/src/worker-misc.c b/src/worker-misc.c index d520a28c..73085ac9 100644 --- a/src/worker-misc.c +++ b/src/worker-misc.c @@ -227,7 +227,6 @@ int complete_vpn_info(worker_st * ws, struct vpn_st *vinfo) vinfo->ipv6_network = ws->config->network.ipv6_network; vinfo->ipv4_netmask = ws->config->network.ipv4_netmask; - vinfo->ipv6_netmask = ws->config->network.ipv6_netmask; vinfo->ipv6_prefix = ws->config->network.ipv6_prefix; if (ws->config->network.mtu != 0) { From baa3e4701e3c5787079f0f335a48fe49cde2ebf4 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 8 Dec 2014 12:56:16 +0100 Subject: [PATCH 02/14] Supplementary configuration is now read by the security module. That allows sec-mod to handle both authentication and accounting. That deprecates the session-control configuration option. --- src/Makefile.am | 2 +- src/common.h | 3 +- src/config.c | 5 +- src/ip-lease.c | 61 ++++++- src/ipc.proto | 20 +++ src/main-auth.c | 26 ++- src/main-misc.c | 106 +++++++++--- src/main.c | 3 - src/main.h | 1 - src/ocserv-args.def | 6 - src/sec-mod-auth.c | 24 +-- ...main-sup-config.c => sec-mod-sup-config.c} | 6 +- ...main-sup-config.h => sec-mod-sup-config.h} | 8 +- src/sec-mod.c | 24 ++- src/sec-mod.h | 5 +- src/sup-config/file.c | 151 +++++++----------- src/sup-config/file.h | 2 +- src/vpn.h | 6 +- 18 files changed, 289 insertions(+), 170 deletions(-) rename src/{main-sup-config.c => sec-mod-sup-config.c} (89%) rename src/{main-sup-config.h => sec-mod-sup-config.h} (83%) diff --git a/src/Makefile.am b/src/Makefile.am index 1ae8e6f8..080baeac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,7 +73,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \ script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) \ icmp-ping.c icmp-ping.h \ - main-sup-config.c main-sup-config.h \ + sec-mod-sup-config.c sec-mod-sup-config.h \ sup-config/file.c sup-config/file.h \ worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \ vasprintf.c vasprintf.h \ diff --git a/src/common.h b/src/common.h index f9c71f08..d941a4eb 100644 --- a/src/common.h +++ b/src/common.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Nikos Mavrogiannopoulos + * Copyright (C) 2013, 2014 Nikos Mavrogiannopoulos + * Copyright (C) 2014 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * diff --git a/src/config.c b/src/config.c index 8cbfbe44..fd02f718 100644 --- a/src/config.c +++ b/src/config.c @@ -452,8 +452,9 @@ unsigned force_cert_auth; if (config->occtl_socket_file == NULL) config->occtl_socket_file = talloc_strdup(config, OCCTL_UNIX_SOCKET); - if (config->auth_types & AUTH_TYPE_USERNAME_PASS) { - READ_TF("session-control", config->session_control, 0); + val = get_option("session-control", NULL); + if (val != NULL) { + fprintf(stderr, "The option 'session-control' is deprecated\n"); } READ_STRING("banner", config->banner); diff --git a/src/ip-lease.c b/src/ip-lease.c index 24a09f7f..723de428 100644 --- a/src/ip-lease.c +++ b/src/ip-lease.c @@ -141,7 +141,34 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc) int ret; const char* c_network, *c_netmask; char buf[64]; + + if (proc->config.explicit_ipv4) { + /* if an explicit IP is given for that client, then + * don't do any IP accounting */ + ret = + inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&network)); + + if (ret != 1) { + mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4); + return -1; + } + + proc->ipv4 = talloc_zero(proc, struct ip_lease_st); + if (proc->ipv4 == NULL) + return ERR_MEM; + + ((struct sockaddr_in*)&network)->sin_family = AF_INET; + ((struct sockaddr_in*)&network)->sin_port = 0; + memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); + proc->ipv4->lip_len = sizeof(struct sockaddr_in); + memcpy(&proc->ipv4->rip, &network, sizeof(struct sockaddr_in)); + proc->ipv4->rip_len = sizeof(struct sockaddr_in); + + return 0; + } + + /* Our IP accounting */ if (proc->config.ipv4_network && proc->config.ipv4_netmask) { c_network = proc->config.ipv4_network; c_netmask = proc->config.ipv4_netmask; @@ -277,6 +304,32 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc) char *c_netmask = NULL; char buf[64]; + if (proc->config.explicit_ipv6) { + /* if an explicit IP is given for that client, then + * don't do any IP accounting */ + ret = + inet_pton(AF_INET6, proc->config.explicit_ipv6, SA_IN6_P(&network)); + + if (ret != 1) { + mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv6); + return -1; + } + + proc->ipv6 = talloc_zero(proc, struct ip_lease_st); + if (proc->ipv6 == NULL) + return ERR_MEM; + + ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)&network)->sin6_port = 0; + memcpy(&proc->ipv6->lip, &network, sizeof(struct sockaddr_in6)); + proc->ipv6->lip_len = sizeof(struct sockaddr_in6); + + memcpy(&proc->ipv6->rip, &network, sizeof(struct sockaddr_in6)); + proc->ipv6->rip_len = sizeof(struct sockaddr_in6); + + return 0; + } + if (proc->config.ipv6_network && proc->config.ipv6_prefix) { c_network = proc->config.ipv6_network; c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix); @@ -401,7 +454,7 @@ fail: } static -int unref_ip_lease(struct ip_lease_st * lease) +int unref_ip_lease(struct ip_lease_st *lease) { if (lease->db) { htable_del(&lease->db->ht, rehash(lease, NULL), lease); @@ -409,7 +462,7 @@ int unref_ip_lease(struct ip_lease_st * lease) return 0; } -int get_ip_leases(main_server_st* s, struct proc_st* proc) +int get_ip_leases(main_server_st *s, struct proc_st *proc) { int ret; char buf[128]; @@ -419,7 +472,7 @@ char buf[128]; if (ret < 0) return ret; - if (proc->ipv4) { + if (proc->ipv4 && proc->ipv4->db) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table."); return -1; @@ -433,7 +486,7 @@ char buf[128]; if (ret < 0) return ret; - if (proc->ipv6) { + if (proc->ipv6 && proc->ipv4->db) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table."); return -1; diff --git a/src/ipc.proto b/src/ipc.proto index 9365f6fd..ee805936 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -192,4 +192,24 @@ message sec_auth_session_msg message sec_auth_session_reply_msg { required AUTH_REP reply = 1; + + /* sup - config */ + optional bool no_udp = 10; + optional bool deny_roaming = 11; + optional bool require_cert = 12; + repeated string routes = 13; + repeated string iroutes = 14; + repeated string dns = 15; + repeated string nbns = 16; + optional string ipv4_net = 17; + optional string ipv4_netmask = 18; + optional string ipv6_net = 19; + optional uint32 ipv6_prefix = 20; + optional string cgroup = 21; + optional string xml_config_file = 22; + optional uint32 rx_per_sec = 23; + optional uint32 tx_per_sec = 24; + optional uint32 net_priority = 25; + optional string explicit_ipv4 = 26; + optional string explicit_ipv6 = 27; } diff --git a/src/main-auth.c b/src/main-auth.c index f08f1eed..5520101a 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "str.h" #include @@ -209,17 +208,16 @@ struct cookie_entry_st *old; memset(&proc->config, 0, sizeof(proc->config)); apply_default_sup_config(s->config, proc); - if (s->config_module) { - ret = s->config_module->get_sup_config(s->config, proc); - if (ret < 0) { - mslog(s, proc, LOG_ERR, - "error reading additional configuration"); - return ERR_READ_CONFIG; - } + /* loads sup config */ + ret = session_open(s, proc); + if (ret < 0) { + mslog(s, proc, LOG_INFO, "could not open session"); + return -1; + } - if (proc->config.cgroup != NULL) { - put_into_cgroup(s, proc->config.cgroup, proc->pid); - } + /* Put into right cgroup */ + if (proc->config.cgroup != NULL) { + put_into_cgroup(s, proc->config.cgroup, proc->pid); } /* check whether the cookie IP matches */ @@ -283,12 +281,6 @@ struct cookie_entry_st *old; memcpy(proc->ipv4_seed, &cmsg->ipv4_seed, sizeof(proc->ipv4_seed)); - ret = session_open(s, proc); - if (ret < 0) { - mslog(s, proc, LOG_INFO, "could not open session"); - return -1; - } - /* add the links to proc hash */ proc_table_add(s, proc); diff --git a/src/main-misc.c b/src/main-misc.c index 6f41b40e..b5f9ac8c 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -46,7 +46,6 @@ #include #include #include -#include #ifdef HAVE_MALLOC_TRIM # include @@ -168,10 +167,8 @@ int session_cmd(main_server_st * s, struct proc_st *proc, unsigned open) int sd, ret, e; SecAuthSessionMsg ireq = SEC_AUTH_SESSION_MSG__INIT; SecAuthSessionReplyMsg *msg = NULL; - unsigned type; - - if (s->config->session_control == 0) - return 0; + unsigned type, i; + PROTOBUF_ALLOCATOR(pa, proc); if (open) type = SM_CMD_AUTH_SESSION_OPEN; @@ -227,6 +224,86 @@ int session_cmd(main_server_st * s, struct proc_st *proc, unsigned open) mslog(s, proc, LOG_INFO, "could not initiate session for '%s'", proc->username); return -1; } + + /* fill in group_cfg_st */ + if (msg->has_no_udp) + proc->config.no_udp = msg->no_udp; + + if (msg->has_deny_roaming) + proc->config.deny_roaming = msg->deny_roaming; + + if (msg->has_require_cert) + proc->config.require_cert = msg->require_cert; + + if (msg->has_ipv6_prefix) + proc->config.ipv6_prefix = msg->ipv6_prefix; + + if (msg->rx_per_sec) + proc->config.rx_per_sec = msg->rx_per_sec; + if (msg->tx_per_sec) + proc->config.tx_per_sec = msg->tx_per_sec; + + if (msg->net_priority) + proc->config.net_priority = msg->net_priority; + + if (msg->ipv4_net) { + proc->config.ipv4_network = talloc_strdup(proc, msg->ipv4_net); + } + if (msg->ipv4_netmask) { + proc->config.ipv4_netmask = talloc_strdup(proc, msg->ipv4_netmask); + } + if (msg->ipv6_net) { + proc->config.ipv6_network = talloc_strdup(proc, msg->ipv6_net); + } + + if (msg->cgroup) { + proc->config.cgroup = talloc_strdup(proc, msg->cgroup); + } + + if (msg->xml_config_file) { + proc->config.xml_config_file = talloc_strdup(proc, msg->xml_config_file); + } + + if (msg->explicit_ipv4) { + proc->config.explicit_ipv4 = talloc_strdup(proc, msg->explicit_ipv4); + } + + if (msg->explicit_ipv6) { + proc->config.explicit_ipv6 = talloc_strdup(proc, msg->explicit_ipv6); + } + + if (msg->n_routes > 0) { + proc->config.routes = talloc_size(proc, sizeof(char*)*msg->n_routes); + for (i=0;in_routes;i++) { + proc->config.routes[i] = talloc_strdup(proc, msg->routes[i]); + } + proc->config.routes_size = msg->n_routes; + } + + if (msg->n_iroutes > 0) { + proc->config.iroutes = talloc_size(proc, sizeof(char*)*msg->n_iroutes); + for (i=0;in_iroutes;i++) { + proc->config.iroutes[i] = talloc_strdup(proc, msg->iroutes[i]); + } + proc->config.iroutes_size = msg->n_iroutes; + } + + if (msg->n_dns > 0) { + proc->config.dns = talloc_size(proc, sizeof(char*)*msg->n_dns); + for (i=0;in_dns;i++) { + proc->config.dns[i] = talloc_strdup(proc, msg->dns[i]); + } + proc->config.dns_size = msg->n_dns; + } + + if (msg->n_nbns > 0) { + proc->config.nbns = talloc_size(proc, sizeof(char*)*msg->n_nbns); + for (i=0;in_nbns;i++) { + proc->config.nbns[i] = talloc_strdup(proc, msg->nbns[i]); + } + proc->config.nbns_size = msg->n_nbns; + } + sec_auth_session_reply_msg__free_unpacked(msg, &pa); } else { close(sd); } @@ -262,7 +339,7 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k) } /* close any pending sessions */ - if (s->config->session_control != 0 && proc->active_sid) { + if (proc->active_sid) { session_close(s, proc); } @@ -273,26 +350,17 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k) proc->pid = -1; remove_iroutes(s, proc); - if (s->config_module) { - s->config_module->clear_sup_config(&proc->config); - } if (proc->ipv4 || proc->ipv6) remove_ip_leases(s, proc); /* expire any available cookies */ if (proc->cookie_ptr) { - unsigned timeout = s->config->cookie_timeout; - proc->cookie_ptr->proc = NULL; - if (s->config->session_control != 0) { - /* if we use session control and we closed the session we - * need to invalidate the cookie, so that a new session is - * used on the next connection */ - proc->cookie_ptr->expiration = 1; - } else { - proc->cookie_ptr->expiration = time(0) + timeout; - } + /* if we use session control and we closed the session we + * need to invalidate the cookie, so that a new session is + * used on the next connection */ + proc->cookie_ptr->expiration = 1; } close_tun(s, proc); diff --git a/src/main.c b/src/main.c index 6afc9b20..893c5e21 100644 --- a/src/main.c +++ b/src/main.c @@ -51,7 +51,6 @@ # include #endif #include -#include #include #include #include @@ -987,8 +986,6 @@ int main(int argc, char** argv) run_sec_mod(s); - sup_config_init(s); - ret = ctl_handler_init(s); if (ret < 0) { fprintf(stderr, "Cannot create command handler\n"); diff --git a/src/main.h b/src/main.h index 1a78c11d..107315b2 100644 --- a/src/main.h +++ b/src/main.h @@ -213,7 +213,6 @@ typedef struct main_server_st { time_t start_time; void * auth_extra; - struct config_mod_st *config_module; #ifdef HAVE_DBUS void * ctl_ctx; diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 146e59a9..c4b2a727 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -96,12 +96,6 @@ An example configuration file follows. # to generate password entries. #auth = "plain[/etc/ocserv/ocpasswd]" -# Whether to enable the authentication method's session control (i.e., PAM). -# That requires more resources on the server, and makes cookies one-time-use; -# thus don't enable unless you need it. That should be used when you have an -# accounting system in place with the PAM modules. -#session-control = true - # Whether to enable seccomp worker isolation. That restricts the number of # system calls allowed to a worker process, in order to reduce damage from a # bug in the worker process. It is available on Linux systems at a performance cost. diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index a9d8d2ff..8c13ca01 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -49,6 +49,7 @@ #include #include #include +#include static const struct auth_mod_st *module = NULL; @@ -106,6 +107,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) { SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT; int ret; + void *pool = NULL; if (r == AUTH__REP__OK) { /* fill message */ @@ -135,6 +137,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) (pack_size_func) sec_auth_reply_msg__get_packed_size, (pack_func) sec_auth_reply_msg__pack); + talloc_free(pool); } else { msg.reply = AUTH__REP__FAILED; @@ -279,9 +282,6 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) } ret = 0; - if (module != NULL && (sec->config->session_control == 0 || module->open_session == NULL)) { - del_client_entry(sec, e); - } /* else do nothing, and wait for session close/open messages */ } else { e->status = PS_AUTH_FAILED; add_ip_to_ban_list(sec, e->ip, time(0) + sec->config->min_reauth_time); @@ -305,19 +305,12 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) /* opens or closes a session. */ -int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd) +int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, + unsigned cmd, client_entry_st **r_entry) { client_entry_st *e; int ret; - if (module == NULL || module->open_session == NULL) - return 0; - - if (sec->config->session_control == 0) { - seclog(sec, LOG_ERR, "auth session open/close but session control is disabled!"); - return 0; - } - if (req->sid.len != SID_SIZE) { seclog(sec, LOG_ERR, "auth session open/close but with illegal sid size (%d)!", (int)req->sid.len); @@ -331,6 +324,13 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, } if (cmd == SM_CMD_AUTH_SESSION_OPEN) { + if (r_entry) { + *r_entry = e; + } + + if (module == NULL || module->open_session == NULL) + return 0; + ret = module->open_session(e->auth_ctx); if (ret < 0) { e->status = PS_AUTH_FAILED; diff --git a/src/main-sup-config.c b/src/sec-mod-sup-config.c similarity index 89% rename from src/main-sup-config.c rename to src/sec-mod-sup-config.c index edc37351..29ce7752 100644 --- a/src/main-sup-config.c +++ b/src/sec-mod-sup-config.c @@ -27,11 +27,11 @@ #include #include #include -#include +#include #include -void sup_config_init(main_server_st *s) +void sup_config_init(sec_mod_st *sec) { - s->config_module = &file_sup_config; + sec->config_module = &file_sup_config; } diff --git a/src/main-sup-config.h b/src/sec-mod-sup-config.h similarity index 83% rename from src/main-sup-config.h rename to src/sec-mod-sup-config.h index 17ea7d45..ef11b041 100644 --- a/src/main-sup-config.h +++ b/src/sec-mod-sup-config.h @@ -21,16 +21,16 @@ #ifndef SUP_CONFIG_H # define SUP_CONFIG_H -#include +#include /* The get_sup_config() should read any additional configuration for * proc->username/proc->groupname and save it in proc->config. */ struct config_mod_st { - int (*get_sup_config)(struct cfg_st *global_config, struct proc_st *proc); - void (*clear_sup_config)(struct group_cfg_st *out); + int (*get_sup_config)(struct cfg_st *global_config, client_entry_st *entry, + SecAuthSessionReplyMsg *msg, void *pool); }; -void sup_config_init(main_server_st *s); +void sup_config_init(sec_mod_st *sec); #endif diff --git a/src/sec-mod.c b/src/sec-mod.c index 66c1b9ed..2b2bd755 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -281,7 +282,9 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, case SM_CMD_AUTH_SESSION_OPEN: case SM_CMD_AUTH_SESSION_CLOSE:{ SecAuthSessionMsg *msg; + void *lpool = NULL; SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT; + client_entry_st *e = NULL; if (uid != 0) { seclog(sec, LOG_INFO, "received session open/close from unauthorized uid (%u)\n", (unsigned)uid); @@ -296,21 +299,36 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - ret = handle_sec_auth_session_cmd(sec, msg, cmd); + ret = handle_sec_auth_session_cmd(sec, msg, cmd, &e); sec_auth_session_msg__free_unpacked(msg, &pa); if (cmd == SM_CMD_AUTH_SESSION_OPEN) { - if (ret < 0) + if (ret < 0 || e == NULL) rep.reply = AUTH__REP__FAILED; else rep.reply = AUTH__REP__OK; + if (sec->config_module && e != NULL) { + lpool = talloc_new(e); + if (lpool == NULL) { + return ERR_MEM; + } + + ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool); + if (ret < 0) { + seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username); + talloc_free(lpool); + return ERR_READ_CONFIG; + } + } + ret = send_msg(pool, sec->fd, SM_CMD_AUTH_SESSION_REPLY, &rep, (pack_size_func) sec_auth_session_reply_msg__get_packed_size, (pack_func) sec_auth_session_reply_msg__pack); if (ret < 0) { seclog(sec, LOG_WARNING, "sec-mod error in sending session reply"); } + talloc_free(lpool); } return ret; @@ -435,6 +453,8 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f sec->dcookie_key.size = COOKIE_KEY_SIZE; sec->config = talloc_steal(sec, config); + sup_config_init(sec); + memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", socket_file); diff --git a/src/sec-mod.h b/src/sec-mod.h index 3def32c5..72e3f647 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -19,6 +19,7 @@ * along with this program. If not, see */ #ifndef SEC_MOD_H +# define SEC_MOD_H #include #include @@ -34,6 +35,8 @@ typedef struct sec_mod_st { struct htable *client_db; struct htable *ban_db; + struct config_mod_st *config_module; + int fd; } sec_mod_st; @@ -87,7 +90,7 @@ void sec_auth_init(struct cfg_st *config); int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req); int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req); -int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd); +int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd, client_entry_st **_e); void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e); void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file, diff --git a/src/sup-config/file.c b/src/sup-config/file.c index e6a13757..ba9202f4 100644 --- a/src/sup-config/file.c +++ b/src/sup-config/file.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Nikos Mavrogiannopoulos + * Copyright (C) 2014 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +34,7 @@ #include #include -#include +#include struct cfg_options { const char* name; @@ -68,14 +69,14 @@ static struct cfg_options available_options[] = { if (val != NULL && val->valType == OPARG_TYPE_STRING) { \ if (s_name == NULL) { \ num = 0; \ - s_name = talloc_size(proc, sizeof(char*)*MAX_CONFIG_ENTRIES); \ + s_name = talloc_size(pool, sizeof(char*)*MAX_CONFIG_ENTRIES); \ } \ do { \ if (num >= MAX_CONFIG_ENTRIES) \ break; \ if (val && !strcmp(val->pzName, name)==0) \ continue; \ - s_name[num] = talloc_strdup(proc, val->v.strVal); \ + s_name[num] = talloc_strdup(pool, val->v.strVal); \ num++; \ } while((val = optionNextValue(pov, val)) != NULL); \ s_name[num] = NULL; \ @@ -86,28 +87,33 @@ static struct cfg_options available_options[] = { if (val != NULL && val->valType == OPARG_TYPE_STRING) { \ if (s_name != NULL) \ talloc_free(s_name); \ - s_name = talloc_strdup(proc, val->v.strVal); \ + s_name = talloc_strdup(pool, val->v.strVal); \ }} -#define READ_RAW_NUMERIC(name, s_name) { \ +#define READ_RAW_NUMERIC(name, s_name, def) { \ val = optionGetValue(pov, name); \ if (val != NULL) { \ - if (val->valType == OPARG_TYPE_NUMERIC) \ + if (val->valType == OPARG_TYPE_NUMERIC) {\ s_name = val->v.longVal; \ - else if (val->valType == OPARG_TYPE_STRING) \ + def = 1; \ + } else if (val->valType == OPARG_TYPE_STRING) {\ s_name = atoi(val->v.strVal); \ + def = 1; \ + } \ }} -#define READ_RAW_PRIO_TOS(name, s_name) { \ +#define READ_RAW_PRIO_TOS(name, s_name, def) { \ val = optionGetValue(pov, name); \ if (val != NULL) { \ if (val->valType == OPARG_TYPE_STRING) { \ if (strncmp(val->v.strVal, "0x", 2) == 0) { \ s_name = strtol(val->v.strVal, NULL, 16); \ s_name = TOS_PACK(s_name); \ + def = 1; \ } else { \ s_name = atoi(val->v.strVal); \ s_name++; \ + def = 1; \ } \ } \ }} @@ -115,12 +121,13 @@ static struct cfg_options available_options[] = { #define READ_TF(name, s_name, def) { \ { char* tmp_tf = NULL; \ READ_RAW_STRING(name, tmp_tf); \ - if (tmp_tf == NULL) s_name = def; \ - else { \ + if (tmp_tf == NULL) { def = 0; \ + } else { \ if (c_strcasecmp(tmp_tf, "true") == 0 || c_strcasecmp(tmp_tf, "yes") == 0) \ s_name = 1; \ else \ s_name = 0; \ + def = 1; \ } \ talloc_free(tmp_tf); \ }} @@ -143,13 +150,13 @@ unsigned j; * already allocated using this function. */ static -int parse_group_cfg_file(struct cfg_st *global_config, struct proc_st *proc, +int parse_group_cfg_file(struct cfg_st *global_config, + SecAuthSessionReplyMsg *msg, void *pool, const char* file) { tOptionValue const * pov; const tOptionValue* val, *prev; unsigned prefix = 0; -struct group_cfg_st *sconfig = &proc->config; pov = configFileLoad(file); if (pov == NULL) { @@ -171,59 +178,58 @@ struct group_cfg_st *sconfig = &proc->config; prev = val; } while((val = optionNextValue(pov, prev)) != NULL); - READ_TF("no-udp", sconfig->no_udp, (global_config->udp_port!=0)?0:1); - READ_TF("deny-roaming", sconfig->deny_roaming, global_config->deny_roaming); - READ_TF("require-cert", sconfig->require_cert, 0); + READ_TF("no-udp", msg->no_udp, msg->has_no_udp); + READ_TF("deny-roaming", msg->deny_roaming, msg->has_deny_roaming); + READ_TF("require-cert", msg->require_cert, msg->has_require_cert); - READ_RAW_MULTI_LINE("route", sconfig->routes, sconfig->routes_size); - READ_RAW_MULTI_LINE("iroute", sconfig->iroutes, sconfig->iroutes_size); + READ_RAW_MULTI_LINE("route", msg->routes, msg->n_routes); + READ_RAW_MULTI_LINE("iroute", msg->iroutes, msg->n_iroutes); - READ_RAW_MULTI_LINE("dns", sconfig->dns, sconfig->dns_size); - if (sconfig->dns_size == 0) { + READ_RAW_MULTI_LINE("dns", msg->dns, msg->n_dns); + if (msg->n_dns == 0) { /* try aliases */ - READ_RAW_MULTI_LINE("ipv6-dns", sconfig->dns, sconfig->dns_size); - READ_RAW_MULTI_LINE("ipv4-dns", sconfig->dns, sconfig->dns_size); + READ_RAW_MULTI_LINE("ipv6-dns", msg->dns, msg->n_dns); + READ_RAW_MULTI_LINE("ipv4-dns", msg->dns, msg->n_dns); } - READ_RAW_MULTI_LINE("nbns", sconfig->nbns, sconfig->nbns_size); - if (sconfig->nbns_size == 0) { + READ_RAW_MULTI_LINE("nbns", msg->nbns, msg->n_nbns); + if (msg->n_nbns == 0) { /* try aliases */ - READ_RAW_MULTI_LINE("ipv6-nbns", sconfig->nbns, sconfig->nbns_size); - READ_RAW_MULTI_LINE("ipv4-nbns", sconfig->nbns, sconfig->nbns_size); + READ_RAW_MULTI_LINE("ipv6-nbns", msg->nbns, msg->n_nbns); + READ_RAW_MULTI_LINE("ipv4-nbns", msg->nbns, msg->n_nbns); } - READ_RAW_STRING("cgroup", sconfig->cgroup); - READ_RAW_STRING("ipv4-network", sconfig->ipv4_network); - READ_RAW_STRING("ipv6-network", sconfig->ipv6_network); - READ_RAW_STRING("ipv4-netmask", sconfig->ipv4_netmask); + READ_RAW_STRING("cgroup", msg->cgroup); + READ_RAW_STRING("ipv4-network", msg->ipv4_net); + READ_RAW_STRING("ipv6-network", msg->ipv6_net); + READ_RAW_STRING("ipv4-netmask", msg->ipv4_netmask); - READ_RAW_NUMERIC("ipv6-prefix", prefix); - if (prefix > 0) { - sconfig->ipv6_prefix = prefix; - - if (valid_ipv6_prefix(prefix) == 0) { + READ_RAW_NUMERIC("ipv6-prefix", msg->ipv6_prefix, msg->has_ipv6_prefix); + if (msg->has_ipv6_prefix != 0) { + if (valid_ipv6_prefix(msg->ipv6_prefix) == 0) { syslog(LOG_ERR, "unknown ipv6-prefix '%u' in %s", prefix, file); } } - READ_RAW_NUMERIC("rx-data-per-sec", sconfig->rx_per_sec); - READ_RAW_NUMERIC("tx-data-per-sec", sconfig->tx_per_sec); - sconfig->rx_per_sec /= 1000; /* in kb */ - sconfig->tx_per_sec /= 1000; /* in kb */ + READ_RAW_NUMERIC("rx-data-per-sec", msg->rx_per_sec, msg->has_rx_per_sec); + READ_RAW_NUMERIC("tx-data-per-sec", msg->tx_per_sec, msg->has_tx_per_sec); + msg->rx_per_sec /= 1000; /* in kb */ + msg->tx_per_sec /= 1000; /* in kb */ /* net-priority will contain the actual priority + 1, * to allow having zero as uninitialized. */ - READ_RAW_PRIO_TOS("net-priority", sconfig->net_priority); + READ_RAW_PRIO_TOS("net-priority", msg->net_priority, msg->has_net_priority); - READ_RAW_STRING("user-profile", sconfig->xml_config_file); + READ_RAW_STRING("user-profile", msg->xml_config_file); optionUnloadNested(pov); return 0; } -static int read_sup_config_file(struct cfg_st *global_config, struct proc_st *proc, - const char *file, const char *fallback, const char *type) +static int read_sup_config_file(struct cfg_st *global_config, + SecAuthSessionReplyMsg *msg, void *pool, + const char *file, const char *fallback, const char *type) { int ret; @@ -231,44 +237,41 @@ static int read_sup_config_file(struct cfg_st *global_config, struct proc_st *pr syslog(LOG_DEBUG, "Loading %s configuration '%s'", type, file); - ret = parse_group_cfg_file(global_config, proc, file); + ret = parse_group_cfg_file(global_config, msg, pool, file); if (ret < 0) return ERR_READ_CONFIG; } else { if (fallback != NULL) { syslog(LOG_DEBUG, "Loading default %s configuration '%s'", type, fallback); - ret = parse_group_cfg_file(global_config, proc, fallback); + ret = parse_group_cfg_file(global_config, msg, pool, fallback); if (ret < 0) return ERR_READ_CONFIG; - } else { - syslog(LOG_DEBUG, "No %s configuration for '%s'", type, - proc->username); } } return 0; } -static int get_sup_config(struct cfg_st *global_config, struct proc_st *proc) +static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry, + SecAuthSessionReplyMsg *msg, void *pool) { char file[_POSIX_PATH_MAX]; int ret; - if (global_config->per_group_dir != NULL && proc->groupname[0] != 0) { - snprintf(file, sizeof(file), "%s/%s", global_config->per_group_dir, - proc->groupname); + if (cfg->per_group_dir != NULL && entry->groupname[0] != 0) { + snprintf(file, sizeof(file), "%s/%s", cfg->per_group_dir, + entry->groupname); - ret = read_sup_config_file(global_config, proc, file, global_config->default_group_conf, "group"); + ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_group_conf, "group"); if (ret < 0) return ret; } - if (global_config->per_user_dir != NULL) { - snprintf(file, sizeof(file), "%s/%s", global_config->per_user_dir, - proc->username); - - ret = read_sup_config_file(global_config, proc, file, global_config->default_user_conf, "user"); + if (cfg->per_user_dir != NULL) { + snprintf(file, sizeof(file), "%s/%s", cfg->per_user_dir, + entry->username); + ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_user_conf, "user"); if (ret < 0) return ret; } @@ -276,40 +279,6 @@ static int get_sup_config(struct cfg_st *global_config, struct proc_st *proc) return 0; } - -static -void clear_sup_config(struct group_cfg_st* config) -{ -unsigned i; - - for(i=0;iroutes_size;i++) { - talloc_free(config->routes[i]); - } - talloc_free(config->routes); - - for(i=0;iiroutes_size;i++) { - talloc_free(config->iroutes[i]); - } - talloc_free(config->iroutes); - - for(i=0;idns_size;i++) { - talloc_free(config->dns[i]); - } - talloc_free(config->dns); - - for(i=0;inbns_size;i++) { - talloc_free(config->nbns[i]); - } - talloc_free(config->nbns); - - talloc_free(config->cgroup); - talloc_free(config->ipv4_network); - talloc_free(config->ipv6_network); - talloc_free(config->ipv4_netmask); - safe_memset(config, 0, sizeof(*config)); -} - struct config_mod_st file_sup_config = { .get_sup_config = get_sup_config, - .clear_sup_config = clear_sup_config, }; diff --git a/src/sup-config/file.h b/src/sup-config/file.h index fb37ca53..cb1f5c77 100644 --- a/src/sup-config/file.h +++ b/src/sup-config/file.h @@ -21,7 +21,7 @@ #ifndef SUP_CONFIG_FILE_H #define SUP_CONFIG_FILE_H -#include +#include extern struct config_mod_st file_sup_config; diff --git a/src/vpn.h b/src/vpn.h index 0809ffc4..f485efd0 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -145,7 +145,10 @@ struct group_cfg_st { char *ipv6_network; unsigned ipv6_prefix; char *ipv4_netmask; - + + char *explicit_ipv4; + char *explicit_ipv6; + char *cgroup; char *xml_config_file; @@ -202,7 +205,6 @@ struct cfg_st { char *cert_user_oid; /* The OID that will be used to extract the username */ char *cert_group_oid; /* The OID that will be used to extract the groupname */ unsigned int auth_types; /* or'ed sequence of AUTH_TYPE */ - unsigned session_control; /* whether to use the session control part of authentication (PAM) */ char *auth_additional; /* the additional string specified in the auth methode */ gnutls_certificate_request_t cert_req; char *priorities; From 2194e11b3929f131270556ee7dc10cc7ceeaf030 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 8 Dec 2014 15:37:44 +0100 Subject: [PATCH 03/14] Added support for radius authentication --- configure.ac | 27 ++++ doc/sample.config | 3 + src/Makefile.am | 6 +- src/auth/common.c | 26 ++++ src/auth/common.h | 10 ++ src/auth/plain.c | 5 +- src/auth/radius.c | 292 ++++++++++++++++++++++++++++++++++++++++++++ src/auth/radius.h | 28 +++++ src/config.c | 33 ++++- src/main.h | 2 + src/ocserv-args.def | 6 +- src/sec-mod-auth.c | 14 +-- src/sec-mod-auth.h | 2 + src/sec-mod.c | 2 +- src/sec-mod.h | 2 +- src/vpn.h | 1 + 16 files changed, 438 insertions(+), 21 deletions(-) create mode 100644 src/auth/common.c create mode 100644 src/auth/common.h create mode 100644 src/auth/radius.c create mode 100644 src/auth/radius.h diff --git a/configure.ac b/configure.ac index 622929d8..e4cf122c 100644 --- a/configure.ac +++ b/configure.ac @@ -188,6 +188,32 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([ LIBS="$oldlibs" fi +AC_ARG_WITH(radius, + AS_HELP_STRING([--without-radius], [do not include Radius support]), + test_for_radius=$withval, + test_for_radius=yes) + +radius_enabled=no + +if test "$test_for_radius" = yes;then +LIBS="$oldlibs -lfreeradius-client" +AC_MSG_CHECKING([for freeradius client library]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ + #include ],[ + rc_read_config(0);])], + [AC_MSG_RESULT(yes) + AC_SUBST([FREERADIUS_CLIENT_LIBS], [-lfreeradius-client]) + AC_SUBST([FREERADIUS_CLIENT_CFLAGS], []) + radius_enabled=yes + AC_DEFINE([HAVE_RADIUS], 1, [Enable the Radius library])], + [AC_MSG_RESULT(no) + AC_MSG_WARN([[ +*** +*** libfreeradius-client was not found. Radius support will be disabled. +*** ]])]) +LIBS="$oldlibs" +fi + gl_INIT AC_LIB_HAVE_LINKFLAGS(crypt,, [#define _XOPEN_SOURCE @@ -381,6 +407,7 @@ Summary of build options: CFlags: ${CFLAGS} PAM auth backend: ${pam_enabled} + Radius auth backend: ${radius_enabled} TCP wrappers: ${libwrap_enabled} systemd: ${systemd_enabled} (socket activation) diff --git a/doc/sample.config b/doc/sample.config index e07e36a2..7f92b21c 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -22,6 +22,9 @@ auth = "plain[./sample.passwd]" # to generate password entries. #auth = "plain[/etc/ocserv/ocpasswd]" +# User authentication using radius. +#auth = "radius[/etc/radiusclient/radiusclient.conf]" + # Whether to enable seccomp worker isolation. That restricts the number of # system calls allowed to a worker process, in order to reduce damage from a # bug in the worker process. It is available on Linux systems at a performance cost. diff --git a/src/Makefile.am b/src/Makefile.am index 080baeac..08991828 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ endif COMMON_SOURCES=common.c common.h system.c system.h setproctitle.c setproctitle.h # Authentication module sources -AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h +AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h auth/radius.c auth/radius.h \ + auth/common.c auth/common.h ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ cookies.c main-misc.c ip-lease.c ip-lease.h \ @@ -87,7 +88,8 @@ ocserv_SOURCES += ipc.pb-c.h ipc.pb-c.c ctl.pb-c.c ctl.pb-c.h ocserv_LDADD = ../gl/libgnu.a $(NEEDED_LIBOPTS) libcmd-ocserv.a ocserv_LDADD += $(LIBGNUTLS_LIBS) $(PAM_LIBS) $(LIBUTIL) \ $(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT) $(NEEDED_HTTP_PARSER_LIBS) \ - $(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBTALLOC_LIBS) + $(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBTALLOC_LIBS) \ + $(FREERADIUS_CLIENT_LIBS) if PCL diff --git a/src/auth/common.c b/src/auth/common.c new file mode 100644 index 00000000..d55242df --- /dev/null +++ b/src/auth/common.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of ocserv. + * + * ocserv is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * ocserv is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +const char* pass_msg_first = "Please enter your password."; +const char* pass_msg_second = "Please enter your challenge password."; +const char* pass_msg_failed = "Login failed.\nPlease enter your password."; + diff --git a/src/auth/common.h b/src/auth/common.h new file mode 100644 index 00000000..36c4c5d9 --- /dev/null +++ b/src/auth/common.h @@ -0,0 +1,10 @@ +#ifndef AUTH_COMMON_H +# define AUTH_COMMON_H + +#define MAX_TRIES 3 + +extern const char* pass_msg_first; +extern const char* pass_msg_second; +extern const char* pass_msg_failed; + +#endif diff --git a/src/auth/plain.c b/src/auth/plain.c index 0e13241f..bf2e80f7 100644 --- a/src/auth/plain.c +++ b/src/auth/plain.c @@ -29,14 +29,11 @@ #include #include #include "plain.h" +#include "auth/common.h" #include #include #define MAX_CPASS_SIZE 128 -#define MAX_TRIES 3 - -const char* pass_msg_first = "Please enter your password."; -const char* pass_msg_failed = "Login failed.\nPlease enter your password."; struct plain_ctx_st { char username[MAX_USERNAME_SIZE]; diff --git a/src/auth/radius.c b/src/auth/radius.c new file mode 100644 index 00000000..4fe78803 --- /dev/null +++ b/src/auth/radius.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This file is part of ocserv. + * + * ocserv is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * ocserv is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* inet_ntop */ +#include "radius.h" +#include "auth/common.h" + +#ifdef HAVE_RADIUS + +#include + +#define RAD_GROUP_NAME 1030 + +int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, + char *msg, int add_nas_port, int request_type); + +static rc_handle *rh = NULL; + +struct radius_ctx_st { + char username[MAX_USERNAME_SIZE*2]; + char groupname[MAX_GROUPNAME_SIZE]; + char msg[4096]; + + char ipv4[MAX_IP_STR]; + char ipv6[MAX_IP_STR]; + + const char *config; /* radius config file */ + const char *pass_msg; + unsigned retries; +}; + +static void radius_global_init(void *pool, void *additional) +{ + rh = rc_read_config(additional); + if (rh == NULL) { + fprintf(stderr, "radius initialization error\n"); + exit(1); + } + + if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) { + fprintf(stderr, "error reading the radius dictionary\n"); + exit(1); + } + + return; +} + +static void radius_global_deinit() +{ + if (rh != NULL) + rc_destroy(rh); +} + +static int radius_auth_init(void **ctx, void *pool, const char *username, const char *ip, + void *additional) +{ + struct radius_ctx_st *pctx; + char *default_realm; + + pctx = talloc_zero(pool, struct radius_ctx_st); + if (pctx == NULL) + return ERR_AUTH_FAIL; + + snprintf(pctx->username, sizeof(pctx->username), "%s", username); + pctx->config = additional; + pctx->pass_msg = pass_msg_first; + + default_realm = rc_conf_str(rh, "default_realm"); + + if ((strchr(username, '@') == NULL) && default_realm && + default_realm[0] != 0) { + snprintf(pctx->username, sizeof(pctx->username), "%s@%s", username, default_realm); + } else { + strcpy(pctx->username, username); + } + + + *ctx = pctx; + + return 0; +} + +static int radius_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size) +{ + struct radius_ctx_st *pctx = ctx; + + groupname[0] = 0; + + if (suggested != NULL) { + if (strcmp(suggested, pctx->groupname) == 0) { + snprintf(groupname, groupname_size, "%s", pctx->groupname); + return 0; + } + + syslog(LOG_AUTH, + "user '%s' requested group '%s' but is not a member", + pctx->username, suggested); + return -1; + } + + if (pctx->groupname[0] != 0 && groupname[0] == 0) { + snprintf(groupname, groupname_size, "%s", pctx->groupname); + } + return 0; +} + +static int radius_auth_user(void *ctx, char *username, int username_size) +{ + /* do not update username */ + return -1; +} + +/* Returns 0 if the user is successfully authenticated, and sets the appropriate group name. + */ +static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) +{ + struct radius_ctx_st *pctx = ctx; + VALUE_PAIR *send = NULL, *recvd = NULL; + uint32_t service; + int ret; + + syslog(LOG_DEBUG, "communicating username (%s) and password to radius", pctx->username); + if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) { + syslog(LOG_ERR, + "%s:%u: user '%s' auth error", __func__, __LINE__, + pctx->username); + return ERR_AUTH_FAIL; + } + + if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, (char*)pass, -1, 0) == NULL) { + syslog(LOG_ERR, + "%s:%u: user '%s' auth error", __func__, __LINE__, + pctx->username); + return ERR_AUTH_FAIL; + } + + service = PW_AUTHENTICATE_ONLY; + if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) { + syslog(LOG_ERR, + "%s:%u: user '%s' auth error", __func__, __LINE__, + pctx->username); + return ERR_AUTH_FAIL; + } + + ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCESS_REQUEST); + + if (ret == OK_RC) { + VALUE_PAIR *vp = recvd; + while(vp != NULL) { + if (vp->attribute == PW_SERVICE_TYPE && vp->lvalue != PW_FRAMED) { + syslog(LOG_ERR, + "%s:%u: unknown radius service type '%d'", __func__, __LINE__, + (int)vp->lvalue); + goto fail; + } else if (vp->attribute == RAD_GROUP_NAME && vp->type == PW_TYPE_STRING) { + snprintf(pctx->groupname, sizeof(pctx->groupname), "%s", vp->strvalue); + } else if (vp->attribute == PW_FRAMED_IP_ADDRESS && vp->type == PW_TYPE_IPADDR) { + inet_ntop(AF_INET, &vp->lvalue, pctx->ipv4, sizeof(pctx->ipv4)); + } else { + syslog(LOG_DEBUG, "radius: ignoring server's value %u of type %u", (int)vp->attribute, (int)vp->type); + } + vp = vp->next; + } + + if (recvd != NULL) + rc_avpair_free(recvd); + return 0; + } else { + fail: + if (recvd != NULL) + rc_avpair_free(recvd); + + if (ret == PW_ACCESS_CHALLENGE) { + pctx->pass_msg = pass_msg_second; + return ERR_AUTH_CONTINUE; + } else if ( pctx->retries++ < MAX_TRIES) { + pctx->pass_msg = pass_msg_failed; + return ERR_AUTH_CONTINUE; + } else { + syslog(LOG_AUTH, + "radius-auth: error authenticating user '%s'", + pctx->username); + return ERR_AUTH_FAIL; + } + } +} + +static int radius_auth_msg(void *ctx, char *msg, size_t msg_size) +{ + struct radius_ctx_st *pctx = ctx; + + snprintf(msg, msg_size, "%s", pctx->pass_msg); + return 0; +} + +static void radius_auth_deinit(void *ctx) +{ + struct radius_ctx_st *pctx = ctx; + talloc_free(pctx); +} + + +static int radius_auth_open_session(void* ctx) +{ +struct radius_ctx_st * pctx = ctx; +int ret; +uint32_t status_type; +VALUE_PAIR *send = NULL, *recvd = NULL; + + status_type = PW_STATUS_START; + + syslog(LOG_DEBUG, "opening session with radius"); + if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) + return -1; + + ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST); + if (recvd != NULL) + rc_avpair_free(recvd); + + if (ret != OK_RC) { + syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret); + return -1; + } + + return 0; +} + +static void radius_auth_close_session(void* ctx) +{ +struct radius_ctx_st * pctx = ctx; +int ret; +uint32_t status_type; +VALUE_PAIR *send = NULL, *recvd = NULL; + + status_type = PW_STATUS_STOP; + + syslog(LOG_DEBUG, "closing session with radius"); + if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) + return; + + ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST); + if (recvd != NULL) + rc_avpair_free(recvd); + + if (ret != OK_RC) { + syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret); + return; + } + + return; +} + +const struct auth_mod_st radius_auth_funcs = { + .type = AUTH_TYPE_RADIUS | AUTH_TYPE_USERNAME_PASS, + .global_init = radius_global_init, + .global_deinit = radius_global_deinit, + .auth_init = radius_auth_init, + .auth_deinit = radius_auth_deinit, + .auth_msg = radius_auth_msg, + .auth_pass = radius_auth_pass, + .auth_user = radius_auth_user, + .auth_group = radius_auth_group, + .open_session = radius_auth_open_session, + .close_session = radius_auth_close_session, + .group_list = NULL +}; + +#endif diff --git a/src/auth/radius.h b/src/auth/radius.h new file mode 100644 index 00000000..fa862020 --- /dev/null +++ b/src/auth/radius.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of ocserv. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#ifndef RADIUS_H +#define RADIUS_H + +#include + +extern const struct auth_mod_st radius_auth_funcs; + +#endif diff --git a/src/config.c b/src/config.c index fd02f718..a62179ec 100644 --- a/src/config.c +++ b/src/config.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ static char pid_file[_POSIX_PATH_MAX] = ""; static const char* cfg_file = DEFAULT_CFG_FILE; +static const struct auth_mod_st *amod = NULL; struct cfg_options { const char* name; @@ -324,6 +326,11 @@ static char *get_brackets_string(void *pool, const char *str) return talloc_strndup(pool, p, len); } +const struct auth_mod_st *get_auth_mod(void) +{ + return amod; +} + static void parse_cfg_file(const char* file, struct cfg_st *config, unsigned reload) { tOptionValue const * pov; @@ -332,7 +339,6 @@ unsigned j, i, mand; char** auth = NULL; unsigned auth_size = 0; unsigned prefix = 0, auto_select_group = 0; -const struct auth_mod_st *amod = NULL; char *tmp; unsigned force_cert_auth; @@ -369,7 +375,7 @@ unsigned force_cert_auth; exit(1); } #ifdef HAVE_PAM - config->auth_types |= AUTH_TYPE_PAM; + config->auth_types |= amod->type; amod = &pam_auth_funcs; #else fprintf(stderr, "PAM support is disabled\n"); @@ -387,7 +393,25 @@ unsigned force_cert_auth; exit(1); } amod = &plain_auth_funcs; - config->auth_types |= AUTH_TYPE_PLAIN; + config->auth_types |= amod->type; + } else if (strncasecmp(auth[j], "radius", 6) == 0) { + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); + exit(1); + } + +#ifdef HAVE_RADIUS + config->auth_additional = get_brackets_string(config, auth[j]+6); + if (config->auth_additional == NULL) { + fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); + exit(1); + } + amod = &radius_auth_funcs; + config->auth_types |= amod->type; +#else + fprintf(stderr, "Radius support is disabled\n"); + exit(1); +#endif } else if (c_strcasecmp(auth[j], "certificate") == 0) { config->auth_types |= AUTH_TYPE_CERTIFICATE; } else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) { @@ -821,6 +845,9 @@ void print_version(tOptions *opts, tOptDesc *desc) #ifdef HAVE_LIBWRAP fprintf(stderr, "tcp-wrappers, "); #endif +#ifdef HAVE_RADIUS + fprintf(stderr, "radius, "); +#endif #ifdef HAVE_PAM fprintf(stderr, "PAM, "); #endif diff --git a/src/main.h b/src/main.h index 107315b2..25330c28 100644 --- a/src/main.h +++ b/src/main.h @@ -304,4 +304,6 @@ int send_socket_msg_to_worker(main_server_st* s, struct proc_st* proc, uint8_t c void request_reload(int signo); void request_stop(int signo); +const struct auth_mod_st *get_auth_mod(void); + #endif diff --git a/src/ocserv-args.def b/src/ocserv-args.def index c4b2a727..2e6eb46b 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -76,7 +76,7 @@ An example configuration file follows. # User authentication method. Could be set multiple times and in # that case all should succeed. To enable multiple methods use # multiple auth directives. Available options: certificate, certificate[optional], -# plain, pam. +# plain, pam, radius[config]. #auth = "certificate" #auth = "pam" @@ -96,6 +96,10 @@ An example configuration file follows. # to generate password entries. #auth = "plain[/etc/ocserv/ocpasswd]" +# The radius option requires specifying freeradius-client configuration +# file. +#auth = "radius[/etc/radiusclient/radiusclient.conf]" + # Whether to enable seccomp worker isolation. That restricts the number of # system calls allowed to a worker process, in order to reduce damage from a # bug in the worker process. It is available on Linux systems at a performance cost. diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 8c13ca01..887c6614 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -53,16 +53,12 @@ static const struct auth_mod_st *module = NULL; -void sec_auth_init(struct cfg_st *config) +void sec_auth_init(void *pool, struct cfg_st *config) { -#ifdef HAVE_PAM - if ((config->auth_types & pam_auth_funcs.type) == pam_auth_funcs.type) - module = &pam_auth_funcs; - else -#endif - if ((config->auth_types & plain_auth_funcs.type) == - plain_auth_funcs.type) { - module = &plain_auth_funcs; + module = get_auth_mod(); + + if (module->global_init) { + module->global_init(pool, config->auth_additional); } } diff --git a/src/sec-mod-auth.h b/src/sec-mod-auth.h index 1cde226c..3bc5a1f0 100644 --- a/src/sec-mod-auth.h +++ b/src/sec-mod-auth.h @@ -28,6 +28,8 @@ struct auth_mod_st { unsigned int type; + void (*global_init)(void *pool, void* additional); + void (*global_deinit)(void); int (*auth_init)(void** ctx, void *pool, const char* username, const char* ip, void* additional); int (*auth_msg)(void* ctx, char* msg, size_t msg_size); int (*auth_pass)(void* ctx, const char* pass, unsigned pass_len); diff --git a/src/sec-mod.c b/src/sec-mod.c index 2b2bd755..15ea8e84 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -472,7 +472,7 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f alarm(MAINTAINANCE_TIME); - sec_auth_init(config); + sec_auth_init(sec, config); #ifdef HAVE_PKCS11 ret = gnutls_pkcs11_reinit(); diff --git a/src/sec-mod.h b/src/sec-mod.h index 72e3f647..7cd5909f 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -86,7 +86,7 @@ void cleanup_client_entries(sec_mod_st *sec); } #endif -void sec_auth_init(struct cfg_st *config); +void sec_auth_init(void *pool, struct cfg_st *config); int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req); int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req); diff --git a/src/vpn.h b/src/vpn.h index f485efd0..527b87a2 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -76,6 +76,7 @@ extern int syslog_open; #define AUTH_TYPE_PLAIN (1<<2 | AUTH_TYPE_USERNAME_PASS) #define AUTH_TYPE_CERTIFICATE (1<<3) #define AUTH_TYPE_CERTIFICATE_OPT (1<<4|AUTH_TYPE_CERTIFICATE) +#define AUTH_TYPE_RADIUS (1<<5 | AUTH_TYPE_USERNAME_PASS) #define ERR_SUCCESS 0 #define ERR_BAD_COMMAND -2 From 766afb591a4375b7c5d7e07e73798a401fb3369f Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 9 Dec 2014 13:20:11 +0100 Subject: [PATCH 04/14] Added support for reading user configuration from radius. --- doc/sample.config | 2 +- src/Makefile.am | 1 + src/auth/radius.c | 49 +++++++++++++------ src/auth/radius.h | 21 ++++++++ src/config.c | 64 ++++++++++++++++++++++--- src/ocserv-args.def | 7 +-- src/sec-mod-sup-config.c | 7 ++- src/sec-mod-sup-config.h | 3 ++ src/sup-config/radius.c | 100 +++++++++++++++++++++++++++++++++++++++ src/sup-config/radius.h | 28 +++++++++++ src/vpn.h | 1 + 11 files changed, 258 insertions(+), 25 deletions(-) create mode 100644 src/sup-config/radius.c create mode 100644 src/sup-config/radius.h diff --git a/doc/sample.config b/doc/sample.config index 7f92b21c..75649414 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -23,7 +23,7 @@ auth = "plain[./sample.passwd]" #auth = "plain[/etc/ocserv/ocpasswd]" # User authentication using radius. -#auth = "radius[/etc/radiusclient/radiusclient.conf]" +#auth = "radius[/usr/local/etc/radiusclient/radiusclient.conf,groupconfig]" # Whether to enable seccomp worker isolation. That restricts the number of # system calls allowed to a worker process, in order to reduce damage from a diff --git a/src/Makefile.am b/src/Makefile.am index 08991828..e7d79464 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ icmp-ping.c icmp-ping.h \ sec-mod-sup-config.c sec-mod-sup-config.h \ sup-config/file.c sup-config/file.h \ + sup-config/radius.c sup-config/radius.h \ worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \ vasprintf.c vasprintf.h \ proc-search.c proc-search.h \ diff --git a/src/auth/radius.c b/src/auth/radius.c index 4fe78803..b3f12a81 100644 --- a/src/auth/radius.c +++ b/src/auth/radius.c @@ -33,26 +33,20 @@ #include +#if !defined(PW_FRAMED_IPV6_ADDRESS) && defined(PW_TYPE_IPV6ADDR) +#define PW_FRAMED_IPV6_ADDRESS 168 +#define PW_DNS_SERVER_IPV6_ADDRESS 169 +#endif + #define RAD_GROUP_NAME 1030 +#define RAD_IPV4_DNS1 ((311<<16)|(28)) +#define RAD_IPV4_DNS2 ((311<<16)|(29)) int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, int request_type); static rc_handle *rh = NULL; -struct radius_ctx_st { - char username[MAX_USERNAME_SIZE*2]; - char groupname[MAX_GROUPNAME_SIZE]; - char msg[4096]; - - char ipv4[MAX_IP_STR]; - char ipv6[MAX_IP_STR]; - - const char *config; /* radius config file */ - const char *pass_msg; - unsigned retries; -}; - static void radius_global_init(void *pool, void *additional) { rh = rc_read_config(additional); @@ -170,6 +164,7 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) if (ret == OK_RC) { VALUE_PAIR *vp = recvd; + uint32_t ip; while(vp != NULL) { if (vp->attribute == PW_SERVICE_TYPE && vp->lvalue != PW_FRAMED) { syslog(LOG_ERR, @@ -177,9 +172,35 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) (int)vp->lvalue); goto fail; } else if (vp->attribute == RAD_GROUP_NAME && vp->type == PW_TYPE_STRING) { + /* Group-Name */ snprintf(pctx->groupname, sizeof(pctx->groupname), "%s", vp->strvalue); +#ifdef PW_FRAMED_IPV6_ADDRESS + } else if (vp->attribute == PW_FRAMED_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) { + /* Framed-IPv6-Address */ + inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6, sizeof(pctx->ipv6)); + } else if (vp->attribute == PW_DNS_SERVER_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) { + /* DNS-Server-IPv6-Address */ + if (pctx->ipv6_dns1[0] == 0) + inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns1, sizeof(pctx->ipv6_dns1)); + else + inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns2, sizeof(pctx->ipv6_dns2)); +#endif } else if (vp->attribute == PW_FRAMED_IP_ADDRESS && vp->type == PW_TYPE_IPADDR) { - inet_ntop(AF_INET, &vp->lvalue, pctx->ipv4, sizeof(pctx->ipv4)); + /* Framed-IP-Address */ + ip = htonl(vp->lvalue); + inet_ntop(AF_INET, &ip, pctx->ipv4, sizeof(pctx->ipv4)); + } else if (vp->attribute == PW_FRAMED_IP_NETMASK && vp->type == PW_TYPE_IPADDR) { + /* Framed-IP-Netmask */ + ip = htonl(vp->lvalue); + inet_ntop(AF_INET, &ip, pctx->ipv4_mask, sizeof(pctx->ipv4_mask)); + } else if (vp->attribute == RAD_IPV4_DNS1 && vp->type == PW_TYPE_IPADDR) { + /* MS-Primary-DNS-Server */ + ip = htonl(vp->lvalue); + inet_ntop(AF_INET, &ip, pctx->ipv4_dns1, sizeof(pctx->ipv4_dns1)); + } else if (vp->attribute == RAD_IPV4_DNS2 && vp->type == PW_TYPE_IPADDR) { + /* MS-Secondary-DNS-Server */ + ip = htonl(vp->lvalue); + inet_ntop(AF_INET, &ip, pctx->ipv4_dns2, sizeof(pctx->ipv4_dns2)); } else { syslog(LOG_DEBUG, "radius: ignoring server's value %u of type %u", (int)vp->attribute, (int)vp->type); } diff --git a/src/auth/radius.h b/src/auth/radius.h index fa862020..b98ac823 100644 --- a/src/auth/radius.h +++ b/src/auth/radius.h @@ -23,6 +23,27 @@ #include +struct radius_ctx_st { + char username[MAX_USERNAME_SIZE*2]; + char groupname[MAX_GROUPNAME_SIZE]; + char msg[4096]; + + /* variables for configuration */ + char ipv4[MAX_IP_STR]; + char ipv4_mask[MAX_IP_STR]; + char ipv4_dns1[MAX_IP_STR]; + char ipv4_dns2[MAX_IP_STR]; + + char ipv6[MAX_IP_STR]; + uint16_t ipv6_prefix; + char ipv6_dns1[MAX_IP_STR]; + char ipv6_dns2[MAX_IP_STR]; + + const char *config; /* radius config file */ + const char *pass_msg; + unsigned retries; +}; + extern const struct auth_mod_st radius_auth_funcs; #endif diff --git a/src/config.c b/src/config.c index a62179ec..f42e7938 100644 --- a/src/config.c +++ b/src/config.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,9 @@ static struct cfg_options available_options[] = { { .name = "default-group-config", .type = OPTION_STRING, .mandatory = 0 }, }; -static char *get_brackets_string(void *pool, const char *str); +#define get_brackets_string get_brackets_string1 +static char *get_brackets_string1(void *pool, const char *str); +static char *get_brackets_string2(void *pool, const char *str); static const tOptionValue* get_option(const char* name, unsigned * mand) { @@ -302,7 +305,7 @@ unsigned j; } } -static char *get_brackets_string(void *pool, const char *str) +static char *get_brackets_string1(void *pool, const char *str) { char *p, *p2; unsigned len; @@ -315,10 +318,47 @@ static char *get_brackets_string(void *pool, const char *str) while (c_isspace(*p)) p++; - p2 = strchr(p, ']'); + p2 = strchr(p, ','); if (p2 == NULL) { - fprintf(stderr, "error parsing %s\n", str); - exit(1); + p2 = strchr(p, ']'); + if (p2 == NULL) { + fprintf(stderr, "error parsing %s\n", str); + exit(1); + } + } + + len = p2 - p; + + return talloc_strndup(pool, p, len); +} + +static char *get_brackets_string2(void *pool, const char *str) +{ + char *p, *p2; + unsigned len; + + p = strchr(str, '['); + if (p == NULL) { + return NULL; + } + p++; + + p = strchr(p, ','); + if (p == NULL) { + return NULL; + } + p++; + + while (c_isspace(*p)) + p++; + + p2 = strchr(p, ','); + if (p2 == NULL) { + p2 = strchr(p, ']'); + if (p2 == NULL) { + fprintf(stderr, "error parsing %s\n", str); + exit(1); + } } len = p2 - p; @@ -366,6 +406,8 @@ unsigned force_cert_auth; prev = val; } while((val = optionNextValue(pov, prev)) != NULL); + config->sup_config_type = SUP_CONFIG_FILE; + READ_MULTI_LINE("auth", auth, auth_size); for (j=0;jauth_types |= amod->type; } else if (strncasecmp(auth[j], "radius", 6) == 0) { + const char *p; if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); exit(1); } #ifdef HAVE_RADIUS - config->auth_additional = get_brackets_string(config, auth[j]+6); + config->auth_additional = get_brackets_string1(config, auth[j]+6); if (config->auth_additional == NULL) { fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); exit(1); } + + p = get_brackets_string2(config, auth[j]+6); + if (p != NULL) { + if (strcasecmp(p, "groupconfig") != 0) { + fprintf(stderr, "No known configuration option: %s\n", p); + exit(1); + } + config->sup_config_type = SUP_CONFIG_RADIUS; + } amod = &radius_auth_funcs; config->auth_types |= amod->type; #else diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 2e6eb46b..10db7245 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -76,7 +76,7 @@ An example configuration file follows. # User authentication method. Could be set multiple times and in # that case all should succeed. To enable multiple methods use # multiple auth directives. Available options: certificate, certificate[optional], -# plain, pam, radius[config]. +# plain, pam, radius[configfile,groupconfig]. #auth = "certificate" #auth = "pam" @@ -97,8 +97,9 @@ An example configuration file follows. #auth = "plain[/etc/ocserv/ocpasswd]" # The radius option requires specifying freeradius-client configuration -# file. -#auth = "radius[/etc/radiusclient/radiusclient.conf]" +# file. If the groupconfig option is set, then config-per-user will be overriden, +# and all configuration will be read from radius. +#auth = "radius[/etc/radiusclient/radiusclient.conf,groupconfig]" # Whether to enable seccomp worker isolation. That restricts the number of # system calls allowed to a worker process, in order to reduce damage from a diff --git a/src/sec-mod-sup-config.c b/src/sec-mod-sup-config.c index 29ce7752..0caa6376 100644 --- a/src/sec-mod-sup-config.c +++ b/src/sec-mod-sup-config.c @@ -29,9 +29,14 @@ #include #include #include +#include void sup_config_init(sec_mod_st *sec) { - sec->config_module = &file_sup_config; + if (sec->config->sup_config_type == SUP_CONFIG_FILE) { + sec->config_module = &file_sup_config; + } else if (sec->config->sup_config_type == SUP_CONFIG_RADIUS) { + sec->config_module = &radius_sup_config; + } } diff --git a/src/sec-mod-sup-config.h b/src/sec-mod-sup-config.h index ef11b041..1252bb79 100644 --- a/src/sec-mod-sup-config.h +++ b/src/sec-mod-sup-config.h @@ -23,6 +23,9 @@ #include +#define SUP_CONFIG_FILE 1 +#define SUP_CONFIG_RADIUS 2 + /* The get_sup_config() should read any additional configuration for * proc->username/proc->groupname and save it in proc->config. */ diff --git a/src/sup-config/radius.c b/src/sup-config/radius.c new file mode 100644 index 00000000..a05bde2e --- /dev/null +++ b/src/sup-config/radius.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_RADIUS + +#include +#include +#include +#include + +static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry, + SecAuthSessionReplyMsg *msg, void *pool) +{ + struct radius_ctx_st *pctx = entry->auth_ctx; + unsigned dns = 0; + + if (pctx == NULL) + return 0; + + if (pctx->ipv4[0] != 0) { + msg->explicit_ipv4 = talloc_strdup(pool, pctx->ipv4); + } + + if (pctx->ipv4_mask[0] != 0) { + msg->ipv4_netmask = talloc_strdup(pool, pctx->ipv4_mask); + } + + if (pctx->ipv4_dns1[0] != 0) + dns++; + if (pctx->ipv4_dns2[0] != 0) + dns++; + if (pctx->ipv6_dns1[0] != 0) + dns++; + if (pctx->ipv6_dns2[0] != 0) + dns++; + + if (dns > 0) { + msg->dns = talloc_size(pool, dns*sizeof(char*)); + if (msg->dns != NULL) { + unsigned pos = 0; + if (pctx->ipv4_dns1[0] != 0) + msg->dns[pos++] = talloc_strdup(pool, pctx->ipv4_dns1); + if (pctx->ipv4_dns2[0] != 0) + msg->dns[pos++] = talloc_strdup(pool, pctx->ipv4_dns2); + if (pctx->ipv6_dns1[0] != 0) + msg->dns[pos++] = talloc_strdup(pool, pctx->ipv6_dns1); + if (pctx->ipv6_dns2[0] != 0) + msg->dns[pos++] = talloc_strdup(pool, pctx->ipv6_dns2); + + msg->n_dns = dns; + } + } + + if (pctx->ipv6[0] != 0) { + msg->explicit_ipv6 = talloc_strdup(pool, pctx->ipv6); + } + + if (pctx->ipv6_prefix != 0) { + msg->ipv6_prefix = pctx->ipv6_prefix; + msg->has_ipv6_prefix = 1; + } + + return 0; +} + +struct config_mod_st radius_sup_config = { + .get_sup_config = get_sup_config, +}; + +#endif diff --git a/src/sup-config/radius.h b/src/sup-config/radius.h new file mode 100644 index 00000000..554e7ab9 --- /dev/null +++ b/src/sup-config/radius.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of ocserv. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#ifndef SUP_CONFIG_RADIUS_H +#define SUP_CONFIG_RADIUS_H + +#include + +extern struct config_mod_st radius_sup_config; + +#endif diff --git a/src/vpn.h b/src/vpn.h index 527b87a2..5c70a4bc 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -192,6 +192,7 @@ struct cfg_st { unsigned int udp_port; unsigned int is_dyndns; char* unix_conn_file; + unsigned int sup_config_type; /* one of SUP_CONFIG_ */ char *pin_file; char *srk_pin_file; From ed5b177691d52c1c5417ef802854e26c9dd5d4f4 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 08:56:23 +0100 Subject: [PATCH 05/14] authentication information is only read on load --- src/config.c | 128 ++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/src/config.c b/src/config.c index f42e7938..bf5e1522 100644 --- a/src/config.c +++ b/src/config.c @@ -406,75 +406,79 @@ unsigned force_cert_auth; prev = val; } while((val = optionNextValue(pov, prev)) != NULL); - config->sup_config_type = SUP_CONFIG_FILE; + /* authentication information is only read on first load, as + * it cannot be safely switched */ + if (reload == 0) { + config->sup_config_type = SUP_CONFIG_FILE; - READ_MULTI_LINE("auth", auth, auth_size); - for (j=0;jauth_additional = get_brackets_string(config, auth[j]+3); - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } -#ifdef HAVE_PAM - config->auth_types |= amod->type; - amod = &pam_auth_funcs; -#else - fprintf(stderr, "PAM support is disabled\n"); - exit(1); -#endif - } else if (strncasecmp(auth[j], "plain", 5) == 0) { - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } - - config->auth_additional = get_brackets_string(config, auth[j]+5); - if (config->auth_additional == NULL) { - fprintf(stderr, "Format error in %s\n", auth[j]); - exit(1); - } - amod = &plain_auth_funcs; - config->auth_types |= amod->type; - } else if (strncasecmp(auth[j], "radius", 6) == 0) { - const char *p; - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } - -#ifdef HAVE_RADIUS - config->auth_additional = get_brackets_string1(config, auth[j]+6); - if (config->auth_additional == NULL) { - fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); - exit(1); - } - - p = get_brackets_string2(config, auth[j]+6); - if (p != NULL) { - if (strcasecmp(p, "groupconfig") != 0) { - fprintf(stderr, "No known configuration option: %s\n", p); + READ_MULTI_LINE("auth", auth, auth_size); + for (j=0;jauth_additional = get_brackets_string(config, auth[j]+3); + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); exit(1); } - config->sup_config_type = SUP_CONFIG_RADIUS; - } - amod = &radius_auth_funcs; - config->auth_types |= amod->type; +#ifdef HAVE_PAM + config->auth_types |= amod->type; + amod = &pam_auth_funcs; #else - fprintf(stderr, "Radius support is disabled\n"); - exit(1); + fprintf(stderr, "PAM support is disabled\n"); + exit(1); #endif - } else if (c_strcasecmp(auth[j], "certificate") == 0) { - config->auth_types |= AUTH_TYPE_CERTIFICATE; - } else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) { - config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT; - } else { - fprintf(stderr, "Unknown auth method: %s\n", auth[j]); - exit(1); + } else if (strncasecmp(auth[j], "plain", 5) == 0) { + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); + exit(1); + } + + config->auth_additional = get_brackets_string(config, auth[j]+5); + if (config->auth_additional == NULL) { + fprintf(stderr, "Format error in %s\n", auth[j]); + exit(1); + } + amod = &plain_auth_funcs; + config->auth_types |= amod->type; + } else if (strncasecmp(auth[j], "radius", 6) == 0) { + const char *p; + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); + exit(1); + } + +#ifdef HAVE_RADIUS + config->auth_additional = get_brackets_string1(config, auth[j]+6); + if (config->auth_additional == NULL) { + fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); + exit(1); + } + + p = get_brackets_string2(config, auth[j]+6); + if (p != NULL) { + if (strcasecmp(p, "groupconfig") != 0) { + fprintf(stderr, "No known configuration option: %s\n", p); + exit(1); + } + config->sup_config_type = SUP_CONFIG_RADIUS; + } + amod = &radius_auth_funcs; + config->auth_types |= amod->type; +#else + fprintf(stderr, "Radius support is disabled\n"); + exit(1); +#endif + } else if (c_strcasecmp(auth[j], "certificate") == 0) { + config->auth_types |= AUTH_TYPE_CERTIFICATE; + } else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) { + config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT; + } else { + fprintf(stderr, "Unknown auth method: %s\n", auth[j]); + exit(1); + } + talloc_free(auth[j]); } - talloc_free(auth[j]); + talloc_free(auth); } - talloc_free(auth); /* When adding allocated data, remember to modify * reload_cfg_file(); From 35e93c63417f75e5eab51cb20a325472ef392f99 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 10:15:02 +0100 Subject: [PATCH 06/14] added option to send statistics periodically to sec-mod --- src/config.c | 3 +++ src/ipc.proto | 1 + src/ocserv-args.def | 6 ++++++ src/sec-mod.c | 36 ++++++++++++++++++++++++++++++++++++ src/sec-mod.h | 5 +++++ src/vpn.h | 2 ++ src/worker-auth.c | 12 +----------- src/worker-vpn.c | 28 ++++++++++++++++++++++++++++ src/worker.h | 14 ++++++++++++++ 9 files changed, 96 insertions(+), 11 deletions(-) diff --git a/src/config.c b/src/config.c index bf5e1522..90935722 100644 --- a/src/config.c +++ b/src/config.c @@ -109,6 +109,7 @@ static struct cfg_options available_options[] = { { .name = "net-priority", .type = OPTION_STRING, .mandatory = 0 }, { .name = "output-buffer", .type = OPTION_NUMERIC, .mandatory = 0 }, { .name = "cookie-timeout", .type = OPTION_NUMERIC, .mandatory = 0 }, + { .name = "stats-report-time", .type = OPTION_NUMERIC, .mandatory = 0 }, { .name = "rekey-time", .type = OPTION_NUMERIC, .mandatory = 0 }, { .name = "rekey-method", .type = OPTION_STRING, .mandatory = 0 }, { .name = "auth-timeout", .type = OPTION_NUMERIC, .mandatory = 0 }, @@ -577,6 +578,8 @@ unsigned force_cert_auth; READ_TF("deny-roaming", config->deny_roaming, 0); + READ_NUMERIC("stats-report-time", config->stats_report_time); + config->rekey_time = -1; READ_NUMERIC("rekey-time", config->rekey_time); if (config->rekey_time == -1) { diff --git a/src/ipc.proto b/src/ipc.proto index ee805936..7879bec3 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -86,6 +86,7 @@ message cli_stats_msg { required uint64 bytes_in = 1; required uint64 bytes_out = 2; + optional bytes sid = 3; /* only required by sec-mod */ } /* UDP_FD */ diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 10db7245..0c8f8b24 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -140,6 +140,12 @@ udp-port = 3333 # combined with certificate authentication. #listen-clear-file = /var/run/ocserv-conn.socket +# Stats report time. The number of seconds after which each +# worker process will report its usage statistics (number of +# bytes transferred etc). This is useful when accounting like +# radius is in use. +#stats-report-time = 360 + # Keepalive in seconds keepalive = 32400 diff --git a/src/sec-mod.c b/src/sec-mod.c index 15ea8e84..4604d63f 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -249,6 +249,42 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return ret; + case SM_CMD_CLI_STATS:{ + CliStatsMsg *tmsg; + client_entry_st *e; + + tmsg = cli_stats_msg__unpack(&pa, data.size, data.data); + if (tmsg == NULL) { + seclog(sec, LOG_ERR, "error unpacking data"); + ret = ERR_BAD_COMMAND; + return -1; + } + + if (tmsg->has_sid == 0 || tmsg->sid.len != SID_SIZE) { + cli_stats_msg__free_unpacked(tmsg, &pa); + seclog(sec, LOG_INFO, "error in SID received by client (size: %d)", + (int)tmsg->sid.len); + return -1; + } + + e = find_client_entry(sec, tmsg->sid.data); + if (e == NULL) { + cli_stats_msg__free_unpacked(tmsg, &pa); + seclog(sec, LOG_INFO, "session stats received with non-existing sid!"); + return -1; + } + cli_stats_msg__free_unpacked(tmsg, &pa); + + if (e->status != PS_AUTH_COMPLETED) { + seclog(sec, LOG_ERR, "session stats received in unauthenticated client!"); + return -1; + } + + e->bytes_in = tmsg->bytes_in; + e->bytes_out = tmsg->bytes_out; + } + break; + case SM_CMD_AUTH_INIT:{ SecAuthInitMsg *auth_init; diff --git a/src/sec-mod.h b/src/sec-mod.h index 7cd5909f..a48dc448 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -52,6 +52,11 @@ typedef struct client_entry_st { unsigned have_session; /* whether an auth session is initialized */ unsigned tls_auth_ok; + /* these are filled in after the worker process dies, using the + * Cli stats message. */ + uint64_t bytes_in; + uint64_t bytes_out; + unsigned status; /* PS_AUTH_ */ char ip[MAX_IP_STR]; /* the user's IP */ diff --git a/src/vpn.h b/src/vpn.h index 5c70a4bc..5d134e39 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -123,6 +123,7 @@ typedef enum { SM_CMD_AUTH_SESSION_OPEN, SM_CMD_AUTH_SESSION_CLOSE, SM_CMD_AUTH_SESSION_REPLY, + SM_CMD_CLI_STATS, } cmd_request_t; #define MAX_IP_STR 46 @@ -193,6 +194,7 @@ struct cfg_st { unsigned int is_dyndns; char* unix_conn_file; unsigned int sup_config_type; /* one of SUP_CONFIG_ */ + unsigned int stats_report_time; char *pin_file; char *srk_pin_file; diff --git a/src/worker-auth.c b/src/worker-auth.c index d87aa977..d644b61e 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -641,7 +641,7 @@ static int recv_cookie_auth_reply(worker_st * ws) } /* returns the fd */ -static int connect_to_secmod(worker_st * ws) +int connect_to_secmod(worker_st * ws) { int sd, ret, e; @@ -667,16 +667,6 @@ static int connect_to_secmod(worker_st * ws) return sd; } -static -int send_msg_to_secmod(worker_st * ws, int sd, uint8_t cmd, - const void *msg, pack_size_func get_size, pack_func pack) -{ - oclog(ws, LOG_DEBUG, "sending message '%s' to secmod", - cmd_request_to_str(cmd)); - - return send_msg(ws, sd, cmd, msg, get_size, pack); -} - static int recv_auth_reply(worker_st * ws, int sd, char *txt, size_t max_txt_size) { diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 4cb5d99b..7fc1c5a8 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -992,6 +992,34 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now, } + if (ws->config->stats_report_time > 0 && + now - ws->last_stats_msg >= ws->config->stats_report_time && + ws->sid_set) { + CliStatsMsg msg = CLI_STATS_MSG__INIT; + int sd; + + ws->last_stats_msg = now; + + sd = connect_to_secmod(ws); + if (sd >= 0) { + msg.bytes_in = ws->tun_bytes_in; + msg.bytes_out = ws->tun_bytes_out; + msg.sid.len = sizeof(ws->sid); + msg.sid.data = ws->sid; + msg.has_sid = 1; + + send_msg_to_secmod(ws, sd, SM_CMD_CLI_STATS, &msg, + (pack_size_func)cli_stats_msg__get_packed_size, + (pack_func) cli_stats_msg__pack); + close(sd); + + oclog(ws, LOG_DEBUG, + "sending periodic stats (in: %lu, out: %lu) to sec-mod", + (unsigned long)msg.bytes_in, + (unsigned long)msg.bytes_out); + } + } + /* check DPD. Otherwise exit */ if (ws->udp_state == UP_ACTIVE && now - ws->last_msg_udp > DPD_TRIES * dpd && dpd > 0) { diff --git a/src/worker.h b/src/worker.h index f1f0c507..578eacd4 100644 --- a/src/worker.h +++ b/src/worker.h @@ -172,6 +172,9 @@ typedef struct worker_st { time_t last_tls_rehandshake; time_t last_dtls_rehandshake; + /* the time the last stats message was sent */ + time_t last_stats_msg; + /* for mtu trials */ unsigned last_good_mtu; unsigned last_bad_mtu; @@ -274,6 +277,17 @@ int handle_worker_commands(struct worker_st *ws); int disable_system_calls(struct worker_st *ws); void ocsigaltstack(struct worker_st *ws); +int connect_to_secmod(worker_st * ws); +inline static +int send_msg_to_secmod(worker_st * ws, int sd, uint8_t cmd, + const void *msg, pack_size_func get_size, pack_func pack) +{ + oclog(ws, LOG_DEBUG, "sending message '%s' to secmod", + cmd_request_to_str(cmd)); + + return send_msg(ws, sd, cmd, msg, get_size, pack); +} + inline static int send_msg_to_main(worker_st *ws, uint8_t cmd, const void* msg, pack_size_func get_size, pack_func pack) From 320773e80acb53d75f6852a088edb2614addb061 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 11:10:08 +0100 Subject: [PATCH 07/14] Added support for radius interim updates --- doc/sample.config | 6 +++ src/auth/pam.c | 2 +- src/auth/radius.c | 132 +++++++++++++++++++++++++++++++++++++++++---- src/auth/radius.h | 3 ++ src/common.c | 2 + src/sec-mod-auth.c | 33 +++++++++++- src/sec-mod-auth.h | 3 +- src/sec-mod.c | 24 +-------- src/sec-mod.h | 1 + 9 files changed, 171 insertions(+), 35 deletions(-) diff --git a/doc/sample.config b/doc/sample.config index 75649414..92217c57 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -59,6 +59,12 @@ max-same-clients = 2 # reconnects. #listen-host-is-dyndns = true +# Stats report time. The number of seconds after which each +# worker process will report its usage statistics (number of +# bytes transferred etc). This is useful when accounting like +# radius is in use. +#stats-report-time = 360 + # TCP and UDP port number tcp-port = 443 udp-port = 443 diff --git a/src/auth/pam.c b/src/auth/pam.c index 96016f78..27a26218 100644 --- a/src/auth/pam.c +++ b/src/auth/pam.c @@ -348,7 +348,7 @@ struct pam_ctx_st * pctx = ctx; talloc_free(pctx); } -static int pam_auth_open_session(void* ctx) +static int pam_auth_open_session(void* ctx, const void *sid, unsigned sid_size) { struct pam_ctx_st * pctx = ctx; int pret; diff --git a/src/auth/radius.c b/src/auth/radius.c index b3f12a81..fd6cd838 100644 --- a/src/auth/radius.c +++ b/src/auth/radius.c @@ -149,7 +149,8 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) syslog(LOG_ERR, "%s:%u: user '%s' auth error", __func__, __LINE__, pctx->username); - return ERR_AUTH_FAIL; + ret = ERR_AUTH_FAIL; + goto cleanup; } service = PW_AUTHENTICATE_ONLY; @@ -157,7 +158,8 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) syslog(LOG_ERR, "%s:%u: user '%s' auth error", __func__, __LINE__, pctx->username); - return ERR_AUTH_FAIL; + ret = ERR_AUTH_FAIL; + goto cleanup; } ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCESS_REQUEST); @@ -207,18 +209,24 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len) vp = vp->next; } + ret = 0; + cleanup: + rc_avpair_free(send); if (recvd != NULL) rc_avpair_free(recvd); - return 0; + return ret; } else { fail: + if (send != NULL) + rc_avpair_free(send); + if (recvd != NULL) rc_avpair_free(recvd); if (ret == PW_ACCESS_CHALLENGE) { pctx->pass_msg = pass_msg_second; return ERR_AUTH_CONTINUE; - } else if ( pctx->retries++ < MAX_TRIES) { + } else if (pctx->retries++ < MAX_TRIES) { pctx->pass_msg = pass_msg_failed; return ERR_AUTH_CONTINUE; } else { @@ -245,7 +253,74 @@ static void radius_auth_deinit(void *ctx) } -static int radius_auth_open_session(void* ctx) +static void radius_auth_session_stats(void* ctx, uint64_t bytes_in, uint64_t bytes_out) +{ +struct radius_ctx_st * pctx = ctx; +int ret; +uint32_t status_type; +VALUE_PAIR *send = NULL, *recvd = NULL; +uint32_t uin, uout; + + status_type = PW_STATUS_ALIVE; + + syslog(LOG_DEBUG, "sending radius session interim update"); + + if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + uin = bytes_in; + uout = bytes_out; + + if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + uin = bytes_in / 4294967296; + if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + uout = bytes_in / 4294967296; + if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST); + + if (recvd != NULL) + rc_avpair_free(recvd); + + if (ret != OK_RC) { + syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret); + goto cleanup; + } + + cleanup: + rc_avpair_free(send); + return; +} + +static int radius_auth_open_session(void* ctx, const void *sid, unsigned sid_size) { struct radius_ctx_st * pctx = ctx; int ret; @@ -254,20 +329,45 @@ VALUE_PAIR *send = NULL, *recvd = NULL; status_type = PW_STATUS_START; - syslog(LOG_DEBUG, "opening session with radius"); - if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) + if (sid_size != SID_SIZE) { + syslog(LOG_DEBUG, "incorrect sid size"); return -1; + } + + base64_encode((char *)sid, sid_size, (char *)pctx->sid, sizeof(pctx->sid)); + + syslog(LOG_DEBUG, "opening session %s with radius", pctx->sid); + + if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) { + ret = -1; + goto cleanup; + } ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST); + if (recvd != NULL) rc_avpair_free(recvd); if (ret != OK_RC) { syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret); - return -1; + ret = -1; + goto cleanup; } - return 0; + ret = 0; + cleanup: + rc_avpair_free(send); + return ret; } static void radius_auth_close_session(void* ctx) @@ -283,15 +383,26 @@ VALUE_PAIR *send = NULL, *recvd = NULL; if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) return; + if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) { + goto cleanup; + } + + if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) { + goto cleanup; + } + + ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST); if (recvd != NULL) rc_avpair_free(recvd); if (ret != OK_RC) { syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret); - return; + goto cleanup; } + cleanup: + rc_avpair_free(send); return; } @@ -307,6 +418,7 @@ const struct auth_mod_st radius_auth_funcs = { .auth_group = radius_auth_group, .open_session = radius_auth_open_session, .close_session = radius_auth_close_session, + .session_stats = radius_auth_session_stats, .group_list = NULL }; diff --git a/src/auth/radius.h b/src/auth/radius.h index b98ac823..586aa387 100644 --- a/src/auth/radius.h +++ b/src/auth/radius.h @@ -22,10 +22,13 @@ #define RADIUS_H #include +#include struct radius_ctx_st { char username[MAX_USERNAME_SIZE*2]; char groupname[MAX_GROUPNAME_SIZE]; + char sid[BASE64_LENGTH(SID_SIZE) + 1]; + char msg[4096]; /* variables for configuration */ diff --git a/src/common.c b/src/common.c index 0d251fa6..e8213b1c 100644 --- a/src/common.c +++ b/src/common.c @@ -56,6 +56,8 @@ static char tmp[32]; case CMD_CLI_STATS: return "cli stats"; + case SM_CMD_CLI_STATS: + return "sm: cli stats"; case SM_CMD_AUTH_INIT: return "sm: auth init"; case SM_CMD_AUTH_CONT: diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 887c6614..9c158b1b 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -327,7 +327,7 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, if (module == NULL || module->open_session == NULL) return 0; - ret = module->open_session(e->auth_ctx); + ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len); if (ret < 0) { e->status = PS_AUTH_FAILED; seclog(sec, LOG_ERR, "could not open session."); @@ -342,6 +342,37 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, return 0; } +int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req) +{ + client_entry_st *e; + + if (req->sid.len != SID_SIZE) { + seclog(sec, LOG_ERR, "auth session open/close but with illegal sid size (%d)!", + (int)req->sid.len); + return -1; + } + + e = find_client_entry(sec, req->sid.data); + if (e == NULL) { + seclog(sec, LOG_INFO, "session open/close but with non-existing sid!"); + return -1; + } + + if (e->status != PS_AUTH_COMPLETED) { + seclog(sec, LOG_ERR, "session stats received in unauthenticated client!"); + return -1; + } + + e->bytes_in = req->bytes_in; + e->bytes_out = req->bytes_out; + + if (module == NULL || module->session_stats == NULL) + return 0; + + module->session_stats(e->auth_ctx, e->bytes_in, e->bytes_out); + return 0; +} + int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req) { client_entry_st *e; diff --git a/src/sec-mod-auth.h b/src/sec-mod-auth.h index 3bc5a1f0..f95cf679 100644 --- a/src/sec-mod-auth.h +++ b/src/sec-mod-auth.h @@ -36,7 +36,8 @@ struct auth_mod_st { int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size); int (*auth_user)(void* ctx, char *groupname, int groupname_size); - int (*open_session)(void *ctx); /* optional, may be null */ + int (*open_session)(void *ctx, const void *sid, unsigned sid_size); /* optional, may be null */ + void (*session_stats)(void *ctx, uint64_t bytes_in, uint64_t bytes_out); /* optional, may be null */ void (*close_session)(void *ctx); /* optional */ void (*auth_deinit)(void* ctx); diff --git a/src/sec-mod.c b/src/sec-mod.c index 4604d63f..d404e569 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -251,7 +251,6 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, case SM_CMD_CLI_STATS:{ CliStatsMsg *tmsg; - client_entry_st *e; tmsg = cli_stats_msg__unpack(&pa, data.size, data.data); if (tmsg == NULL) { @@ -260,28 +259,9 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - if (tmsg->has_sid == 0 || tmsg->sid.len != SID_SIZE) { - cli_stats_msg__free_unpacked(tmsg, &pa); - seclog(sec, LOG_INFO, "error in SID received by client (size: %d)", - (int)tmsg->sid.len); - return -1; - } - - e = find_client_entry(sec, tmsg->sid.data); - if (e == NULL) { - cli_stats_msg__free_unpacked(tmsg, &pa); - seclog(sec, LOG_INFO, "session stats received with non-existing sid!"); - return -1; - } + ret = handle_sec_auth_stats_cmd(sec, tmsg); cli_stats_msg__free_unpacked(tmsg, &pa); - - if (e->status != PS_AUTH_COMPLETED) { - seclog(sec, LOG_ERR, "session stats received in unauthenticated client!"); - return -1; - } - - e->bytes_in = tmsg->bytes_in; - e->bytes_out = tmsg->bytes_out; + return ret; } break; diff --git a/src/sec-mod.h b/src/sec-mod.h index a48dc448..96ae66bd 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -96,6 +96,7 @@ void sec_auth_init(void *pool, struct cfg_st *config); int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req); int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req); int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd, client_entry_st **_e); +int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req); void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e); void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file, From c1deee1fb5b02e42efb20907b3d1fca980fa2584 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 11:22:22 +0100 Subject: [PATCH 08/14] updated todo list --- TODO | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 397d3cba..f9d2adeb 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,7 @@ Short term items: -* Enhance the current accounting modules to allow, native radius support - with real-time accounting (e.g., sending periodically the transferred - bytes). Use radius for testing it. +* Use the UDP address to report the client's IP when sniproxy or haproxy + are being used. * When a user (IP) gets into the BAN list multiple times, disable it for longer time (or should we drop this functionality altogether and rely From 93125ea945fe3ce836a394dcca94c4c57bb1262d Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 11:46:17 +0100 Subject: [PATCH 09/14] updated documentation on radius --- README | 3 +++ doc/sample.config | 7 ++++++- src/ocserv-args.def | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README b/README index c4d60ff2..e62720c2 100644 --- a/README +++ b/README @@ -30,6 +30,9 @@ libopts25-dev / autogen-libopts-devel autogen / autogen +For radius support the freeradius-client library is required. Currently +(2014-12-10) the best would be to use the version from the git repository +at: https://github.com/FreeRADIUS/freeradius-client === Build instructions === diff --git a/doc/sample.config b/doc/sample.config index 92217c57..68733db6 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -22,7 +22,12 @@ auth = "plain[./sample.passwd]" # to generate password entries. #auth = "plain[/etc/ocserv/ocpasswd]" -# User authentication using radius. +# The radius option requires specifying freeradius-client configuration +# file. If the groupconfig option is set, then config-per-user will be overriden, +# and all configuration will be read from radius. The supported atributes for +# radius configuration are: +# Group-Name, Framed-IPv6-Address, DNS-Server-IPv6-Address, Framed-IP-Address, +# Framed-IP-Netmask, MS-Primary-DNS-Server, MS-Secondary-DNS-Server #auth = "radius[/usr/local/etc/radiusclient/radiusclient.conf,groupconfig]" # Whether to enable seccomp worker isolation. That restricts the number of diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 0c8f8b24..5beffa02 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -98,7 +98,10 @@ An example configuration file follows. # The radius option requires specifying freeradius-client configuration # file. If the groupconfig option is set, then config-per-user will be overriden, -# and all configuration will be read from radius. +# and all configuration will be read from radius. The supported atributes for +# radius configuration are: +# Group-Name, Framed-IPv6-Address, DNS-Server-IPv6-Address, Framed-IP-Address, +# Framed-IP-Netmask, MS-Primary-DNS-Server, MS-Secondary-DNS-Server #auth = "radius[/etc/radiusclient/radiusclient.conf,groupconfig]" # Whether to enable seccomp worker isolation. That restricts the number of From 54e6450807318e0309c96d30d756849ab405f545 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 13:24:42 +0100 Subject: [PATCH 10/14] sec-mod: separated request serving from main loop --- src/sec-mod-auth.c | 2 - src/sec-mod.c | 110 ++++++++++++++++++++++++--------------------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 9c158b1b..f80bec85 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -103,7 +103,6 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) { SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT; int ret; - void *pool = NULL; if (r == AUTH__REP__OK) { /* fill message */ @@ -133,7 +132,6 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) (pack_size_func) sec_auth_reply_msg__get_packed_size, (pack_func) sec_auth_reply_msg__pack); - talloc_free(pool); } else { msg.reply = AUTH__REP__FAILED; diff --git a/src/sec-mod.c b/src/sec-mod.c index d404e569..c31d0120 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -405,6 +405,55 @@ static void check_other_work(sec_mod_st *sec) } } +/* serves a new requst. + * the provided buffer is also pool for other allocations */ +static +void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigned buffer_size) +{ + int ret, e; + unsigned cmd, length; + uint16_t l16; + + /* read request */ + ret = force_read_timeout(cfd, buffer, 3, MAX_WAIT_SECS); + if (ret == 0) + goto leave; + else if (ret < 3) { + e = errno; + seclog(sec, LOG_INFO, "error receiving msg head: %s", + strerror(e)); + goto leave; + } + + cmd = buffer[0]; + memcpy(&l16, &buffer[1], 2); + length = l16; + + if (length > buffer_size - 4) { + seclog(sec, LOG_INFO, "too big message (%d)", length); + goto leave; + } + + /* read the body */ + ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS); + if (ret < 0) { + e = errno; + seclog(sec, LOG_INFO, "error receiving msg body: %s", + strerror(e)); + goto leave; + } + + sec->fd = cfd; + ret = process_packet(buffer, sec, cmd, uid, buffer, ret); + if (ret < 0) { + seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret); + } + + leave: + close(cfd); + return; +} + /* sec_mod_server: * @config: server configuration * @socket_file: the name of the socket @@ -438,11 +487,9 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f struct sockaddr_un sa; socklen_t sa_len; int cfd, ret, e; - unsigned cmd, length; unsigned i, buffer_size; uid_t uid; - uint8_t *buffer, *tpool; - uint16_t l16; + uint8_t *buffer; struct pin_st pins; int sd; sec_mod_st *sec; @@ -506,13 +553,6 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f if (config->min_reauth_time > 0) sec_mod_ban_db_init(sec); - buffer_size = 8 * 1024; - buffer = talloc_size(sec, buffer_size); - if (buffer == NULL) { - seclog(sec, LOG_ERR, "error in memory allocation"); - exit(1); - } - sd = socket(AF_UNIX, SOCK_STREAM, 0); if (sd == -1) { @@ -614,50 +654,18 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f ret = check_upeer_id("sec-mod", cfd, config->uid, config->gid, &uid); if (ret < 0) { seclog(sec, LOG_INFO, "rejected unauthorized connection"); - goto cont; + } else { + buffer_size = 8 * 1024; + buffer = talloc_size(sec, buffer_size); + if (buffer == NULL) { + seclog(sec, LOG_ERR, "error in memory allocation"); + close(cfd); + } else { + serve_request(sec, uid, cfd, buffer, buffer_size); + } } - - /* read request */ - ret = force_read_timeout(cfd, buffer, 3, MAX_WAIT_SECS); - if (ret == 0) - goto cont; - else if (ret < 3) { - e = errno; - seclog(sec, LOG_INFO, "error receiving msg head: %s", - strerror(e)); - goto cont; - } - - cmd = buffer[0]; - memcpy(&l16, &buffer[1], 2); - length = l16; - - if (length > buffer_size - 4) { - seclog(sec, LOG_INFO, "too big message (%d)", length); - goto cont; - } - - /* read the body */ - ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS); - if (ret < 0) { - e = errno; - seclog(sec, LOG_INFO, "error receiving msg body: %s", - strerror(e)); - goto cont; - } - - tpool = talloc_new(sec); - sec->fd = cfd; - ret = process_packet(tpool, sec, cmd, uid, buffer, ret); - if (ret < 0) { - seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret); - } - talloc_free(tpool); - #ifdef DEBUG_LEAKS talloc_report_full(sec, stderr); #endif - cont: - close(cfd); } } From 0551338a7a861900acf4c34c89f4cac78fc71ac8 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 13:48:45 +0100 Subject: [PATCH 11/14] sec-mod: preparations for thread safety --- src/sec-mod-auth.c | 61 +++++++++++++++++++++++++++++++--------------- src/sec-mod.c | 53 ++++++++-------------------------------- src/sec-mod.h | 8 +++--- 3 files changed, 54 insertions(+), 68 deletions(-) diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index f80bec85..d39ec751 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -99,7 +99,7 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry) } static -int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) +int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTHREP r) { SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT; int ret; @@ -127,7 +127,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) msg.dtls_session_id.data = entry->dtls_session_id; msg.dtls_session_id.len = sizeof(entry->dtls_session_id); - ret = send_msg(entry, sec->fd, SM_CMD_AUTH_REP, + ret = send_msg(entry, cfd, SM_CMD_AUTH_REP, &msg, (pack_size_func) sec_auth_reply_msg__get_packed_size, @@ -135,7 +135,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) } else { msg.reply = AUTH__REP__FAILED; - ret = send_msg(entry, sec->fd, SM_CMD_AUTH_REP, + ret = send_msg(entry, cfd, SM_CMD_AUTH_REP, &msg, (pack_size_func) sec_auth_reply_msg__get_packed_size, @@ -152,7 +152,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r) } static -int send_sec_auth_reply_msg(sec_mod_st * sec, client_entry_st * e) +int send_sec_auth_reply_msg(int cfd, sec_mod_st * sec, client_entry_st * e) { SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT; char tmp[MAX_MSG_SIZE] = ""; @@ -173,7 +173,7 @@ int send_sec_auth_reply_msg(sec_mod_st * sec, client_entry_st * e) msg.sid.data = e->sid; msg.sid.len = sizeof(e->sid); - ret = send_msg(e, sec->fd, SM_CMD_AUTH_REP, &msg, + ret = send_msg(e, cfd, SM_CMD_AUTH_REP, &msg, (pack_size_func) sec_auth_reply_msg__get_packed_size, (pack_func) sec_auth_reply_msg__pack); if (ret < 0) { @@ -253,12 +253,12 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e, * @result: the auth result */ static -int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) +int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int result) { int ret; if (result == ERR_AUTH_CONTINUE) { - ret = send_sec_auth_reply_msg(sec, e); + ret = send_sec_auth_reply_msg(cfd, sec, e); if (ret < 0) { e->status = PS_AUTH_FAILED; seclog(sec, LOG_ERR, "could not send reply auth cmd."); @@ -268,7 +268,7 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) } else if (result == 0) { e->status = PS_AUTH_COMPLETED; - ret = send_sec_auth_reply(sec, e, AUTH__REP__OK); + ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__OK); if (ret < 0) { e->status = PS_AUTH_FAILED; seclog(sec, LOG_ERR, "could not send reply auth cmd."); @@ -280,7 +280,7 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) e->status = PS_AUTH_FAILED; add_ip_to_ban_list(sec, e->ip, time(0) + sec->config->min_reauth_time); - ret = send_sec_auth_reply(sec, e, AUTH__REP__FAILED); + ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED); if (ret < 0) { seclog(sec, LOG_ERR, "could not send reply auth cmd."); return ret; @@ -299,10 +299,11 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result) /* opens or closes a session. */ -int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, - unsigned cmd, client_entry_st **r_entry) +int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionMsg * req, + unsigned cmd) { client_entry_st *e; + void *lpool; int ret; if (req->sid.len != SID_SIZE) { @@ -318,9 +319,7 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, } if (cmd == SM_CMD_AUTH_SESSION_OPEN) { - if (r_entry) { - *r_entry = e; - } + SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT; if (module == NULL || module->open_session == NULL) return 0; @@ -330,9 +329,31 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, e->status = PS_AUTH_FAILED; seclog(sec, LOG_ERR, "could not open session."); del_client_entry(sec, e); - return ret; + rep.reply = AUTH__REP__FAILED; + } else { + e->have_session = 1; + rep.reply = AUTH__REP__OK; } - e->have_session = 1; + + lpool = talloc_new(e); + if (lpool == NULL) { + return ERR_MEM; + } + + ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool); + if (ret < 0) { + seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username); + talloc_free(lpool); + return ERR_READ_CONFIG; + } + + ret = send_msg(lpool, cfd, SM_CMD_AUTH_SESSION_REPLY, &rep, + (pack_size_func) sec_auth_session_reply_msg__get_packed_size, + (pack_func) sec_auth_session_reply_msg__pack); + if (ret < 0) { + seclog(sec, LOG_WARNING, "sec-mod error in sending session reply"); + } + talloc_free(lpool); } else { del_client_entry(sec, e); } @@ -371,7 +392,7 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req) return 0; } -int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req) +int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req) { client_entry_st *e; int ret; @@ -416,10 +437,10 @@ int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req) e->username); } - return handle_sec_auth_res(sec, e, ret); + return handle_sec_auth_res(cfd, sec, e, ret); } -int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req) +int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req) { int ret = -1; client_entry_st *e; @@ -513,7 +534,7 @@ int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req) ret = 0; cleanup: - return handle_sec_auth_res(sec, e, ret); + return handle_sec_auth_res(cfd, sec, e, ret); } void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e) diff --git a/src/sec-mod.c b/src/sec-mod.c index c31d0120..9b3015dc 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -167,7 +167,7 @@ int load_pins(struct cfg_st *config, struct pin_st *s) return 0; } -static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep, +static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_t * rep, size_t rep_size) { SecOpMsg msg = SEC_OP_MSG__INIT; @@ -176,7 +176,7 @@ static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep, msg.data.data = rep; msg.data.len = rep_size; - ret = send_msg(pool, sec->fd, type, &msg, + ret = send_msg(pool, cfd, type, &msg, (pack_size_func) sec_op_msg__get_packed_size, (pack_func) sec_op_msg__pack); if (ret < 0) { @@ -187,7 +187,7 @@ static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep, } static -int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, +int process_packet(void *pool, int cfd, sec_mod_st * sec, cmd_request_t cmd, uid_t uid, uint8_t * buffer, size_t buffer_size) { unsigned i; @@ -244,7 +244,7 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - ret = handle_op(pool, sec, cmd, out.data, out.size); + ret = handle_op(pool, cfd, sec, cmd, out.data, out.size); gnutls_free(out.data); return ret; @@ -276,7 +276,7 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - ret = handle_sec_auth_init(sec, auth_init); + ret = handle_sec_auth_init(cfd, sec, auth_init); sec_auth_init_msg__free_unpacked(auth_init, &pa); return ret; } @@ -291,16 +291,13 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - ret = handle_sec_auth_cont(sec, auth_cont); + ret = handle_sec_auth_cont(cfd, sec, auth_cont); sec_auth_cont_msg__free_unpacked(auth_cont, &pa); return ret; } case SM_CMD_AUTH_SESSION_OPEN: case SM_CMD_AUTH_SESSION_CLOSE:{ SecAuthSessionMsg *msg; - void *lpool = NULL; - SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT; - client_entry_st *e = NULL; if (uid != 0) { seclog(sec, LOG_INFO, "received session open/close from unauthorized uid (%u)\n", (unsigned)uid); @@ -315,38 +312,9 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd, return -1; } - ret = handle_sec_auth_session_cmd(sec, msg, cmd, &e); + ret = handle_sec_auth_session_cmd(cfd, sec, msg, cmd); sec_auth_session_msg__free_unpacked(msg, &pa); - if (cmd == SM_CMD_AUTH_SESSION_OPEN) { - if (ret < 0 || e == NULL) - rep.reply = AUTH__REP__FAILED; - else - rep.reply = AUTH__REP__OK; - - if (sec->config_module && e != NULL) { - lpool = talloc_new(e); - if (lpool == NULL) { - return ERR_MEM; - } - - ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool); - if (ret < 0) { - seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username); - talloc_free(lpool); - return ERR_READ_CONFIG; - } - } - - ret = send_msg(pool, sec->fd, SM_CMD_AUTH_SESSION_REPLY, &rep, - (pack_size_func) sec_auth_session_reply_msg__get_packed_size, - (pack_func) sec_auth_session_reply_msg__pack); - if (ret < 0) { - seclog(sec, LOG_WARNING, "sec-mod error in sending session reply"); - } - talloc_free(lpool); - } - return ret; } default: @@ -405,14 +373,13 @@ static void check_other_work(sec_mod_st *sec) } } -/* serves a new requst. - * the provided buffer is also pool for other allocations */ static void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigned buffer_size) { int ret, e; unsigned cmd, length; uint16_t l16; + void *pool = buffer; /* read request */ ret = force_read_timeout(cfd, buffer, 3, MAX_WAIT_SECS); @@ -443,13 +410,13 @@ void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigne goto leave; } - sec->fd = cfd; - ret = process_packet(buffer, sec, cmd, uid, buffer, ret); + ret = process_packet(pool, cfd, sec, cmd, uid, buffer, ret); if (ret < 0) { seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret); } leave: + talloc_free(pool); close(cfd); return; } diff --git a/src/sec-mod.h b/src/sec-mod.h index 96ae66bd..cbc7a75e 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -36,8 +36,6 @@ typedef struct sec_mod_st { struct htable *ban_db; struct config_mod_st *config_module; - - int fd; } sec_mod_st; @@ -93,9 +91,9 @@ void cleanup_client_entries(sec_mod_st *sec); void sec_auth_init(void *pool, struct cfg_st *config); -int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req); -int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req); -int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd, client_entry_st **_e); +int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg * req); +int handle_sec_auth_cont(int cfd, sec_mod_st *sec, const SecAuthContMsg * req); +int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMsg *req, unsigned cmd); int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req); void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e); From c8a2666fa7fc4b729eac9bb2f18cdbeb7c109155 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 14:15:37 +0100 Subject: [PATCH 12/14] avoid crash when no auth module is in use --- src/sec-mod-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index d39ec751..1b7fd0a9 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -57,7 +57,7 @@ void sec_auth_init(void *pool, struct cfg_st *config) { module = get_auth_mod(); - if (module->global_init) { + if (module && module->global_init) { module->global_init(pool, config->auth_additional); } } From c15a7befbbd8a77c3bfe0ef5b3ce1403b552ba0e Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 15:10:25 +0100 Subject: [PATCH 13/14] sec-mod: always reply on open-session cmd --- src/sec-mod-auth.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 1b7fd0a9..ebae25d5 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -321,17 +321,18 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionM if (cmd == SM_CMD_AUTH_SESSION_OPEN) { SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT; - if (module == NULL || module->open_session == NULL) - return 0; - - ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len); - if (ret < 0) { - e->status = PS_AUTH_FAILED; - seclog(sec, LOG_ERR, "could not open session."); - del_client_entry(sec, e); - rep.reply = AUTH__REP__FAILED; + if (module != NULL && module->open_session != NULL) { + ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len); + if (ret < 0) { + e->status = PS_AUTH_FAILED; + seclog(sec, LOG_ERR, "could not open session."); + del_client_entry(sec, e); + rep.reply = AUTH__REP__FAILED; + } else { + e->have_session = 1; + rep.reply = AUTH__REP__OK; + } } else { - e->have_session = 1; rep.reply = AUTH__REP__OK; } @@ -340,11 +341,13 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionM return ERR_MEM; } - ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool); - if (ret < 0) { - seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username); - talloc_free(lpool); - return ERR_READ_CONFIG; + if (sec->config_module && sec->config_module->get_sup_config) { + ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool); + if (ret < 0) { + seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username); + talloc_free(lpool); + return ERR_READ_CONFIG; + } } ret = send_msg(lpool, cfd, SM_CMD_AUTH_SESSION_REPLY, &rep, From 065753bd573f688e514e22b163e273103b6d2ad4 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 10 Dec 2014 15:28:11 +0100 Subject: [PATCH 14/14] undid ed5b177691d52c1c5417ef802854e26c9dd5d4f4 It is not currently possible to reload only a part of the configuration. If the back-end module changes, the server will bail out instead. --- src/config.c | 133 ++++++++++++++++++++++----------------------- src/sec-mod-auth.c | 14 ++++- src/sec-mod.c | 1 + src/sec-mod.h | 3 +- 4 files changed, 80 insertions(+), 71 deletions(-) diff --git a/src/config.c b/src/config.c index 90935722..bcf18e07 100644 --- a/src/config.c +++ b/src/config.c @@ -407,79 +407,75 @@ unsigned force_cert_auth; prev = val; } while((val = optionNextValue(pov, prev)) != NULL); - /* authentication information is only read on first load, as - * it cannot be safely switched */ - if (reload == 0) { - config->sup_config_type = SUP_CONFIG_FILE; + config->sup_config_type = SUP_CONFIG_FILE; - READ_MULTI_LINE("auth", auth, auth_size); - for (j=0;jauth_additional = get_brackets_string(config, auth[j]+3); - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } -#ifdef HAVE_PAM - config->auth_types |= amod->type; - amod = &pam_auth_funcs; -#else - fprintf(stderr, "PAM support is disabled\n"); - exit(1); -#endif - } else if (strncasecmp(auth[j], "plain", 5) == 0) { - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } - - config->auth_additional = get_brackets_string(config, auth[j]+5); - if (config->auth_additional == NULL) { - fprintf(stderr, "Format error in %s\n", auth[j]); - exit(1); - } - amod = &plain_auth_funcs; - config->auth_types |= amod->type; - } else if (strncasecmp(auth[j], "radius", 6) == 0) { - const char *p; - if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { - fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); - exit(1); - } - -#ifdef HAVE_RADIUS - config->auth_additional = get_brackets_string1(config, auth[j]+6); - if (config->auth_additional == NULL) { - fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); - exit(1); - } - - p = get_brackets_string2(config, auth[j]+6); - if (p != NULL) { - if (strcasecmp(p, "groupconfig") != 0) { - fprintf(stderr, "No known configuration option: %s\n", p); - exit(1); - } - config->sup_config_type = SUP_CONFIG_RADIUS; - } - amod = &radius_auth_funcs; - config->auth_types |= amod->type; -#else - fprintf(stderr, "Radius support is disabled\n"); - exit(1); -#endif - } else if (c_strcasecmp(auth[j], "certificate") == 0) { - config->auth_types |= AUTH_TYPE_CERTIFICATE; - } else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) { - config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT; - } else { - fprintf(stderr, "Unknown auth method: %s\n", auth[j]); + READ_MULTI_LINE("auth", auth, auth_size); + for (j=0;jauth_additional = get_brackets_string(config, auth[j]+3); + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); exit(1); } - talloc_free(auth[j]); +#ifdef HAVE_PAM + config->auth_types |= amod->type; + amod = &pam_auth_funcs; +#else + fprintf(stderr, "PAM support is disabled\n"); + exit(1); +#endif + } else if (strncasecmp(auth[j], "plain", 5) == 0) { + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); + exit(1); + } + + config->auth_additional = get_brackets_string(config, auth[j]+5); + if (config->auth_additional == NULL) { + fprintf(stderr, "Format error in %s\n", auth[j]); + exit(1); + } + amod = &plain_auth_funcs; + config->auth_types |= amod->type; + } else if (strncasecmp(auth[j], "radius", 6) == 0) { + const char *p; + if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) { + fprintf(stderr, "You cannot mix multiple username/password authentication methods\n"); + exit(1); + } + +#ifdef HAVE_RADIUS + config->auth_additional = get_brackets_string1(config, auth[j]+6); + if (config->auth_additional == NULL) { + fprintf(stderr, "No configuration specified; error in %s\n", auth[j]); + exit(1); + } + + p = get_brackets_string2(config, auth[j]+6); + if (p != NULL) { + if (strcasecmp(p, "groupconfig") != 0) { + fprintf(stderr, "No known configuration option: %s\n", p); + exit(1); + } + config->sup_config_type = SUP_CONFIG_RADIUS; + } + amod = &radius_auth_funcs; + config->auth_types |= amod->type; +#else + fprintf(stderr, "Radius support is disabled\n"); + exit(1); +#endif + } else if (c_strcasecmp(auth[j], "certificate") == 0) { + config->auth_types |= AUTH_TYPE_CERTIFICATE; + } else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) { + config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT; + } else { + fprintf(stderr, "Unknown auth method: %s\n", auth[j]); + exit(1); } - talloc_free(auth); + talloc_free(auth[j]); } + talloc_free(auth); /* When adding allocated data, remember to modify * reload_cfg_file(); @@ -931,6 +927,7 @@ void print_version(tOptions *opts, tOptDesc *desc) void reload_cfg_file(void *pool, struct cfg_st* config) { clear_cfg_file(config); + memset(config, 0, sizeof(*config)); parse_cfg_file(cfg_file, config, 1); diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index ebae25d5..b740f247 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -53,12 +53,22 @@ static const struct auth_mod_st *module = NULL; -void sec_auth_init(void *pool, struct cfg_st *config) +void sec_auth_init(sec_mod_st * sec, struct cfg_st *config) { module = get_auth_mod(); if (module && module->global_init) { - module->global_init(pool, config->auth_additional); + module->global_init(sec, config->auth_additional); + } +} + +void sec_auth_reinit(sec_mod_st * sec, struct cfg_st *config) +{ + if (module) { + if (module != get_auth_mod()) { + seclog(sec, LOG_ERR, "Cannot change authentication method on reload"); + exit(1); + } } } diff --git a/src/sec-mod.c b/src/sec-mod.c index 9b3015dc..da4e1559 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -358,6 +358,7 @@ static void check_other_work(sec_mod_st *sec) if (need_reload) { seclog(sec, LOG_DEBUG, "reloading configuration"); reload_cfg_file(sec, sec->config); + sec_auth_reinit(sec, sec->config); need_reload = 0; } diff --git a/src/sec-mod.h b/src/sec-mod.h index cbc7a75e..45fc2d4d 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -89,7 +89,8 @@ void cleanup_client_entries(sec_mod_st *sec); } #endif -void sec_auth_init(void *pool, struct cfg_st *config); +void sec_auth_init(sec_mod_st *sec, struct cfg_st *config); +void sec_auth_reinit(sec_mod_st *sec, struct cfg_st *config); int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg * req); int handle_sec_auth_cont(int cfd, sec_mod_st *sec, const SecAuthContMsg * req);