Added reference counting to configuration values.

That is, to allow referencing to these values from proc_st
without fearing of them being invalidated on a config reload. We
perform a cleanup of these values on the server periodic check.
This commit is contained in:
Nikos Mavrogiannopoulos
2015-12-03 14:58:34 +01:00
committed by Nikos Mavrogiannopoulos
parent 2e68ba1158
commit 9252e22298
12 changed files with 119 additions and 95 deletions

View File

@@ -61,6 +61,8 @@
static char pid_file[_POSIX_PATH_MAX] = "";
static char cfg_file[_POSIX_PATH_MAX] = DEFAULT_CFG_FILE;
static void archive_cfg(struct perm_cfg_st* perm_config);
struct cfg_options {
const char* name;
unsigned type;
@@ -740,6 +742,21 @@ size_t urlfw_size = 0;
perm_config->occtl_socket_file = talloc_strdup(perm_config, OCCTL_UNIX_SOCKET);
PREAD_STRING(perm_config, "chroot-dir", perm_config->chroot_dir);
list_head_init(&perm_config->attic);
}
perm_config->config = talloc_zero(perm_config, struct cfg_st);
if (perm_config->config == NULL)
exit(1);
config = perm_config->config;
pool = config;
config->usage_count = talloc_zero(config, int);
if (config->usage_count == NULL) {
fprintf(stderr, "memory error\n");
exit(1);
}
/* When adding allocated data, remember to modify
@@ -1145,21 +1162,17 @@ int cmd_parser (void *pool, int argc, char **argv, struct perm_cfg_st** config)
if (*config == NULL)
exit(1);
(*config)->config = talloc_zero(*config, struct cfg_st);
if ((*config)->config == NULL)
exit(1);
optionProcess( &ocservOptions, argc, argv);
if (HAVE_OPT(FOREGROUND))
(*config)->config->foreground = 1;
(*config)->foreground = 1;
if (HAVE_OPT(PID_FILE)) {
strlcpy(pid_file, OPT_ARG(PID_FILE), sizeof(pid_file));
}
if (HAVE_OPT(DEBUG))
(*config)->config->debug = OPT_VALUE_DEBUG;
(*config)->debug = OPT_VALUE_DEBUG;
if (HAVE_OPT(CONFIG)) {
strlcpy(cfg_file, OPT_ARG(CONFIG), sizeof(cfg_file));
@@ -1176,70 +1189,40 @@ int cmd_parser (void *pool, int argc, char **argv, struct perm_cfg_st** config)
}
#define DEL(x) {talloc_free(x);x=NULL;}
static void archive_cfg(struct perm_cfg_st* perm_config)
{
attic_entry_st *e;
/* we don't clear anything as it may be referenced by some
* client (proc_st). We move everything to attic and
* once nothing is in use we clear that */
e = talloc(perm_config, attic_entry_st);
if (e == NULL) {
/* we leak, but better than crashing */
return;
}
e->usage_count = perm_config->config->usage_count;
/* we rely on talloc doing that recursively */
talloc_steal(e, perm_config->config);
perm_config->config = NULL;
if (e->usage_count == NULL || *e->usage_count == 0) {
talloc_free(e);
} else {
list_add(&perm_config->attic, &e->list);
}
return;
}
void clear_cfg(struct perm_cfg_st* perm_config)
{
unsigned i;
#ifdef ANYCONNECT_CLIENT_COMPAT
DEL(perm_config->config->xml_config_file);
DEL(perm_config->config->xml_config_hash);
#endif
DEL(perm_config->config->cgroup);
DEL(perm_config->config->route_add_cmd);
DEL(perm_config->config->route_del_cmd);
DEL(perm_config->config->per_user_dir);
DEL(perm_config->config->per_group_dir);
DEL(perm_config->config->default_domain);
DEL(perm_config->config->ocsp_response);
DEL(perm_config->config->banner);
DEL(perm_config->config->crl);
DEL(perm_config->config->cert_user_oid);
DEL(perm_config->config->cert_group_oid);
DEL(perm_config->config->priorities);
DEL(perm_config->config->connect_script);
DEL(perm_config->config->disconnect_script);
DEL(perm_config->config->proxy_url);
#ifdef HAVE_GSSAPI
for (i=0;i<perm_config->config->kkdcp_size;i++) {
unsigned j;
DEL(perm_config->config->kkdcp[i].url);
for (j=0;j<perm_config->config->kkdcp[i].realms_size;j++) {
DEL(perm_config->config->kkdcp[i].realms[j].realm);
}
}
DEL(perm_config->config->kkdcp);
#endif
DEL(perm_config->config->network.ipv4);
DEL(perm_config->config->network.ipv4_netmask);
DEL(perm_config->config->network.ipv6);
for (i=0;i<perm_config->config->network.routes_size;i++)
DEL(perm_config->config->network.routes[i]);
DEL(perm_config->config->network.routes);
for (i=0;i<perm_config->config->network.dns_size;i++)
DEL(perm_config->config->network.dns[i]);
DEL(perm_config->config->network.dns);
for (i=0;i<perm_config->config->network.nbns_size;i++)
DEL(perm_config->config->network.nbns[i]);
DEL(perm_config->config->network.nbns);
for (i=0;i<perm_config->config->custom_header_size;i++)
DEL(perm_config->config->custom_header[i]);
DEL(perm_config->config->custom_header);
for (i=0;i<perm_config->config->split_dns_size;i++)
DEL(perm_config->config->split_dns[i]);
DEL(perm_config->config->split_dns);
for (i=0;i<perm_config->config->group_list_size;i++)
DEL(perm_config->config->group_list[i]);
DEL(perm_config->config->group_list);
DEL(perm_config->config->default_select_group);
#ifdef HAVE_LIBTALLOC
/* our included talloc don't include that */
talloc_free_children(perm_config->config);
#endif
memset(perm_config->config, 0, sizeof(*perm_config->config));
/* we rely on talloc doing that recursively */
talloc_free(perm_config->config);
perm_config->config = NULL;
return;
}
@@ -1287,9 +1270,12 @@ void print_version(tOptions *opts, tOptDesc *desc)
}
void reload_cfg_file(void *pool, struct perm_cfg_st* perm_config)
void reload_cfg_file(void *pool, struct perm_cfg_st* perm_config, unsigned archive)
{
clear_cfg(perm_config);
if (archive)
archive_cfg(perm_config);
else
clear_cfg(perm_config);
parse_cfg_file(pool, cfg_file, perm_config, 1);
@@ -1355,3 +1341,16 @@ int add_multi_line_val(void *pool, const char *name, char ***s_name, size_t *num
(*s_name)[*num] = NULL;
return 0;
}
void clear_old_configs(struct perm_cfg_st* config)
{
attic_entry_st *e, *pos;
/* go through the attic and clear old configurations if unused */
list_for_each_safe(&config->attic, e, pos, list) {
if (*e->usage_count == 0) {
list_del(&e->list);
talloc_free(e);
}
}
}

View File

@@ -99,16 +99,16 @@ void __attribute__ ((format(printf, 3, 4)))
const char* ip;
va_list args;
if (priority == LOG_DEBUG && ws->config->debug < 3)
if (priority == LOG_DEBUG && ws->perm_config->debug < 3)
return;
if (priority == LOG_HTTP_DEBUG) {
if (ws->config->debug < DEBUG_HTTP)
if (ws->perm_config->debug < DEBUG_HTTP)
return;
else
priority = LOG_INFO;
} else if (priority == LOG_TRANSFER_DEBUG) {
if (ws->config->debug < DEBUG_TRANSFERRED)
if (ws->perm_config->debug < DEBUG_TRANSFERRED)
return;
else
priority = LOG_DEBUG;
@@ -142,16 +142,16 @@ void __attribute__ ((format(printf, 4, 5)))
const char* ip = NULL;
va_list args;
if (priority == LOG_DEBUG && s->config->debug < 3)
if (priority == LOG_DEBUG && s->perm_config->debug < 3)
return;
if (priority == LOG_HTTP_DEBUG) {
if (s->config->debug < DEBUG_HTTP)
if (s->perm_config->debug < DEBUG_HTTP)
return;
else
priority = LOG_DEBUG;
} else if (priority == LOG_TRANSFER_DEBUG) {
if (s->config->debug < DEBUG_TRANSFERRED)
if (s->perm_config->debug < DEBUG_TRANSFERRED)
return;
else
priority = LOG_DEBUG;
@@ -186,7 +186,7 @@ void mslog_hex(const main_server_st * s, const struct proc_st* proc,
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
if (priority == LOG_DEBUG && s->config->debug == 0)
if (priority == LOG_DEBUG && s->perm_config->debug == 0)
return;
if (b64) {
@@ -211,7 +211,7 @@ void oclog_hex(const worker_st* ws, int priority,
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
if (priority == LOG_DEBUG && ws->config->debug == 0)
if (priority == LOG_DEBUG && ws->perm_config->debug == 0)
return;
if (b64) {
@@ -236,7 +236,7 @@ void seclog_hex(const struct sec_mod_st* sec, int priority,
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
if (priority == LOG_DEBUG && sec->config->debug == 0)
if (priority == LOG_DEBUG && sec->perm_config->debug == 0)
return;
if (b64) {

View File

@@ -371,7 +371,6 @@ static int append_user_info(method_ctx *ctx,
rep->dpd = ctmp->config->dpd;
rep->keepalive = ctmp->config->keepalive;
rep->domains = ctx->s->config->split_dns;
rep->n_domains = ctx->s->config->split_dns_size;
@@ -721,7 +720,7 @@ static void ctl_handle_commands(main_server_st * s)
goto cleanup;
}
ret = check_upeer_id("ctl", s->config->debug, cfd, 0, 0, NULL, NULL);
ret = check_upeer_id("ctl", s->perm_config->debug, cfd, 0, 0, NULL, NULL);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "ctl: unauthorized connection");
goto cleanup;

View File

@@ -211,6 +211,9 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned flags)
close_tun(s, proc);
proc_table_del(s, proc);
if (proc->config_usage_count && *proc->config_usage_count > 0) {
(*proc->config_usage_count)--;
}
talloc_free(proc);
}

View File

@@ -412,6 +412,10 @@ void apply_default_config(main_server_st *s, proc_st *proc, GroupCfgSt *gc)
gc->n_fw_ports = s->config->n_fw_ports;
gc->fw_ports = s->config->fw_ports;
}
/* since we keep pointers on s->config, increase its usage count */
proc->config_usage_count = s->config->usage_count;
(*proc->config_usage_count)++;
}
int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie, unsigned cookie_size)

View File

@@ -176,7 +176,7 @@ int _listen_ports(void *pool, struct perm_cfg_st* config,
else
continue;
if (config->config->foreground != 0)
if (config->foreground != 0)
fprintf(stderr, "listening (%s) on %s...\n",
type, human_addr(ptr->ai_addr, ptr->ai_addrlen,
buf, sizeof(buf)));
@@ -249,7 +249,7 @@ int _listen_unix_ports(void *pool, struct perm_cfg_st* config,
strlcpy(sa.sun_path, config->unix_conn_file, sizeof(sa.sun_path));
remove(sa.sun_path);
if (config->config->foreground != 0)
if (config->foreground != 0)
fprintf(stderr, "listening (UNIX) on %s...\n",
sa.sun_path);
@@ -608,7 +608,7 @@ static void drop_privileges(main_server_st* s)
}
#define MAX_WORKER_MEM (16*1024*1024)
if (s->config->debug == 0) {
if (s->perm_config->debug == 0) {
rl.rlim_cur = MAX_WORKER_MEM;
rl.rlim_max = MAX_WORKER_MEM;
ret = setrlimit(RLIMIT_AS, &rl);
@@ -850,7 +850,8 @@ unsigned total = 10;
if (reload_conf != 0) {
mslog(s, NULL, LOG_INFO, "reloading configuration");
reload_cfg_file(s->main_pool, s->perm_config);
reload_cfg_file(s->main_pool, s->perm_config, 1);
s->config = s->perm_config->config;
tls_reload_crl(s, s->creds, 1);
reload_conf = 0;
kill(s->sec_mod_pid, SIGHUP);
@@ -897,6 +898,7 @@ unsigned total = 10;
tls_reload_crl(s, s->creds, 0);
expire_tls_sessions(s);
cleanup_banned_entries(s);
clear_old_configs(s->perm_config);
alarm(MAINTAINANCE_TIME(s));
}
}
@@ -1024,7 +1026,7 @@ int main(int argc, char** argv)
flags = LOG_PID|LOG_NDELAY;
#ifdef LOG_PERROR
if (s->config->debug != 0)
if (s->perm_config->debug != 0)
flags |= LOG_PERROR;
#endif
openlog("ocserv", flags, LOG_DAEMON);
@@ -1034,7 +1036,7 @@ int main(int argc, char** argv)
deny_severity = LOG_DAEMON|LOG_WARNING;
#endif
if (s->config->foreground == 0) {
if (s->perm_config->foreground == 0) {
if (daemon(0, 0) == -1) {
e = errno;
fprintf(stderr, "daemon failed: %s\n", strerror(e));

View File

@@ -44,7 +44,8 @@ extern char **saved_argv;
extern sigset_t sig_default_set;
int cmd_parser (void *pool, int argc, char **argv, struct perm_cfg_st** config);
void reload_cfg_file(void *pool, struct perm_cfg_st* config);
void reload_cfg_file(void *pool, struct perm_cfg_st* config, unsigned archive);
void clear_old_configs(struct perm_cfg_st* config);
void clear_cfg(struct perm_cfg_st* config);
void write_pid_file(void);
void remove_pid_file(void);
@@ -147,6 +148,7 @@ typedef struct proc_st {
/* The following we rely on talloc for deallocation */
GroupCfgSt *config; /* custom user/group config */
int *config_usage_count; /* points to s->config->usage_count */
} proc_st;
struct ip_lease_db_st {

View File

@@ -435,7 +435,8 @@ static void check_other_work(sec_mod_st *sec)
if (need_reload) {
seclog(sec, LOG_DEBUG, "reloading configuration");
reload_cfg_file(sec, sec->perm_config);
reload_cfg_file(sec, sec->perm_config, 0);
sec->config = sec->perm_config->config;
need_reload = 0;
}
@@ -836,7 +837,7 @@ void sec_mod_server(void *main_pool, struct perm_cfg_st *perm_config, const char
/* do not allow unauthorized processes to issue commands
*/
ret = check_upeer_id("sec-mod", sec->config->debug, cfd, perm_config->uid, perm_config->gid, &uid, &pid);
ret = check_upeer_id("sec-mod", sec->perm_config->debug, cfd, perm_config->uid, perm_config->gid, &uid, &pid);
if (ret < 0) {
seclog(sec, LOG_INFO, "rejected unauthorized connection");
} else {

View File

@@ -112,7 +112,7 @@ void cleanup_client_entries(sec_mod_st *sec);
#ifdef __GNUC__
# define seclog(sec, prio, fmt, ...) \
if (prio != LOG_DEBUG || sec->config->debug >= 3) { \
if (prio != LOG_DEBUG || sec->perm_config->debug >= 3) { \
syslog(prio, "sec-mod: "fmt, ##__VA_ARGS__); \
}
#else

View File

@@ -682,7 +682,7 @@ void tls_load_certs(main_server_st *s, tls_st *creds)
int ret;
const char* perr;
if (s->config->debug >= DEBUG_TLS) {
if (s->perm_config->debug >= DEBUG_TLS) {
gnutls_global_set_log_function(tls_log_func);
gnutls_global_set_log_level(9);
}

View File

@@ -25,6 +25,7 @@
#include <gnutls/gnutls.h>
#include <http_parser.h>
#include <ccan/htable/htable.h>
#include <ccan/list/list.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -314,8 +315,6 @@ struct cfg_st {
unsigned keepalive;
unsigned dpd;
unsigned mobile_dpd;
unsigned foreground;
unsigned debug;
unsigned max_clients;
unsigned max_same_clients;
unsigned use_utmp;
@@ -372,6 +371,9 @@ struct cfg_st {
/* the tun network */
struct vpn_st network;
/* holds a usage count of holders of pointers in this struct */
int *usage_count;
};
struct perm_cfg_st {
@@ -404,6 +406,9 @@ struct perm_cfg_st {
char *cert_hash;
#endif
unsigned foreground;
unsigned debug;
char *ca;
char *dh_params_file;
@@ -411,8 +416,17 @@ struct perm_cfg_st {
char* unix_conn_file;
unsigned int port;
unsigned int udp_port;
/* attic, where old config allocated values are stored */
struct list_head attic;
};
typedef struct attic_entry_st {
struct list_node list;
int *usage_count;
} attic_entry_st;
/* generic thing to stop complaints */
struct worker_st;
struct main_server_st;

View File

@@ -408,7 +408,7 @@ void vpn_server(struct worker_st *ws)
/* do not allow this process to be traced. That
* prevents worker processes tracing each other. */
if (ws->config->debug == 0)
if (ws->perm_config->debug == 0)
pr_set_undumpable("worker");
if (ws->config->isolate != 0) {
ret = disable_system_calls(ws);