diff --git a/sql/postgresql/create_tables.pgsql b/sql/postgresql/create_tables.pgsql index da3b694f..45740fd3 100644 --- a/sql/postgresql/create_tables.pgsql +++ b/sql/postgresql/create_tables.pgsql @@ -46,7 +46,8 @@ CREATE TABLE dbmail_authlog ( dst_port INT8, status VARCHAR(32) DEFAULT 'active', bytes_rx INT8 DEFAULT '0' NOT NULL, - bytes_tx INT8 DEFAULT '0' NOT NULL + bytes_tx INT8 DEFAULT '0' NOT NULL, + PRIMARY KEY (id) ); diff --git a/src/dm_mailboxstate.c b/src/dm_mailboxstate.c index 723689a8..c04b6d78 100644 --- a/src/dm_mailboxstate.c +++ b/src/dm_mailboxstate.c @@ -212,11 +212,12 @@ T MailboxState_new(Mempool_T pool, uint64_t id) db_begin_transaction(c); // we need read-committed isolation state_load_metadata(M, c); state_load_messages(M, c); + db_commit_transaction(c); CATCH(SQLException) LOG_SQLERROR; + db_rollback_transaction(c); t = DM_EQUERY; FINALLY - db_commit_transaction(c); db_con_close(c); END_TRY; @@ -888,11 +889,12 @@ int MailboxState_info(T M) TRY db_begin_transaction(c); db_getmailbox_info(M, c); + db_commit_transaction(c); CATCH(SQLException) LOG_SQLERROR; + db_rollback_transaction(c); t = DM_EQUERY; FINALLY - db_commit_transaction(c); db_con_close(c); END_TRY; @@ -928,11 +930,12 @@ int MailboxState_count(T M) TRY db_begin_transaction(c); db_getmailbox_count(M, c); + db_commit_transaction(c); CATCH(SQLException) LOG_SQLERROR; + db_rollback_transaction(c); t = DM_EQUERY; FINALLY - db_commit_transaction(c); db_con_close(c); END_TRY; diff --git a/src/dm_misc.c b/src/dm_misc.c index e795de1a..1599c645 100644 --- a/src/dm_misc.c +++ b/src/dm_misc.c @@ -106,6 +106,10 @@ int drop_privileges(char *newuser, char *newgroup) int get_opened_fd_count(void) { +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__SUNPRO_C) + // BSD like systems don't use proc + return 0; +#else DIR* dir = NULL; struct dirent* entry = NULL; char buf[32]; @@ -122,6 +126,7 @@ int get_opened_fd_count(void) closedir(dir); return fd_count - 2; /* exclude '.' and '..' entries */ +#endif } void create_unique_id(char *target, uint64_t message_idnr) diff --git a/src/imapcommands.c b/src/imapcommands.c index bdedb4a1..43760fcc 100644 --- a/src/imapcommands.c +++ b/src/imapcommands.c @@ -946,6 +946,7 @@ void _ic_delete_enter(dm_thread_data *D) db_commit_transaction(c); CATCH(SQLException) LOG_SQLERROR; + db_rollback_transaction(c); t = DM_EQUERY; FINALLY db_con_close(c); diff --git a/src/modules/authldap.c b/src/modules/authldap.c index 19802c8f..05c3331c 100644 --- a/src/modules/authldap.c +++ b/src/modules/authldap.c @@ -28,7 +28,8 @@ extern char configFile[PATH_MAX]; -GStaticPrivate ldap_conn_key; +static void authldap_free(gpointer data); +static GPrivate ldap_conn_key = G_PRIVATE_INIT (authldap_free); static GOnce ldap_conn_once = G_ONCE_INIT; static int authldap_connect(void); @@ -43,7 +44,9 @@ typedef struct _ldap_cfg { Field_T field_members; Field_T query_string; Field_T referrals; + Field_T query_timeout; int scope_int, port_int, version_int; + int query_timeout_int; } _ldap_cfg_t; static _ldap_cfg_t _ldap_cfg; @@ -74,6 +77,7 @@ static void __auth_get_config(void) GETCONFIGVALUE("QUERY_STRING", "LDAP", _ldap_cfg.query_string); GETCONFIGVALUE("SCOPE", "LDAP", _ldap_cfg.scope); GETCONFIGVALUE("REFERRALS", "LDAP", _ldap_cfg.referrals); + GETCONFIGVALUE("QUERY_TIMEOUT", "LDAP", _ldap_cfg.query_timeout); /* Store the port as an integer for later use. */ _ldap_cfg.port_int = atoi(_ldap_cfg.port); @@ -97,6 +101,8 @@ static void __auth_get_config(void) else _ldap_cfg.scope_int = LDAP_SCOPE_SUBTREE; } + /* Store the timeout as an integer. */ + _ldap_cfg.query_timeout_int = atoi(_ldap_cfg.query_timeout); TRACE(TRACE_DEBUG, "integer ldap scope is [%d]", _ldap_cfg.scope_int); } @@ -105,23 +111,54 @@ static void __auth_get_config(void) */ static gpointer authldap_once(gpointer UNUSED data) { - g_static_private_init(&ldap_conn_key); __auth_get_config(); return (gpointer)NULL; } -/* - lookup thread-local ldap connection -*/ +/* + * ldap_con_get() + * + * Lookup thread-local ldap connection and bind using config credentials + * retrying a few times if the server is temporarily unavailable + * + * returns connection on success, NULL on failure + */ static LDAP * ldap_con_get(void) { - LDAP * c = (LDAP *)g_static_private_get(&ldap_conn_key); - if (! c) { - authldap_connect(); - c = (LDAP *)g_static_private_get(&ldap_conn_key); + LDAP * ld = (LDAP *)g_private_get(&ldap_conn_key); + if (ld) { + TRACE(TRACE_DEBUG, "connection [%p]", ld); + return ld; } - TRACE(TRACE_DEBUG, "connection [%p]", c); - return c; + int c = 0; + int c_tries = _ldap_cfg.query_timeout_int; + int err = -1; // Start wanting success + while (err != 0 && c++ < c_tries) { + // Loop until success or too many retries + TRACE(TRACE_DEBUG, "No connection trying [%d/%d]", c, c_tries); + + err = authldap_connect(); + + switch (err) { + case LDAP_SUCCESS: + ld = (LDAP *)g_private_get(&ldap_conn_key); + TRACE(TRACE_DEBUG, "connection [%p]", ld); + break; + case LDAP_SERVER_DOWN: + TRACE(TRACE_WARNING, "LDAP gone away: %s. Trying to reconnect(%d/%d).", ldap_err2string(err), c, c_tries); + sleep(1); // reconnect failed. wait before trying again + break; + default: + TRACE(TRACE_ERR, "LDAP error(%d): %s", err, ldap_err2string(err)); + sleep(1); + break; + } + } + if (! ld) { + TRACE(TRACE_ERR, "Unable to connect to LDAP giving up"); + } + TRACE(TRACE_DEBUG, "connection [%p]", ld); + return ld; } /* @@ -130,16 +167,24 @@ static LDAP * ldap_con_get(void) static void authldap_free(gpointer data) { LDAP *c = (LDAP *)data; - struct sigaction act, oldact; - - memset(&act, 0, sizeof(act)); - memset(&oldact, 0, sizeof(oldact)); - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &act, &oldact); - ldap_unbind(c); - sigaction(SIGPIPE, &oldact, 0); + + int err = ldap_set_option(c, LDAP_OPT_SERVER_CONTROLS, NULL ); + if ( err != LDAP_OPT_SUCCESS ) { + TRACE(TRACE_ERR, "Could not unset controls"); + } + + if ((err = ldap_unbind_ext_s(c, NULL, NULL))) { + TRACE(TRACE_ERR, "ldap_unbind_ext_s failed: %s", ldap_err2string(err)); + } } +/* + * auth_ldap_bind() + * + * Bind to server using config credentials + * + * returns 0 on success, -1 on failure + */ static int auth_ldap_bind(void) { int err; @@ -153,7 +198,6 @@ static int auth_ldap_bind(void) } return 0; - } /* @@ -208,52 +252,56 @@ static int authldap_connect(void) if (strncasecmp(_ldap_cfg.referrals, "no", 2) == 0) ldap_set_option(_ldap_conn, LDAP_OPT_REFERRALS, 0); - g_static_private_set(&ldap_conn_key, _ldap_conn, (GDestroyNotify)authldap_free); + g_private_replace(&ldap_conn_key, _ldap_conn); return auth_ldap_bind(); } -static int authldap_reconnect(void) -{ - LDAP *c; - if ((c = ldap_con_get())) authldap_free((gpointer)c); - return authldap_connect(); -} - +/* + * authldap_search() + * + * Perform an LDAP search + * + * returns search results on success, NULL on failure + */ static LDAPMessage * authldap_search(const gchar *query) { LDAPMessage *ldap_res; int _ldap_attrsonly = 0; char **_ldap_attrs = NULL; - int c=0, err; + int err = -1; // Start wanting success + int c = 0; + int c_tries = _ldap_cfg.query_timeout_int; LDAP *_ldap_conn; g_return_val_if_fail(query!=NULL, NULL); _ldap_conn = ldap_con_get(); - while (c++ < 5) { - TRACE(TRACE_DEBUG, " [%s]", query); - err = ldap_search_s(_ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, - query, _ldap_attrs, _ldap_attrsonly, &ldap_res); + TRACE(TRACE_DEBUG, " [%s]", query); + + while (err != 0 && c++ < c_tries) { + // Loop until success or too many retries - if (! err) - return ldap_res; + // timeout must be NULL as any value times out! + err = ldap_search_ext_s(_ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, + query, _ldap_attrs, _ldap_attrsonly, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_res); switch (err) { + case LDAP_SUCCESS: + return ldap_res; + break; case LDAP_SERVER_DOWN: - TRACE(TRACE_WARNING, "LDAP gone away: %s. Try to reconnect(%d/5).", ldap_err2string(err),c); - if (authldap_reconnect()) - sleep(2); // reconnect failed. wait before trying again + TRACE(TRACE_WARNING, "LDAP gone away: %s. Trying again(%d/%d).", ldap_err2string(err), c, c_tries); break; default: - TRACE(TRACE_ERR, "LDAP error(%d): %s", err, ldap_err2string(err)); - return NULL; + TRACE(TRACE_ERR, "LDAP error(%d): %s. Trying again (%d/%d).", err, ldap_err2string(err), c, c_tries); break; } + sleep(1); // Search failed. Wait before trying again. } - TRACE(TRACE_EMERG,"unrecoverable error while talking to ldap server"); + TRACE(TRACE_ERR,"unrecoverable error while talking to ldap server"); return NULL; } @@ -591,7 +639,10 @@ int auth_connect(void) } int auth_disconnect(void) { - g_static_private_free(&ldap_conn_key); + // Just free the pointer, + // G_PRIVATE_INIT calls GDestroyNotify + // which calls authldap_free() + g_private_replace(&ldap_conn_key, NULL); return 0; } diff --git a/src/server.c b/src/server.c index ba8e5c52..ba3ce10c 100644 --- a/src/server.c +++ b/src/server.c @@ -282,6 +282,8 @@ static int server_start_cli(ServerConfig_T *conf) TRACE(TRACE_ERR, "could not connect to authentication"); return -1; } + // Disconnect this connection as threads will create their own + auth_disconnect(); srand((int) ((int) time(NULL) + (int) getpid())); @@ -656,9 +658,6 @@ void server_sig_cb(int UNUSED fd, short UNUSED event, void *arg) mainReload = 1; case SIGPIPE: // ignore break; - case SIGUSR1: - g_mem_profile(); - break; default: exit(0); break;