/*
Copyright (c) 2002 Aaron Stone, aaron@serendipity.cx
Copyright (c) 2005 Paul Stevens, paul@nfg.nl
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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Id: authldap.c 2187 2006-06-24 14:57:02Z paul $
* * User authentication functions for LDAP.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dbmail.h"
#define AUTH_QUERY_SIZE 1024
#define LDAP_RES_SIZE 1024
extern char *configFile;
static LDAP *_ldap_conn = NULL;
LDAPMod **_ldap_mod;
LDAPMessage *_ldap_res;
LDAPMessage *_ldap_msg;
int _ldap_err;
int _ldap_attrsonly = 0;
char *_ldap_dn;
char **_ldap_vals;
char **_ldap_attrs = NULL;
char _ldap_query[AUTH_QUERY_SIZE];
typedef struct _ldap_cfg {
field_t bind_dn, bind_pw, base_dn, port, version, scope, hostname;
field_t user_objectclass, forw_objectclass;
field_t cn_string;
field_t field_uid, field_cid, min_cid, max_cid, field_nid, min_nid, max_nid;
field_t field_mail, field_mailalt, mailaltprefix;
field_t field_maxmail, field_passwd;
field_t field_fwd, field_fwdsave, field_fwdtarget, fwdtargetprefix;
field_t field_members;
int scope_int, port_int, version_int;
} _ldap_cfg_t;
_ldap_cfg_t _ldap_cfg;
static GList * __auth_get_every_match(const char *q, char **retfields);
static int dm_ldap_user_shadow_rename(u64_t user_idnr, const char *new_name);
static int auth_reconnect(void);
static int auth_search(const gchar *query);
static void __auth_get_config(void)
{
static int beenhere=0;
if (beenhere)
return;
GETCONFIGVALUE("BIND_DN", "LDAP", _ldap_cfg.bind_dn);
GETCONFIGVALUE("BIND_PW", "LDAP", _ldap_cfg.bind_pw);
GETCONFIGVALUE("BASE_DN", "LDAP", _ldap_cfg.base_dn);
GETCONFIGVALUE("PORT", "LDAP", _ldap_cfg.port);
GETCONFIGVALUE("VERSION", "LDAP", _ldap_cfg.version);
GETCONFIGVALUE("HOSTNAME", "LDAP", _ldap_cfg.hostname);
GETCONFIGVALUE("USER_OBJECTCLASS", "LDAP", _ldap_cfg.user_objectclass);
GETCONFIGVALUE("FORW_OBJECTCLASS", "LDAP", _ldap_cfg.forw_objectclass);
GETCONFIGVALUE("CN_STRING", "LDAP", _ldap_cfg.cn_string);
GETCONFIGVALUE("FIELD_UID", "LDAP", _ldap_cfg.field_uid);
GETCONFIGVALUE("FIELD_CID", "LDAP", _ldap_cfg.field_cid);
GETCONFIGVALUE("MIN_CID", "LDAP", _ldap_cfg.min_cid);
GETCONFIGVALUE("MAX_CID", "LDAP", _ldap_cfg.max_cid);
GETCONFIGVALUE("FIELD_NID", "LDAP", _ldap_cfg.field_nid);
GETCONFIGVALUE("MIN_NID", "LDAP", _ldap_cfg.min_nid);
GETCONFIGVALUE("MAX_NID", "LDAP", _ldap_cfg.max_nid);
GETCONFIGVALUE("FIELD_MAIL", "LDAP", _ldap_cfg.field_mail);
GETCONFIGVALUE("FIELD_QUOTA", "LDAP", _ldap_cfg.field_maxmail);
GETCONFIGVALUE("FIELD_PASSWD", "LDAP", _ldap_cfg.field_passwd);
GETCONFIGVALUE("FIELD_FWDTARGET", "LDAP", _ldap_cfg.field_fwdtarget);
GETCONFIGVALUE("SCOPE", "LDAP", _ldap_cfg.scope);
/* Store the port as an integer for later use. */
_ldap_cfg.port_int = atoi(_ldap_cfg.port);
/* Store the version as an integer for later use. */
_ldap_cfg.version_int = atoi(_ldap_cfg.version);
/* defaults to version 3 */
if (!_ldap_cfg.version_int)
_ldap_cfg.version_int=3;
/* Compare the input string with the possible options,
* making sure not to exceeed the length of the given string */
{
int len = (strlen(_ldap_cfg.scope) < 3 ? strlen(_ldap_cfg.scope) : 3);
if (strncasecmp(_ldap_cfg.scope, "one", len) == 0)
_ldap_cfg.scope_int = LDAP_SCOPE_ONELEVEL;
else if (strncasecmp(_ldap_cfg.scope, "bas", len) == 0)
_ldap_cfg.scope_int = LDAP_SCOPE_BASE;
else if (strncasecmp(_ldap_cfg.scope, "sub", len) == 0)
_ldap_cfg.scope_int = LDAP_SCOPE_SUBTREE;
else
_ldap_cfg.scope_int = LDAP_SCOPE_SUBTREE;
}
trace(TRACE_DEBUG,
"%s,%s: integer ldap scope is [%d]",__FILE__,__func__,
_ldap_cfg.scope_int);
beenhere++;
}
static int auth_ldap_bind(void)
{
trace(TRACE_DEBUG, "%s,%s: binding to ldap server as [%s] / [xxxxxxxx]",
__FILE__,__func__,
_ldap_cfg.bind_dn);
/*
* TODO: support tls connects
*/
if ((_ldap_err = ldap_bind_s(_ldap_conn,
_ldap_cfg.bind_dn,
_ldap_cfg.bind_pw,
LDAP_AUTH_SIMPLE))) {
trace(TRACE_ERROR, "%s,%s: ldap_bind_s failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
return -1;
}
trace(TRACE_DEBUG, "%s,%s: successfully bound to ldap server",
__FILE__,__func__);
return 0;
}
/*
* auth_connect()
*
* initializes the connection for authentication.
*
* returns 0 on success, -1 on failure
*/
int auth_connect(void)
{
int version;
if (_ldap_conn != NULL)
return 0;
__auth_get_config();
trace(TRACE_DEBUG, "%s,%s: connecting to ldap server on [%s] : [%d] version [%d]",
__FILE__,__func__,
_ldap_cfg.hostname,
_ldap_cfg.port_int,
_ldap_cfg.version_int);
_ldap_conn = ldap_init(
_ldap_cfg.hostname,
_ldap_cfg.port_int);
switch (_ldap_cfg.version_int) {
case 2:
version = LDAP_VERSION2;
break;
case 3:
version = LDAP_VERSION3;
break;
default:
trace(TRACE_ERROR, "%s, %s: Unsupported LDAP version requested [%d]. "
"Defaulting to LDAP version 3.",
__FILE__, __func__, _ldap_cfg.version_int);
version = LDAP_VERSION3;
break;
}
ldap_set_option(_ldap_conn, LDAP_OPT_PROTOCOL_VERSION, &version);
return auth_ldap_bind();
}
int auth_disconnect(void)
{
/* Destroy the connection */
if (_ldap_conn != NULL) {
ldap_unbind(_ldap_conn);
_ldap_conn = NULL;
}
return 0;
}
static int auth_search(const gchar *query)
{
int c=0;
g_return_val_if_fail(query!=NULL, DM_EQUERY);
while (c++ < 5) {
trace(TRACE_DEBUG, "%s,%s: [%s]",__FILE__,__func__, query);
_ldap_err = ldap_search_s(_ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int,
query, _ldap_attrs, _ldap_attrsonly, &_ldap_res);
if (! _ldap_err)
return 0;
switch (_ldap_err) {
case LDAP_SERVER_DOWN:
trace(TRACE_ERROR, "%s,%s: %s", __FILE__, __func__, ldap_err2string(_ldap_err));
if (auth_reconnect())
sleep(2); // reconnect failed. wait before trying again
break;
default:
trace(TRACE_ERROR, "%s,%s: %s", __FILE__, __func__, ldap_err2string(_ldap_err));
return _ldap_err;
break;
}
}
trace(TRACE_FATAL,"%s,%s: unrecoverable error while talking to ldap server", __FILE__, __func__);
return -1;
}
static int auth_reconnect(void)
{
auth_disconnect();
return auth_connect();
}
void dm_ldap_freeresult(GList *entlist)
{
GList *fldlist, *attlist;
entlist = g_list_first(entlist);
while (entlist) {
fldlist = entlist->data;
while(fldlist) {
attlist = fldlist->data;
g_list_foreach(attlist,(GFunc)g_free,NULL);
g_list_free(attlist);
if (! g_list_next(fldlist))
break;
fldlist = g_list_next(fldlist);
}
if (! g_list_next(entlist))
break;
entlist = g_list_next(entlist);
}
}
GList * dm_ldap_entdm_list_get_values(GList *entlist)
{
GList *fldlist, *attlist;
GList *values = NULL;
gchar *tmp;
entlist = g_list_first(entlist);
while (entlist) {
fldlist = g_list_first(entlist->data);
while (fldlist) {
attlist = g_list_first(fldlist->data);
while (attlist) {
tmp = (gchar *)attlist->data;
trace(TRACE_DEBUG,"%s,%s: value [%s]",
__FILE__, __func__,
tmp);
values = g_list_append_printf(values,"%s", tmp);
if (! g_list_next(attlist))
break;
attlist = g_list_next(attlist);
}
if (! g_list_next(fldlist))
break;
fldlist = g_list_next(fldlist);
}
if (! g_list_next(entlist))
break;
entlist = g_list_next(entlist);
}
return values;
}
static char *dm_ldap_get_filter(const gchar boolean, const gchar *attribute, GList *values)
{
/* build user filter from objectclasses */
gchar *s;
GString *t = g_string_new("");
GString *q = g_string_new("");
GList *l = NULL;
values = g_list_first(values);
while (values) {
g_string_printf(t,"%s=%s", attribute, (char *)values->data);
l = g_list_append(l,g_strdup(t->str));
if (! g_list_next(values))
break;
values = g_list_next(values);
}
t = g_list_join(l,")(");
g_string_printf(q,"(%c(%s))", boolean, t->str);
s = q->str;
g_string_free(t,TRUE);
g_string_free(q,FALSE);
g_list_foreach(l,(GFunc)g_free,NULL);
g_list_free(l);
return s;
}
static u64_t dm_ldap_get_freeid(const gchar *attribute)
{
/* get the first available uidNumber/gidNumber */
u64_t id = 0, t;
GList *ids, *entlist;
u64_t min = 0, max = 0;
char *attrs[2] = { (char *)attribute, NULL };
GString *q = g_string_new("");
u64_t *key;
g_string_printf(q,"(%s=*)", attribute);
entlist = __auth_get_every_match(q->str, attrs);
ids = dm_ldap_entdm_list_get_values(entlist);
/* get the valid range */
if (strcmp(attribute,_ldap_cfg.field_nid)==0) {
min = strtoull(_ldap_cfg.min_nid,NULL,10);
max = strtoull(_ldap_cfg.max_nid,NULL,10);
}
if (strcmp(attribute,_ldap_cfg.field_cid)==0) {
min = strtoull(_ldap_cfg.min_cid,NULL,10);
max = strtoull(_ldap_cfg.max_cid,NULL,10);
}
g_assert(min < max);
/* allocate the key array */
key = g_new0(u64_t, 1 + max - min );
/* get all used ids */
ids = g_list_first(ids);
while (ids) {
t = strtoull(ids->data,NULL,10);
if ( (t >= min) && (t <= max) )
key[t-min] = t;
if (! g_list_next(ids))
break;
ids = g_list_next(ids);
}
/* find the first unused id */
for (t = min; t <= max; t++) {
if (! (key[t-min]))
break;
}
g_assert( (t >= min) && (t <= max) );
/* cleanup */
g_free(key);
g_list_foreach(ids,(GFunc)g_free,NULL);
g_list_free(ids);
id=t;
trace(TRACE_DEBUG,"%s,%s: return free id [%llu]\n",
__FILE__, __func__,
id);
return id;
}
static char * dm_ldap_user_getdn(u64_t user_idnr)
{
GString *t = g_string_new("");
char *dn;
g_string_printf(t, "(%s=%llu)", _ldap_cfg.field_nid, user_idnr);
trace(TRACE_DEBUG, "%s,%s: searching with query [%s]",
__FILE__,__func__,
t->str);
if (auth_search(t->str)) {
g_string_free(t,TRUE);
return NULL;
}
if (ldap_count_entries(_ldap_conn, _ldap_res) < 1) {
trace(TRACE_DEBUG, "%s,%s: no entries found",__FILE__,__func__);
g_string_free(t,TRUE);
ldap_msgfree(_ldap_res);
return NULL;
}
if (! (_ldap_msg = ldap_first_entry(_ldap_conn, _ldap_res))) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err);
trace(TRACE_ERROR, "%s,%s: ldap_first_entry failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
ldap_msgfree(_ldap_res);
return NULL;
}
if (! (dn = ldap_get_dn(_ldap_conn, _ldap_msg))) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err);
trace(TRACE_ERROR, "%s,%s: ldap_get_dn failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
ldap_msgfree(_ldap_res);
return NULL;
}
ldap_msgfree(_ldap_res);
return dn;
}
static int dm_ldap_mod_field(u64_t user_idnr, const char *fieldname, const char *newvalue)
{
LDAPMod *mods[2], modField;
char *newvalues[2];
if (! user_idnr) {
trace(TRACE_ERROR, "%s,%s: no user_idnr specified",
__FILE__,__func__);
return -1;
}
if (! fieldname) {
trace(TRACE_ERROR, "%s,%s: no fieldname specified",
__FILE__,__func__);
return -1;
}
if (! newvalue) {
trace(TRACE_ERROR, "%s,%s: no new value specified",
__FILE__,__func__);
return -1;
}
if (! (_ldap_dn = dm_ldap_user_getdn(user_idnr)))
return -1;
newvalues[0] = (char *)newvalue;
newvalues[1] = NULL;
modField.mod_op = LDAP_MOD_REPLACE;
modField.mod_type = (char *)fieldname;
modField.mod_values = newvalues;
mods[0] = &modField;
mods[1] = NULL;
_ldap_err = ldap_modify_s(_ldap_conn, _ldap_dn, mods);
if (_ldap_err) {
trace(TRACE_ERROR,"%s,%s: error changing field [%s] to value [%s]: %s",
__FILE__, __func__,
fieldname, newvalue,
ldap_err2string(_ldap_err));
ldap_memfree(_ldap_dn);
return -1;
}
ldap_memfree(_ldap_dn);
return 0;
}
/* OLD-SCHOOL:
*
* Each node of retlist contains a data field
* which is a pointer to another list, "fieldlist".
*
* Each node of fieldlist contains a data field
* which is a pointer to another list, "datalist".
*
* Each node of datalist contains a data field
* which is a (char *) pointer to some actual data.
*
* Here's a visualization:
*
* retlist
* has the "rows" that matched
* {
* (struct dm_list *)data
* has the fields you requested
* {
* (struct dm_list *)data
* has the values for the field
* {
* (char *)data
* (char *)data
* (char *)data
* }
* }
* }
*
* TODO: GLIB-STYLIE:
*
* ghashtable *ldap_entities
* {
* gchar *dn;
* ghashtable *ldap_attributes {
* gchar *attribute;
* glist *values;
* }
* }
*
*/
/* returns the number of matches found */
static GList * __auth_get_every_match(const char *q, char **retfields)
{
LDAPMessage *ldap_msg;
int ldap_err;
char **ldap_vals = NULL;
char *dn;
int j = 0, k = 0, m = 0;
GList *attlist,*fldlist,*entlist;
attlist = fldlist = entlist = NULL;
if (auth_search(q))
return NULL;
if ((j = ldap_count_entries(_ldap_conn, _ldap_res)) < 1) {
trace(TRACE_DEBUG, "%s,%s: nothing found",__FILE__,__func__);
if (_ldap_res)
ldap_msgfree(_ldap_res);
return NULL;
}
/* do the first entry here */
if ((ldap_msg = ldap_first_entry(_ldap_conn, _ldap_res)) == NULL) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err);
trace(TRACE_ERROR, "%s,%s: ldap_first_entry failed: [%s]",__FILE__,__func__,
ldap_err2string(_ldap_err));
if (_ldap_res)
ldap_msgfree(_ldap_res);
return NULL;
}
while (ldap_msg) {
dn = ldap_get_dn(_ldap_conn, ldap_msg);
trace(TRACE_DEBUG,"%s,%s: scan results for DN: [%s]", __FILE__, __func__, dn);
for (k = 0; retfields[k] != NULL; k++) {
trace(TRACE_DEBUG,"%s,%s: ldap_get_values [%s]",
__FILE__, __func__, retfields[k]);
if (! (ldap_vals = ldap_get_values(_ldap_conn, ldap_msg, retfields[k]))) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &ldap_err);
trace(TRACE_WARNING, "%s,%s: ldap_get_values failed: [%s] %s",
__FILE__,__func__,
retfields[k],
ldap_err2string(ldap_err));
} else {
m = 0;
while (ldap_vals[m]) {
trace(TRACE_DEBUG,"%s,%s: got value [%s]\n",
__FILE__, __func__,
ldap_vals[m]);
attlist = g_list_append(attlist,g_strdup(ldap_vals[m]));
m++;
}
}
fldlist = g_list_append(fldlist, attlist);
attlist = NULL;
ldap_value_free(ldap_vals);
}
entlist = g_list_append(entlist, fldlist);
fldlist = NULL;
ldap_memfree(dn);
ldap_msg = ldap_next_entry(_ldap_conn, ldap_msg);
}
if (_ldap_res)
ldap_msgfree(_ldap_res);
if (ldap_msg)
ldap_msgfree(ldap_msg);
return entlist;
}
static char *__auth_get_first_match(const char *q, char **retfields)
{
LDAPMessage *ldap_msg;
char *returnid = NULL;
char *ldap_dn = NULL;
char **ldap_vals = NULL;
int k = 0;
if (auth_search(q))
return NULL;
if (ldap_count_entries(_ldap_conn, _ldap_res) < 1) {
trace(TRACE_DEBUG, "%s,%s: none found",__FILE__,__func__);
goto endfree;
}
ldap_msg = ldap_first_entry(_ldap_conn, _ldap_res);
if (ldap_msg == NULL) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err);
trace(TRACE_ERROR, "%s,%s: ldap_first_entry failed: %s",__FILE__,__func__,
ldap_err2string(_ldap_err));
goto endfree;
}
for (k = 0; retfields[k] != NULL; k++) {
if (0 == strcasecmp(retfields[k], "dn")) {
ldap_dn = ldap_get_dn(_ldap_conn, ldap_msg);
if (ldap_dn)
returnid = g_strdup(ldap_dn);
break;
} else {
ldap_vals = ldap_get_values(_ldap_conn, ldap_msg, retfields[k]);
if (ldap_vals)
returnid = g_strdup(ldap_vals[0]);
break;
}
}
endfree:
if (ldap_dn)
ldap_memfree(ldap_dn);
if (ldap_vals)
ldap_value_free(ldap_vals);
if (_ldap_res)
ldap_msgfree(_ldap_res);
trace(TRACE_DEBUG,"%s,%s: returnid [%s]", __FILE__,__func__,returnid);
return returnid;
}
int auth_user_exists(const char *username, u64_t * user_idnr)
{
char *id_char;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_nid, NULL };
assert(user_idnr != NULL);
*user_idnr = 0;
if (!username) {
trace(TRACE_ERROR, "%s,%s: got NULL as username",
__FILE__,__func__);
return 0;
}
/* fall back to db-user for DBMAIL_DELIVERY_USERNAME */
if (strcmp(username,DBMAIL_DELIVERY_USERNAME)==0)
return db_user_exists(DBMAIL_DELIVERY_USERNAME, user_idnr);
snprintf(query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid,
username);
id_char = __auth_get_first_match(query, fields);
*user_idnr = (id_char) ? strtoull(id_char, NULL, 0) : 0;
if (id_char != NULL)
g_free(id_char);
trace(TRACE_DEBUG, "%s,%s: returned value is [%llu]",__FILE__,__func__,
*user_idnr);
if (*user_idnr != 0)
return 1;
return 0;
}
/* Given a useridnr, find the account/login name
* return 0 if not found, NULL on error
*/
char *auth_get_userid(u64_t user_idnr)
{
char *returnid = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_uid, NULL };
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid, user_idnr);
returnid = __auth_get_first_match(query, fields);
trace(TRACE_DEBUG, "%s,%s: returned value is [%s]",__FILE__,__func__,
returnid);
return returnid;
}
/* We'd like to have -1 return on failure, but
* the internal ldap api here won't tell us. */
int auth_check_userid(u64_t user_idnr)
{
char *returnid = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_nid, NULL };
int ret;
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid, user_idnr);
returnid = __auth_get_first_match(query, fields);
if (returnid) {
ret = 0;
trace(TRACE_DEBUG, "%s,%s: found user_idnr [%llu]",
__FILE__, __func__, user_idnr);
} else {
ret = 1;
trace(TRACE_DEBUG, "%s,%s: didn't find user_idnr [%llu]",
__FILE__, __func__, user_idnr);
}
dm_free(returnid);
return ret;
}
/*
* Get the Client ID number
* Return 0 on successful failure
* Return -1 on really big failures
*/
int auth_getclientid(u64_t user_idnr, u64_t * client_idnr)
{
char *cid_char = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_cid, NULL };
assert(client_idnr != NULL);
*client_idnr = 0;
if (!user_idnr) {
trace(TRACE_ERROR,
"%s,%s: got NULL as useridnr",__FILE__,__func__);
return -1;
}
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid,
user_idnr);
cid_char = __auth_get_first_match(query, fields);
*client_idnr = (cid_char) ? strtoull(cid_char, NULL, 0) : 0;
if (cid_char != NULL)
g_free(cid_char);
trace(TRACE_DEBUG, "%s,%s: found client_idnr [%llu]",__FILE__,__func__,
*client_idnr);
return 1;
}
int auth_getmaxmailsize(u64_t user_idnr, u64_t * maxmail_size)
{
char *max_char;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_maxmail, NULL };
assert(maxmail_size != NULL);
*maxmail_size = 0;
if (!user_idnr) {
trace(TRACE_ERROR,
"%s,%s: got NULL as useridnr",__FILE__,__func__);
return 0;
}
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid,
user_idnr);
max_char = __auth_get_first_match(query, fields);
*maxmail_size = (max_char) ? strtoull(max_char, 0, 10) : 0;
if (max_char != NULL)
g_free(max_char);
trace(TRACE_DEBUG,
"%s,%s: returned value is [%llu]",__FILE__,__func__,
*maxmail_size);
return 1;
}
/*
* auth_getencryption()
*
* returns a string describing the encryption used for the passwd storage
* for this user.
* The string is valid until the next function call; in absence of any
* encryption the string will be empty (not null).
*
* If the specified user does not exist an empty string will be returned.
*/
char *auth_getencryption(u64_t user_idnr UNUSED)
{
/* ldap does not support fancy passwords, but return
* something valid for the sql shadow */
return "md5";
}
/* Fills the users list with all existing users
* return -2 on mem error, -1 on db-error, 0 on success */
GList * auth_get_known_users(void)
{
char *query;
char *fields[] = { _ldap_cfg.field_uid, NULL };
GList *users;
GList *entlist;
GString *t = g_string_new(_ldap_cfg.user_objectclass);
GList *l = g_string_split(t,",");
g_string_free(t,TRUE);
query = dm_ldap_get_filter('&',"objectClass",l);
entlist = __auth_get_every_match(query, fields);
g_free(query);
trace(TRACE_INFO, "%s,%s: found %d users",
__FILE__,__func__,
g_list_length(entlist));
users = dm_ldap_entdm_list_get_values(entlist);
dm_ldap_freeresult(entlist);
return users;
}
/*
* auth_check_user_ext()
*
* As auth_check_user() but adds the numeric ID of the user found
* to userids or the forward to the fwds.
*
* returns the number of occurences.
*/
int auth_check_user_ext(const char *address, struct dm_list *userids,
struct dm_list *fwds, int checks)
{
int occurences = 0;
u64_t id;
char *endptr = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_nid, _ldap_cfg.field_fwdtarget, NULL };
unsigned c2;
char *attrvalue;
GList *entlist, *fldlist, *attlist;
if (checks > 20) {
trace(TRACE_ERROR, "%s,%s: too many checks. Possible loop detected.",
__FILE__, __func__);
return 0;
}
trace(TRACE_DEBUG,
"%s,%s: checking user [%s] in alias table",__FILE__,__func__,
address);
/* This is my private line for sending a DN rather than a search */
snprintf(query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_mail, address);
trace(TRACE_DEBUG, "%s,%s: searching with query [%s], checks [%d]",
__FILE__,__func__, query, checks);
entlist = __auth_get_every_match(query, fields);
if (g_list_length(entlist) < 1) {
if (checks > 0) {
/* found the last one, this is the deliver to
* but checks needs to be bigger then 0 because
* else it could be the first query failure */
id = strtoull(address, &endptr, 10);
if (*endptr == 0) {
/* numeric deliver-to --> this is a userid */
trace(TRACE_DEBUG, "%s,%s: adding [%llu] to userids",__FILE__,__func__, id);
dm_list_nodeadd(userids, &id, sizeof(id));
} else {
trace(TRACE_DEBUG, "%s,%s: adding [%s] to forwards",__FILE__,__func__, address);
dm_list_nodeadd(fwds, address, strlen(address) + 1);
}
return 1;
} else {
trace(TRACE_DEBUG, "%s,%s: user [%s] not in aliases table",__FILE__,__func__, address);
dm_ldap_freeresult(entlist);
return 0;
}
}
trace(TRACE_DEBUG, "%s,%s: into checking loop",__FILE__,__func__);
entlist = g_list_first(entlist);
while (entlist) {
fldlist = g_list_first(entlist->data);
c2 = 0;
while(fldlist) {
attlist = g_list_first(fldlist->data);
while(attlist) {
attrvalue = (char *)attlist->data;
occurences += auth_check_user_ext(attrvalue, userids, fwds, checks+1);
if (! g_list_next(attlist))
break;
attlist = g_list_next(attlist);
}
if (! g_list_next(fldlist))
break;
fldlist = g_list_next(fldlist);
c2++;
}
if (! g_list_next(entlist))
break;
entlist = g_list_next(entlist);
}
dm_ldap_freeresult(entlist);
return occurences;
}
/*
* auth_adduser()
*
* adds a new user to the database
* and adds a INBOX..
* returns a 1 on succes, -1 on failure
*/
int auth_adduser(const char *username, const char *password,
const char *enctype UNUSED, u64_t clientid,
u64_t maxmail, u64_t * user_idnr)
{
int i, j, result;
/*int ret; unused variable */
int NUM_MODS = 9;
GString *nid = g_string_new("");
GString *cid = g_string_new("");
GString *maxm = g_string_new("");
u64_t newidnr = dm_ldap_get_freeid(_ldap_cfg.field_nid);
g_string_printf(nid,"%llu", newidnr);
g_string_printf(cid,"%llu",clientid);
g_string_printf(maxm,"%llu",maxmail);
char **obj_values = g_strsplit(_ldap_cfg.user_objectclass,",",0);
char *pw_values[] = { (char *)password, NULL };
char *uid_values[] = { (char *)username, NULL };
char *nid_values[] = { nid->str, NULL };
char *cid_values[] = { cid->str, NULL };
char *max_values[] = { maxm->str, NULL };
field_t mail_type = "mail";
field_t obj_type = "objectClass";
GString *t=g_string_new("");
assert(user_idnr != NULL);
*user_idnr = 0;
/* Construct the array of LDAPMod structures representing the attributes */
if (! (_ldap_mod = (LDAPMod **) dm_malloc((NUM_MODS + 1) * sizeof(LDAPMod *)))) {
trace(TRACE_ERROR, "%s,%s: Cannot allocate memory for mods array",
__FILE__, __func__);
return -1;
}
for (i = 0; i < NUM_MODS; i++) {
if (! (_ldap_mod[i] = (LDAPMod *) dm_malloc(sizeof(LDAPMod)))) {
trace(TRACE_ERROR, "%s,%s: Cannot allocate memory for mods element %d",
__FILE__, __func__, i);
for (j = 0; j < (i - 1); j++)
dm_free(_ldap_mod[j]);
dm_free(_ldap_mod);
return -1;
}
}
g_string_printf(t,"%s=%s,%s", _ldap_cfg.cn_string, username, _ldap_cfg.base_dn);
_ldap_dn=g_strdup(t->str);
g_string_free(t,TRUE);
trace(TRACE_DEBUG, "%s,%s: Adding user with DN of [%s]", __FILE__, __func__, _ldap_dn);
i = 0;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = obj_type;
_ldap_mod[i]->mod_values = obj_values;
if (strlen(_ldap_cfg.field_passwd) > 0) {
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = _ldap_cfg.field_passwd;
_ldap_mod[i]->mod_values = pw_values;
}
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = mail_type;
_ldap_mod[i]->mod_values = uid_values;
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = _ldap_cfg.field_uid;
_ldap_mod[i]->mod_values = uid_values;
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = _ldap_cfg.field_cid;
_ldap_mod[i]->mod_values = cid_values;
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = _ldap_cfg.field_maxmail;
_ldap_mod[i]->mod_values = max_values;
i++;
_ldap_mod[i]->mod_op = LDAP_MOD_ADD;
_ldap_mod[i]->mod_type = _ldap_cfg.field_nid;
_ldap_mod[i]->mod_values = nid_values;
i++;
_ldap_mod[i] = NULL;
_ldap_err = ldap_add_s(_ldap_conn, _ldap_dn, _ldap_mod);
g_strfreev(obj_values);
for (i = 0; i < NUM_MODS; i++)
dm_free(_ldap_mod[i]);
dm_free(_ldap_mod);
ldap_memfree(_ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: could not add user: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
return -1;
}
*user_idnr = newidnr;
result = db_user_create_shadow(username, user_idnr);
if (result != 1) {
trace(TRACE_ERROR, "%s,%s: sql shadow account creation failed",
__FILE__, __func__);
auth_delete_user(username);
*user_idnr=0;
return result;
}
return 1;
}
int auth_delete_user(const char *username)
{
/* look up who's got that username, get their dn, and delete it! */
if (!username) {
trace(TRACE_ERROR, "%s,%s: got NULL as useridnr",__FILE__,__func__);
return 0;
}
snprintf(_ldap_query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid, username);
if (auth_search(_ldap_query))
return -1;
if (ldap_count_entries(_ldap_conn, _ldap_res) < 1) {
trace(TRACE_DEBUG, "%s,%s: no entries found",__FILE__,__func__);
ldap_msgfree(_ldap_res);
return 0;
}
_ldap_msg = ldap_first_entry(_ldap_conn, _ldap_res);
if (_ldap_msg == NULL) {
ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err);
trace(TRACE_ERROR, "%s,%s: ldap_first_entry failed: %s",
__FILE__,__func__, ldap_err2string(_ldap_err));
ldap_msgfree(_ldap_res);
return -1;
}
_ldap_dn = ldap_get_dn(_ldap_conn, _ldap_msg);
if (_ldap_dn) {
trace(TRACE_DEBUG,
"%s,%s: deleting user at dn [%s]",__FILE__,__func__,
_ldap_dn);
_ldap_err = ldap_delete_s(_ldap_conn, _ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR,
"%s,%s: could not delete dn: %s",__FILE__,__func__,
ldap_err2string(_ldap_err));
ldap_memfree(_ldap_dn);
ldap_msgfree(_ldap_res);
return -1;
}
}
ldap_memfree(_ldap_dn);
ldap_msgfree(_ldap_res);
if (db_user_delete(username)) {
trace(TRACE_ERROR, "%s,%s: sql shadow account deletion failed",
__FILE__, __func__);
}
return 0;
}
static int dm_ldap_user_shadow_rename(u64_t user_idnr, const char *new_name)
{
char *oldname;
u64_t dbidnr;
oldname = auth_get_userid(user_idnr);
db_user_exists(oldname,&dbidnr);
if (dbidnr) {
trace(TRACE_DEBUG, "%s,%s: call db_user_rename ([%llu],[%s])\n",
__FILE__, __func__,
dbidnr, new_name);
}
if ((! dbidnr) || (db_user_rename(dbidnr, new_name))) {
trace(TRACE_ERROR, "%s,%s: renaming shadow account in db failed for [%llu]->[%s]",
__FILE__, __func__, user_idnr, new_name);
return -1;
}
return 0;
}
int auth_change_username(u64_t user_idnr, const char *new_name)
{
GString *newrdn;
if (!user_idnr) {
trace(TRACE_ERROR, "%s,%s: got NULL as useridnr",
__FILE__,__func__);
return -1;
}
if (!new_name) {
trace(TRACE_ERROR, "%s,%s: got NULL as new_name",
__FILE__,__func__);
return -1;
}
if (! (_ldap_dn = dm_ldap_user_getdn(user_idnr)))
return -1;
trace(TRACE_DEBUG, "%s,%s: got DN [%s]",
__FILE__,__func__,
_ldap_dn);
db_begin_transaction();
dm_ldap_user_shadow_rename(user_idnr, new_name);
/* perhaps we have to rename the dn */
if (strcmp(_ldap_cfg.field_uid,_ldap_cfg.cn_string)==0) {
newrdn = g_string_new("");
g_string_printf(newrdn,"%s=%s", _ldap_cfg.cn_string,new_name);
_ldap_err = ldap_modrdn_s(_ldap_conn, _ldap_dn, newrdn->str);
ldap_memfree(_ldap_dn);
g_string_free(newrdn,TRUE);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: error calling ldap_modrdn_s [%s]",
__FILE__,__func__,
ldap_err2string(_ldap_err));
db_rollback_transaction();
return -1;
}
db_commit_transaction();
return 0;
}
/* else we need to modify an attribute */
ldap_memfree(_ldap_dn);
if (dm_ldap_mod_field(user_idnr, _ldap_cfg.field_uid, new_name)) {
db_rollback_transaction();
return -1;
}
db_commit_transaction();
return 0;
}
int auth_change_password(u64_t user_idnr, const char *new_pass, const char *enctype UNUSED)
{
return dm_ldap_mod_field(user_idnr, _ldap_cfg.field_passwd, new_pass);
}
int auth_change_clientid(u64_t user_idnr, u64_t newcid)
{
char newcid_str[16];
snprintf(newcid_str, 16, "%llu", newcid);
return dm_ldap_mod_field(user_idnr, _ldap_cfg.field_cid, newcid_str);
}
int auth_change_mailboxsize(u64_t user_idnr, u64_t new_size)
{
int result;
char newsize_str[16];
snprintf(newsize_str, 16, "%llu", new_size);
if ((result = db_change_mailboxsize(user_idnr, new_size)))
return result;
return dm_ldap_mod_field(user_idnr, _ldap_cfg.field_maxmail, newsize_str);
}
/*
* auth_validate()
*
* tries to validate user 'user'
*
* returns useridnr on OK, 0 on validation failed, -1 on error
*/
int auth_validate(clientinfo_t *ci, char *username, char *password, u64_t * user_idnr)
{
timestring_t timestring;
char real_username[DM_USERNAME_LEN];
int result;
u64_t mailbox_idnr;
int ldap_err;
char *ldap_dn = NULL;
assert(user_idnr != NULL);
*user_idnr = 0;
if (username == NULL || password == NULL) {
trace(TRACE_DEBUG, "%s,%s: username or password is NULL",__FILE__,__func__);
return 0;
}
memset(real_username,'\0', sizeof(real_username));
create_current_timestring(×tring);
strncpy(real_username, username, DM_USERNAME_LEN);
if (db_use_usermap()) { /* use usermap */
result = db_usermap_resolve(ci, username, real_username);
if (result == DM_EGENERAL)
return 0;
if (result == DM_EQUERY)
return DM_EQUERY;
}
if (auth_user_exists(real_username, user_idnr) == -1) {
return -1;
}
if (! (ldap_dn = dm_ldap_user_getdn(*user_idnr))) {
trace(TRACE_ERROR,"%s,%s: unable to determine DN for user",
__FILE__, __func__);
return -1;
}
/* now, try to rebind as the given DN using the supplied password */
trace(TRACE_DEBUG, "%s,%s: rebinding as [%s] to validate password",
__FILE__,__func__,
ldap_dn);
ldap_err = ldap_bind_s(_ldap_conn, ldap_dn, password, LDAP_AUTH_SIMPLE);
if (ldap_err) {
trace(TRACE_ERROR, "%s,%s: ldap_bind_s failed: %s",
__FILE__,__func__,
ldap_err2string(ldap_err));
*user_idnr = 0;
} else {
/* FIXME: implement this in LDAP... log login in the database
snprintf(__auth_query_data, AUTH_QUERY_SIZE, "UPDATE users SET last_login = '%s' "
"WHERE user_idnr = '%llu'", timestring, id);
if (__auth_query(__auth_query_data)==-1)
trace(TRACE_ERROR, "%s,%s: could not update user login time",__FILE__,__func__);
*/
}
/* rebind as admin */
auth_ldap_bind();
if (ldap_dn)
ldap_memfree(ldap_dn);
if (*user_idnr == 0)
return 0;
db_find_create_mailbox("INBOX", BOX_DEFAULT, *user_idnr, &mailbox_idnr);
return 1;
}
/* returns useridnr on OK, 0 on validation failed, -1 on error */
u64_t auth_md5_validate(clientinfo_t *ci UNUSED, char *username UNUSED,
unsigned char *md5_apop_he UNUSED,
char *apop_stamp UNUSED)
{
return -1;
}
/**
* \brief get user ids belonging to a client id
* \param client_id
* \param user_ids
* \param num_users
* \return
* - -2 on memory error
* - -1 on database error
* - 1 on success
*/
int auth_get_users_from_clientid(u64_t client_id UNUSED,
/*@out@*/ u64_t ** user_ids UNUSED,
/*@out@*/ unsigned *num_users UNUSED)
{
return 1;
}
/**
* \brief get a list of aliases associated with a user's user_idnr
* \param user_idnr idnr of user
* \param aliases list of aliases
* \return
* - -2 on memory failure
* - -1 on database failure
* - 0 on success
* \attention aliases list needs to be empty. Method calls dm_list_init()
* which sets list->start to NULL.
*/
GList * auth_get_user_aliases(u64_t user_idnr)
{
char *fields[] = { _ldap_cfg.field_mail, NULL };
GString *t = g_string_new("");
GList *aliases = NULL;
GList *entlist, *fldlist, *attlist;
g_string_printf(t,"%s=%llu", _ldap_cfg.field_nid, user_idnr);
if ((entlist = __auth_get_every_match(t->str, fields))) {
entlist = g_list_first(entlist);
fldlist = g_list_first(entlist->data);
attlist = g_list_first(fldlist->data);
while (attlist) {
aliases = g_list_append(aliases, g_strdup(attlist->data));
if (! g_list_next(attlist))
break;
attlist = g_list_next(attlist);
}
dm_ldap_freeresult(entlist);
}
g_string_free(t,TRUE);
return aliases;
}
/**
* \brief get a list of aliases associated with a user's user_idnr
* \param user_idnr idnr of user
* \param aliases list of aliases
* \return
* - -2 on memory failure
* - -1 on database failure
* - 0 on success
* \attention aliases list needs to be empty. Method calls dm_list_init()
* which sets list->start to NULL.
*/
GList * auth_get_aliases_ext(const char *alias)
{
char *fields[] = { _ldap_cfg.field_fwdtarget, NULL };
GString *t = g_string_new("");
GList *aliases = NULL;
GList *entlist, *fldlist, *attlist;
g_string_printf(t,"%s=%s", _ldap_cfg.field_mail, alias);
if ((entlist = __auth_get_every_match(t->str, fields))) {
entlist = g_list_first(entlist);
fldlist = g_list_first(entlist->data);
attlist = g_list_first(fldlist->data);
while (attlist) {
aliases = g_list_append(aliases, g_strdup(attlist->data));
if (! g_list_next(attlist))
break;
attlist = g_list_next(attlist);
}
dm_ldap_freeresult(entlist);
}
g_string_free(t,TRUE);
return aliases;
}
/**
* \brief add an alias for a user
* \param user_idnr user's id
* \param alias new alias
* \param clientid client id
* \return
* - -1 on failure
* - 0 on success
* - 1 if alias already exists for given user
*/
int auth_addalias(u64_t user_idnr, const char *alias, u64_t clientid UNUSED)
{
char *userid = NULL;
char **mailValues = NULL;
LDAPMod *modify[2], addMail;
GList *aliases;
if (! (userid = auth_get_userid(user_idnr)))
return -1;
/* check the alias newval against the known aliases for this user */
aliases = auth_get_user_aliases(user_idnr);
aliases = g_list_first(aliases);
while (aliases) {
if (strcmp(alias,(char *)aliases->data)==0) {
g_list_foreach(aliases,(GFunc)g_free,NULL);
g_list_free(aliases);
return 1;
}
if (! g_list_next(aliases))
break;
aliases = g_list_next(aliases);
}
g_list_foreach(aliases,(GFunc)g_free,NULL);
g_list_free(aliases);
/* get the DN for this user */
if (! (_ldap_dn = dm_ldap_user_getdn(user_idnr)))
return -1;
/* construct and apply the changes */
mailValues = g_strsplit(alias,",",1);
addMail.mod_op = LDAP_MOD_ADD;
addMail.mod_type = _ldap_cfg.field_mail;
addMail.mod_values = mailValues;
modify[0] = &addMail;
modify[1] = NULL;
_ldap_err = ldap_modify_s(_ldap_conn, _ldap_dn, modify);
g_strfreev(mailValues);
ldap_memfree(_ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: update failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
return -1;
}
return 0;
}
/**
* \brief add an alias to deliver to an extern address
* \param alias the alias
* \param deliver_to extern address to deliver to
* \param clientid client idnr
* \return
* - -1 on failure
* - 0 on success
* - 1 if deliver_to already exists for given alias
*/
/* find forwarding alias
* \return
* - -1 error
* - 0 success
* - 1 dn exists but no such deliver_to
*/
static int forward_exists(const char *alias, const char *deliver_to)
{
char *objectfilter, *dn;
char *fields[] = { "dn", _ldap_cfg.field_fwdtarget, NULL };
int result = 0;
GString *t = g_string_new(_ldap_cfg.forw_objectclass);
GList *l = g_string_split(t,",");
objectfilter = dm_ldap_get_filter('&',"objectClass", l);
g_string_printf(t,"(&%s(%s=%s)(%s=%s))", objectfilter, _ldap_cfg.cn_string, alias, _ldap_cfg.field_fwdtarget, deliver_to);
dn = __auth_get_first_match(t->str, fields);
if (! dn) {
result = -1; // assume total failure;
g_string_printf(t,"(&%s(%s=%s))", objectfilter, _ldap_cfg.cn_string, alias);
dn = __auth_get_first_match(t->str, fields);
if (dn)
result = 1; // dn does exist, just this forward is missing
}
g_free(objectfilter);
dm_free(dn);
g_string_free(t,TRUE);
g_list_foreach(l,(GFunc)g_free,NULL);
trace(TRACE_DEBUG, "%s,%s: result [%d]", __FILE__, __func__, result);
return result;
}
static int forward_create(const char *alias, const char *deliver_to)
{
LDAPMod *mods[5], objectClass, cnField, mailField, forwField;
char **obj_values = g_strsplit(_ldap_cfg.forw_objectclass,",",0);
char *cn_values[] = { (char *)alias, NULL };
char *mail_values[] = { (char *)alias, NULL };
char *forw_values[] = { (char *)deliver_to, NULL };
GString *t=g_string_new("");
g_string_printf(t,"%s=%s,%s", _ldap_cfg.cn_string, alias, _ldap_cfg.base_dn);
_ldap_dn=g_strdup(t->str);
g_string_free(t,TRUE);
trace(TRACE_DEBUG, "%s,%s: Adding forwardingAddress with DN of [%s]",
__FILE__, __func__,
_ldap_dn);
objectClass.mod_op = LDAP_MOD_ADD;
objectClass.mod_type = "objectClass";
objectClass.mod_values = obj_values;
cnField.mod_op = LDAP_MOD_ADD;
cnField.mod_type = _ldap_cfg.cn_string;
cnField.mod_values = cn_values;
mailField.mod_op = LDAP_MOD_ADD;
mailField.mod_type = _ldap_cfg.field_mail;
mailField.mod_values = mail_values;
forwField.mod_op = LDAP_MOD_ADD;
forwField.mod_type = _ldap_cfg.field_fwdtarget;
forwField.mod_values = forw_values;
mods[0] = &objectClass;
mods[1] = &cnField;
mods[2] = &mailField;
mods[3] = &forwField;
mods[4] = NULL;
trace(TRACE_DEBUG, "%s,%s: creating new forward [%s] -> [%s]", __FILE__, __func__, alias, deliver_to);
_ldap_err = ldap_add_s(_ldap_conn, _ldap_dn, mods);
g_strfreev(obj_values);
ldap_memfree(_ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: could not add forwardingAddress: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
return -1;
}
return 0;
}
static int forward_add(const char *alias,const char *deliver_to)
{
char **mailValues = NULL;
LDAPMod *modify[2], addForw;
GString *t=g_string_new("");
g_string_printf(t,"%s=%s,%s", _ldap_cfg.cn_string, alias, _ldap_cfg.base_dn);
_ldap_dn=g_strdup(t->str);
g_string_free(t,TRUE);
/* construct and apply the changes */
mailValues = g_strsplit(deliver_to,",",1);
addForw.mod_op = LDAP_MOD_ADD;
addForw.mod_type = _ldap_cfg.field_fwdtarget;
addForw.mod_values = mailValues;
modify[0] = &addForw;
modify[1] = NULL;
trace(TRACE_DEBUG, "%s,%s: creating additional forward [%s] -> [%s]", __FILE__, __func__, alias, deliver_to);
_ldap_err = ldap_modify_s(_ldap_conn, _ldap_dn, modify);
g_strfreev(mailValues);
ldap_memfree(_ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: update failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
return -1;
}
return 0;
}
static int forward_delete(const char *alias, const char *deliver_to)
{
char **mailValues = NULL;
LDAPMod *modify[2], delForw;
GString *t=g_string_new("");
g_string_printf(t,"%s=%s,%s", _ldap_cfg.cn_string, alias, _ldap_cfg.base_dn);
_ldap_dn=g_strdup(t->str);
g_string_free(t,TRUE);
/* construct and apply the changes */
mailValues = g_strsplit(deliver_to,",",1);
delForw.mod_op = LDAP_MOD_DELETE;
delForw.mod_type = _ldap_cfg.field_fwdtarget;
delForw.mod_values = mailValues;
modify[0] = &delForw;
modify[1] = NULL;
trace(TRACE_DEBUG, "%s,%s: delete additional forward [%s] -> [%s]",
__FILE__, __func__, alias, deliver_to);
_ldap_err = ldap_modify_s(_ldap_conn, _ldap_dn, modify);
g_strfreev(mailValues);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: update failed: [%d] %s",
__FILE__,__func__, _ldap_err,
ldap_err2string(_ldap_err));
trace(TRACE_DEBUG, "%s,%s: delete additional forward failed, removing dn [%s]",
__FILE__, __func__, _ldap_dn);
_ldap_err = ldap_delete_s(_ldap_conn, _ldap_dn);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: deletion failed [%s]",
__FILE__, __func__,
ldap_err2string(_ldap_err));
}
}
ldap_memfree(_ldap_dn);
return 0;
}
int auth_addalias_ext(const char *alias, const char *deliver_to, u64_t clientid UNUSED)
{
switch(forward_exists(alias,deliver_to)) {
case -1:
return forward_create(alias,deliver_to);
case 1:
return forward_add(alias,deliver_to);
}
return 0;
}
/**
* \brief remove alias for user
* \param user_idnr user id
* \param alias the alias
* \return
* - -1 on failure
* - 0 on success
*/
int auth_removealias(u64_t user_idnr, const char *alias)
{
char *userid = NULL;
char **mailValues = NULL;
LDAPMod *modify[2], delMail;
GList *aliases;
if (! (userid = auth_get_userid(user_idnr)))
return -1;
/* check the alias against the known aliases for this user */
aliases = auth_get_user_aliases(user_idnr);
aliases = g_list_first(aliases);
while (aliases) {
if (strcmp(alias,(char *)aliases->data)==0)
break;
if (! g_list_next(aliases))
break;
aliases = g_list_next(aliases);
}
if (!aliases) {
trace(TRACE_DEBUG,"%s,%s: alias [%s] for user [%s] not found",
__FILE__, __func__,
alias, userid);
g_list_foreach(aliases,(GFunc)g_free,NULL);
g_list_free(aliases);
return 1;
}
g_list_foreach(aliases,(GFunc)g_free,NULL);
g_list_free(aliases);
/* get the DN for this user */
if (! (_ldap_dn = dm_ldap_user_getdn(user_idnr)))
return -1;
/* construct and apply the changes */
mailValues = g_strsplit(alias,",",1);
delMail.mod_op = LDAP_MOD_DELETE;
delMail.mod_type = _ldap_cfg.field_mail;
delMail.mod_values = mailValues;
modify[0] = &delMail;
modify[1] = NULL;
_ldap_err = ldap_modify_s(_ldap_conn, _ldap_dn, modify);
if (_ldap_err) {
trace(TRACE_ERROR, "%s,%s: update failed: %s",
__FILE__,__func__,
ldap_err2string(_ldap_err));
g_strfreev(mailValues);
ldap_memfree(_ldap_dn);
return -1;
}
g_strfreev(mailValues);
ldap_memfree(_ldap_dn);
return 0;
}
/**
* \brief remove external delivery address for an alias
* \param alias the alias
* \param deliver_to the deliver to address the alias is
* pointing to now
* \return
* - -1 on failure
* - 0 on success
*/
int auth_removealias_ext(const char *alias, const char *deliver_to)
{
int check;
check = forward_exists(alias,deliver_to);
if (check)
return 0;
return forward_delete(alias,deliver_to);
}
gboolean auth_requires_shadow_user(void)
{
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1