Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion sql/postgresql/create_tables.pgsql
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);


Expand Down
9 changes: 6 additions & 3 deletions src/dm_mailboxstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions src/dm_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/imapcommands.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
135 changes: 93 additions & 42 deletions src/modules/authldap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand All @@ -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;
}

/*
Expand All @@ -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;
Expand All @@ -153,7 +198,6 @@ static int auth_ldap_bind(void)
}

return 0;

}

/*
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 2 additions & 3 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()));

Expand Down Expand Up @@ -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;
Expand Down