diff options
author | paul <paul@7b491191-dbf0-0310-aff6-d879d4d69008> | 2005-02-07 12:15:55 +0000 |
---|---|---|
committer | paul <paul@7b491191-dbf0-0310-aff6-d879d4d69008> | 2005-02-07 12:15:55 +0000 |
commit | 2f2151ed6c55e042c39a9bb39683a4b8bf0d35b6 (patch) | |
tree | 60814d82abbc3dc9f08e8fa3a407dad3d398c76b | |
parent | e0cbe72e5c09c0dda71a15c056bc110c4afaf59c (diff) |
authldap and delivery fixes
git-svn-id: https://svn.ic-s.nl/svn/dbmail/trunk/dbmail@1589 7b491191-dbf0-0310-aff6-d879d4d69008
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | auth.h | 22 | ||||
-rw-r--r-- | auth/authldap.c | 1393 | ||||
-rw-r--r-- | auth/authsql.c | 182 | ||||
-rw-r--r-- | check_dbmail.h | 4 | ||||
-rw-r--r-- | check_dbmail_deliver.c | 155 | ||||
-rw-r--r-- | check_dbmail_imapd.c | 2 | ||||
-rw-r--r-- | check_dbmail_message.c | 10 | ||||
-rw-r--r-- | db.c | 116 | ||||
-rw-r--r-- | db.h | 30 | ||||
-rw-r--r-- | dbmail-message.c | 139 | ||||
-rw-r--r-- | dbmail-message.h | 15 | ||||
-rw-r--r-- | dbmail.h | 1 | ||||
-rwxr-xr-x | debian/rules | 5 | ||||
-rw-r--r-- | imaputil.c | 50 | ||||
-rw-r--r-- | imaputil.h | 4 | ||||
-rw-r--r-- | list.c | 13 | ||||
-rw-r--r-- | list.h | 2 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | misc.c | 51 | ||||
-rw-r--r-- | misc.h | 6 | ||||
-rw-r--r-- | pipe.c | 18 | ||||
-rw-r--r-- | user.c | 256 |
24 files changed, 1072 insertions, 1423 deletions
@@ -1,3 +1,17 @@ +2005-02-07 Paul Stevens <paul@nfg.nl> + + * auth.h, auth/authsql.c, auth/authldap.c: first wave of authldap + fixes. + * check_dbmail_deliver.c: implement testcases for auth.h api. The rest + of the tests for the delivery chain is still todo. + * user.c: change output from dbmail-users -l to make it machine + parseable and emulate unix getent standard. + * db.c, dbmail-message.c: move db_insert_message functionality to dbmail-message.c + * misc.c, imaputil.c: move some generic utilities to misc.c. + * list.c (g_list_copy_list): added shallow copy of old-style list to + glist. + * pipe.c, dbmail-message.c: cleanup dbmail_message_store_temp. + 2005-01-26 Paul Stevens <paul@nfg.nl> * imaputil.c, imapcommands.c (_ic_search): introduce sort_search which diff --git a/Makefile.am b/Makefile.am index f3e237d8..02083167 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,12 @@ SERVER = server.c serverchild.c pool.c DELIVER = pipe.c forward.c dsn.c # CFLAGS +if LDAP +AM_CFLAGS = -fomit-frame-pointer -DAUTHLDAP +else AM_CFLAGS = -fomit-frame-pointer +endif + INCLUDES = -I$(top_srcdir) dbmail_smtp_SOURCES = main.c @@ -117,15 +117,19 @@ char *auth_getencryption(u64_t user_idnr); /** * \brief find all deliver_to addresses for a username (?, code is not exactly - * clear to me at the moment, IB 21-08-03) + * clear to me at the moment, IB 21-08-03) + * + * Unused so I removed it, PS 30-01-05 + * * \param username * \param userids list of user ids (empty on call) * \param checks nr of checks. Used internally in recursive calls. It \b should * be set to -1 when called! * \return number of deliver_to addresses found */ -int auth_check_user(const char *username, struct list *userids, - int checks); +//int auth_check_user(const char *username, struct list *userids, +// int checks); + /** * \brief as auth_check_user() but adds the numeric ID of the user found to * userids or the forward to the fwds list @@ -268,10 +272,8 @@ char *auth_get_deliver_from_alias(const char *alias); * - -2 on memory failure * - -1 on database failure * - 0 on success - * \attention aliases list needs to be empty. Method calls list_init() - * which sets list->start to NULL. */ -int auth_get_user_aliases(u64_t user_idnr, struct list *aliases); +GList * auth_get_user_aliases(u64_t user_idnr); /** * \brief add an alias for a user * \param user_idnr user's id @@ -315,5 +317,13 @@ int auth_removealias(u64_t user_idnr, const char *alias); */ int auth_removealias_ext(const char *alias, const char *deliver_to); +#ifdef AUTHLDAP + +char *dm_ldap_get_filter(const gchar boolean, const gchar *attribute, GList *values); +u64_t dm_ldap_get_freeid(const gchar *attribute); +GList * dm_ldap_entlist_get_values(GList *entlist); + +#endif + #endif diff --git a/auth/authldap.c b/auth/authldap.c index 3e2467bf..f8894a15 100644 --- a/auth/authldap.c +++ b/auth/authldap.c @@ -39,6 +39,7 @@ #include <string.h> //#include <crypt.h> #include <time.h> +#include <glib.h> #define AUTH_QUERY_SIZE 1024 #define LDAP_RES_SIZE 1024 @@ -57,18 +58,13 @@ char **_ldap_attrs = NULL; char _ldap_query[AUTH_QUERY_SIZE]; typedef struct _ldap_cfg { - field_t bind_dn, - bind_pw, base_dn, port, scope, hostname, objectclass; - field_t field_uid, - field_cid, - field_nid, - field_mail, - field_mailalt, - mailaltprefix, - field_maxmail, - field_passwd, - field_fwd, - field_fwdsave, field_fwdtarget, fwdtargetprefix, field_members; + field_t bind_dn, bind_pw, base_dn, port, scope, hostname, 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; } _ldap_cfg_t; @@ -88,31 +84,33 @@ _ldap_cfg_t _ldap_cfg; static void __auth_get_config(void); -static void __auth_get_config() +static GList * __auth_get_every_match(const char *q, char **retfields); + + +void __auth_get_config(void) { config_read(configFile); SetTraceLevel("LDAP"); - 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("HOSTNAME", "LDAP", _ldap_cfg.hostname); - GETCONFIGVALUE("OBJECTCLASS", "LDAP", _ldap_cfg.objectclass); - GETCONFIGVALUE("FIELD_UID", "LDAP", _ldap_cfg.field_uid); - GETCONFIGVALUE("FIELD_CID", "LDAP", _ldap_cfg.field_cid); - GETCONFIGVALUE("FIELD_NID", "LDAP", _ldap_cfg.field_nid); - GETCONFIGVALUE("FIELD_MAIL", "LDAP", _ldap_cfg.field_mail); - GETCONFIGVALUE("FIELD_MAILALT", "LDAP", _ldap_cfg.field_mailalt); - GETCONFIGVALUE("MAILALTPREFIX", "LDAP", _ldap_cfg.mailaltprefix); - GETCONFIGVALUE("FIELD_QUOTA", "LDAP", _ldap_cfg.field_maxmail); - GETCONFIGVALUE("FIELD_PASSWD", "LDAP", _ldap_cfg.field_passwd); - GETCONFIGVALUE("FIELD_FORWARD", "LDAP", _ldap_cfg.field_fwd); - GETCONFIGVALUE("FIELD_FWDSAVE", "LDAP", _ldap_cfg.field_fwdsave); - GETCONFIGVALUE("FIELD_FWDTARGET", "LDAP", _ldap_cfg.field_fwdtarget); - GETCONFIGVALUE("FWDTARGETPREFIX", "LDAP", _ldap_cfg.fwdtargetprefix); - GETCONFIGVALUE("FIELD_MEMBERS", "LDAP", _ldap_cfg.field_members); - GETCONFIGVALUE("SCOPE", "LDAP", _ldap_cfg.scope); + 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("HOSTNAME", "LDAP", _ldap_cfg.hostname); + GETCONFIGVALUE("OBJECTCLASS", "LDAP", _ldap_cfg.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); @@ -120,9 +118,7 @@ static void __auth_get_config() /* 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); + 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; @@ -155,12 +151,10 @@ int auth_disconnect(void) { /* Destroy the connection */ if (_ldap_conn != NULL) { - trace(TRACE_DEBUG, - "%s,%s: disconnecting from ldap server",__FILE__,__func__); + trace(TRACE_DEBUG, "%s,%s: disconnecting from ldap server",__FILE__,__func__); ldap_unbind(_ldap_conn); } else { - trace(TRACE_DEBUG, - "%s,%s: was already disconnected from ldap server",__FILE__,__func__); + trace(TRACE_DEBUG, "%s,%s: was already disconnected from ldap server",__FILE__,__func__); } return 0; } @@ -185,51 +179,158 @@ int auth_reconnect(void) { auth_disconnect(); /* ...and make anew! */ - trace(TRACE_DEBUG, - "%s,%s: connecting to ldap server on [%s] : [%d]",__FILE__,__func__, - _ldap_cfg.hostname, _ldap_cfg.port_int); - _ldap_conn = ldap_init(_ldap_cfg.hostname, _ldap_cfg.port_int); - trace(TRACE_DEBUG, - "%s,%s: binding to ldap server as [%s] / [%s]",__FILE__,__func__, - _ldap_cfg.bind_dn, _ldap_cfg.bind_pw); - _ldap_err = - ldap_bind_s(_ldap_conn, _ldap_cfg.bind_dn, _ldap_cfg.bind_pw, - LDAP_AUTH_SIMPLE); - if (_ldap_err) { - trace(TRACE_ERROR, - "%s,%s: ldap_bind_s failed: %s",__FILE__,__func__, - ldap_err2string(_ldap_err)); + trace(TRACE_DEBUG, "%s,%s: connecting to ldap server on [%s] : [%d]", + __FILE__,__func__, + _ldap_cfg.hostname, + _ldap_cfg.port_int); + + _ldap_conn = ldap_init( + _ldap_cfg.hostname, + _ldap_cfg.port_int); + + 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__); + trace(TRACE_DEBUG, "%s,%s: successfully bound to ldap server", + __FILE__,__func__); return 0; } -/* -int __auth_add(const char *q) +void dm_ldap_freeresult(GList *entlist) { - LDAP *__ldap_conn; - 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]; - - if (!q) - { - trace(TRACE_ERROR, "%s,%s: got NULL query",__FILE__,__func__); - return 0; - } + 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); + fldlist = g_list_next(fldlist); + } + entlist = g_list_next(entlist); + } } -*/ -/* - * The list that goes into retlist is really big and scary. - * Here's how it works... + +GList * dm_ldap_entlist_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", g_strdup(tmp)); + attlist = g_list_next(attlist); + } + fldlist = g_list_next(fldlist); + } + entlist = g_list_next(entlist); + } + return values; +} + +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); + do { + g_string_printf(t,"%s=%s", attribute, (char *)values->data); + l = g_list_append(l,g_strdup(t->str)); + } while ((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,FALSE); + g_string_free(q,FALSE); + g_list_foreach(l,(GFunc)g_free,NULL); + g_list_free(l); + + return s; +} + +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(""); + GHashTable *ht; + + g_string_printf(q,"(%s=*)", attribute); + entlist = __auth_get_every_match(q->str, attrs); + + ids = dm_ldap_entlist_get_values(entlist); + trace(TRACE_DEBUG,"%s,%s: found [%d] matches\n", + __FILE__,__func__, + g_list_length(ids)); + + 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); + } + + ht = g_hash_table_new((GHashFunc)g_int_hash,(GEqualFunc)g_int_equal); + ids = g_list_first(ids); + while(ids) { + t = strtoull(ids->data,NULL,10); + if ((t) && (t >= min) && ((max) && (t <= max))) + g_hash_table_insert(ht, (gpointer)(&t), (gpointer)(ids->data)); + ids = g_list_next(ids); + } + for (t = min; t < max; t++) { + if (! (g_hash_table_lookup(ht, (gpointer)(&t)))) + break; + } + if ((t >= min) && (t <= max)) + id=t; + + trace(TRACE_DEBUG,"%s,%s: return free id [%llu]\n", + __FILE__, __func__, + id); + return id; +} + +/* OLD-SCHOOL: * * Each node of retlist contains a data field * which is a pointer to another list, "fieldlist". @@ -258,298 +359,111 @@ int __auth_add(const char *q) * } * } * - * */ - -/* returns the number of matches found */ -int __auth_get_one_entry(const char *q, char **retfields, - struct list *retlist) -{ - LDAPMessage *ldap_res; - LDAPMessage *ldap_msg; - int ldap_err; - int ldap_attrsonly = 0; - /* char *ldap_dn; this variable is unused */ - char **ldap_vals; - char **ldap_attrs = NULL; - char ldap_query[AUTH_QUERY_SIZE]; - int i = 0, j = 0, k = 0, m = 0; - struct list fieldlist, datalist; - - if (!q) { - trace(TRACE_ERROR, - "%s,%s: got NULL query",__FILE__,__func__); - goto endnofree; - } - - auth_reconnect(); - - snprintf(ldap_query, AUTH_QUERY_SIZE, "%s", q); - trace(TRACE_DEBUG, - "%s,%s: retrieving entry for DN [%s]",__FILE__,__func__, - ldap_query); - ldap_err = - ldap_search_s(_ldap_conn, ldap_query, LDAP_SCOPE_BASE, - "(objectClass=*)", ldap_attrs, ldap_attrsonly, - &ldap_res); - if (ldap_err) { - trace(TRACE_ERROR, - "%s,%s: could not retrieve DN: %s",__FILE__,__func__, - ldap_err2string(ldap_err)); - goto endnofree; - } - - /* we're just using a little counter variable, - * since we'll use it in the for loop later */ - j = ldap_count_entries(_ldap_conn, ldap_res); - - if (j < 1) { - trace(TRACE_DEBUG, "%s,%s: none found",__FILE__,__func__); - goto endnofree; - } - - /* do the first entry here */ - 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 endnofree; - } - - list_init(retlist); - - /* we'll get the next entry at the _end_ of the loop! */ - /* get the entries to populate retlist */ - for (i = 0; i < j; i++) { - /* init this list for the field values */ - list_init(&fieldlist); - - /* get the fields to populate fieldlist */ - for (k = 0; retfields[k] != NULL; k++) { - /* init this list for the data values */ - list_init(&datalist); - - /* get the values to populate datalist */ - ldap_vals = - ldap_get_values(_ldap_conn, ldap_msg, - retfields[k]); - if (ldap_vals == NULL) { - ldap_get_option(_ldap_conn, - LDAP_OPT_ERROR_NUMBER, - &ldap_err); - trace(TRACE_ERROR, - "%s,%s: ldap_get_values failed: %s",__FILE__,__func__, - ldap_err2string(ldap_err)); - /* no need to break, because we WANT the list to contain an entry - * for each attribute, even if it is simply the freshly-initialized - * list, which has no nodes -- that's just fine by us and our consumers - break; - */ - } else { - for (m = 0; ldap_vals[m] != NULL; m++) { - /* add the value to the list */ - if (!list_nodeadd - (&datalist, ldap_vals[m], - strlen(ldap_vals[m]) + 1)) { - trace(TRACE_ERROR, - "%s,%s: could not add ldap_vals to &datalist",__FILE__,__func__); - list_freelist(&datalist. - start); - break; - } - } - } - /* add the value to the list */ - if (!list_nodeadd - (&fieldlist, &datalist, sizeof(struct list))) { - trace(TRACE_ERROR, - "%s,%s: could not add &datalist to &fieldlist",__FILE__,__func__); - list_freelist(&fieldlist.start); - break; - } - /* free the values as we use them */ - ldap_value_free(ldap_vals); - } - /* add the value to the list */ - if (!list_nodeadd - (retlist, &fieldlist, sizeof(struct list))) { - trace(TRACE_ERROR, - "%s,%s: could not add &fieldlist to retlist",__FILE__,__func__); - list_freelist(&retlist->start); - goto endfree; - } - - /* do the next entry here */ - ldap_msg = ldap_next_entry(_ldap_conn, ldap_msg); - if (ldap_msg == NULL) { - ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, - &ldap_err); - trace(TRACE_ERROR, - "%s,%s: ldap_next_entry failed: %s",__FILE__,__func__, - ldap_err2string(ldap_err)); - //goto endfree; - break; - } - } - - endfree: - if (ldap_res) - ldap_msgfree(ldap_res); + * TODO: GLIB-STYLIE: + * + * ghashtable *ldap_entities + * { + * gchar *dn; + * ghashtable *ldap_attributes { + * gchar *attribute; + * glist *values; + * } + * } + * + */ - endnofree: - return j; /* remember, j = ldap_count_entries() */ -} /* returns the number of matches found */ -int __auth_get_every_match(const char *q, char **retfields, - struct list *retlist) +GList * __auth_get_every_match(const char *q, char **retfields) { LDAPMessage *ldap_res; LDAPMessage *ldap_msg; int ldap_err; int ldap_attrsonly = 0; - /* char *ldap_dn; usunused variable */ + char *dn; char **ldap_vals; char **ldap_attrs = NULL; char ldap_query[AUTH_QUERY_SIZE]; - int i = 0, j = 0, k = 0, m = 0; - struct list fieldlist, datalist; + int j = 0, k = 0, m = 0; + GList *attlist,*fldlist,*entlist; + + attlist = fldlist = entlist = NULL; if (!q) { - trace(TRACE_ERROR, - "%s,%s: got NULL query",__FILE__,__func__); - goto endnofree; + trace(TRACE_ERROR, "%s,%s: got NULL query",__FILE__,__func__); + return NULL; } auth_reconnect(); snprintf(ldap_query, AUTH_QUERY_SIZE, "%s", q); - trace(TRACE_DEBUG, - "%s,%s: searching with query [%s]",__FILE__,__func__, - ldap_query); - ldap_err = - ldap_search_s(_ldap_conn, _ldap_cfg.base_dn, - _ldap_cfg.scope_int, ldap_query, ldap_attrs, - ldap_attrsonly, &ldap_res); - if (ldap_err) { - trace(TRACE_ERROR, - "%s,%s: could not execute query: %s",__FILE__,__func__, + trace(TRACE_DEBUG, "%s,%s: search with query [%s]",__FILE__,__func__, ldap_query); + + if ((ldap_err = ldap_search_s(_ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, + ldap_query, ldap_attrs, ldap_attrsonly, &ldap_res))) { + trace(TRACE_ERROR, "%s,%s: query failed: %s",__FILE__,__func__, ldap_err2string(ldap_err)); - if (ldap_res != NULL) + if (ldap_res) ldap_msgfree(ldap_res); - goto endnofree; + return NULL; } - /* we're just using a little counter variable, - * since we'll use it in the for loop later */ - j = ldap_count_entries(_ldap_conn, ldap_res); - - if (j < 1) { - trace(TRACE_DEBUG, "%s,%s: none found",__FILE__,__func__); - if (ldap_res != 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); - goto endnofree; + return NULL; } /* do the first entry here */ - 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__, + 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 != NULL) + if (ldap_res) ldap_msgfree(ldap_res); - goto endnofree; + return NULL; } - list_init(retlist); - - /* we'll get the next entry at the _end_ of the loop! */ - /* get the entries to populate retlist */ - for (i = 0; i < j; i++) { - /* init this list for the field values */ - list_init(&fieldlist); - - /* get the fields to populate fieldlist */ + 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++) { - /* init this list for the data values */ - list_init(&datalist); - - /* get the values to populate datalist */ - ldap_vals = - ldap_get_values(_ldap_conn, ldap_msg, - retfields[k]); - if (ldap_vals == NULL) { - ldap_get_option(_ldap_conn, - LDAP_OPT_ERROR_NUMBER, - &ldap_err); - trace(TRACE_ERROR, - "%s,%s: ldap_get_values failed: %s",__FILE__,__func__, - ldap_err2string(ldap_err)); - /* no need to break, because we WANT the list to contain an entry - * for each attribute, even if it is simply the freshly-initialized - * list, which has no nodes -- that's just fine by us and our consumers - break; - */ + 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_ERROR, "%s,%s: ldap_get_values failed: [%s] %s", + __FILE__,__func__, + retfields[k], + ldap_err2string(ldap_err)); } else { - for (m = 0; ldap_vals[m] != NULL; m++) { - /* add the value to the list */ - if (!list_nodeadd - (&datalist, ldap_vals[m], - strlen(ldap_vals[m]) + 1)) { - trace(TRACE_ERROR, - "%s,%s: could not add ldap_vals to &datalist",__FILE__,__func__); - list_freelist(&datalist. - start); - break; - } + 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++; } } - /* add the value to the list */ - if (!list_nodeadd - (&fieldlist, &datalist, sizeof(struct list))) { - trace(TRACE_ERROR, - "%s,%s: could not add &datalist to &fieldlist",__FILE__,__func__); - list_freelist(&fieldlist.start); - break; - } - /* free the values as we use them */ + fldlist = g_list_append(fldlist, attlist); + attlist = NULL; + ldap_value_free(ldap_vals); } - /* add the value to the list */ - if (!list_nodeadd - (retlist, &fieldlist, sizeof(struct list))) { - trace(TRACE_ERROR, - "%s,%s: could not add &fieldlist to retlist",__FILE__,__func__); - list_freelist(&retlist->start); - goto endfree; - } + entlist = g_list_append(entlist, fldlist); + fldlist = NULL; - /* do the next entry here */ ldap_msg = ldap_next_entry(_ldap_conn, ldap_msg); - if (ldap_msg == NULL) { - ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, - &ldap_err); - trace(TRACE_ERROR, - "%s,%s: ldap_next_entry failed: %s",__FILE__,__func__, - ldap_err2string(ldap_err)); - //goto endfree; - break; - } } - endfree: if (ldap_res) ldap_msgfree(ldap_res); if (ldap_msg) ldap_msgfree(ldap_msg); - endnofree: - return j; /* remember, j = ldap_count_entries() */ + return entlist; } char *__auth_get_first_match(const char *q, char **retfields) @@ -648,6 +562,7 @@ int auth_user_exists(const char *username, u64_t * 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; @@ -657,10 +572,14 @@ int auth_user_exists(const char *username, u64_t * user_idnr) if (id_char) dm_free(id_char); - if (*user_idnr == 0) + if (*user_idnr != 0) return 0; - else - return 1; + + /* 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); + + return 1; } /* Given a useridnr, find the account/login name @@ -768,175 +687,36 @@ int auth_getmaxmailsize(u64_t user_idnr, u64_t * maxmail_size) char *auth_getencryption(u64_t user_idnr UNUSED) { /* ldap does not support fancy passwords */ - return 0; + return g_strdup(""); } + + /* Fills the users list with all existing users * return -2 on mem error, -1 on db-error, 0 on success */ -int auth_get_known_users(struct list *users) +GList * auth_get_known_users(void) { - int64_t known; - /* u64_t curr; unused variable */ - char query[AUTH_QUERY_SIZE]; + char *query; char *fields[] = { _ldap_cfg.field_uid, NULL }; - struct list templist; - struct element *tempelem1, *tempelem2, *tempelem3; - - if (!users) { - trace(TRACE_ERROR, - "%s,%s: got a NULL pointer as argument",__FILE__,__func__); - return -2; - } - - list_init(users); - - snprintf(query, AUTH_QUERY_SIZE, "(objectClass=%s)", - _ldap_cfg.objectclass); - known = __auth_get_every_match(query, fields, &templist); - trace(TRACE_ERROR, "%s,%s: found %llu users",__FILE__,__func__, - known); - - /* do the first entry here */ - tempelem1 = list_getstart(&templist); - - /* we'll get the next entry at the _end_ of the loop! */ - while (tempelem1 != NULL) { - tempelem2 = list_getstart((struct list *) tempelem1->data); - while (tempelem2 != NULL) { - tempelem3 = - list_getstart((struct list *) tempelem2->data); - while (tempelem3 != NULL) { - list_nodeadd(users, - (char *) tempelem3->data, - strlen((char *) tempelem3-> - data) + 1); - tempelem3 = tempelem3->nextnode; - } - tempelem2 = tempelem2->nextnode; - } - tempelem1 = tempelem1->nextnode; - } - - /* pass through any error from __auth_get_every_match() */ - return (known < 0 ? known : 0); -} - - -/* recursive function, should be called with checks == -1 from main routine */ -int auth_check_user(const char *address, struct list *userids, int checks) -{ - int occurences = 0, r; - /*int i; unused variable */ - int j; - char query[AUTH_QUERY_SIZE]; - char *fields[] = { _ldap_cfg.field_nid, NULL }; - int c1, c2, c3; - int count1, count2, count3; - struct list templist; - struct element *tempelem1, *tempelem2, *tempelem3; - - - trace(TRACE_DEBUG, "%s,%s: checking for user [%s]",__FILE__,__func__, - address); - - if (checks > MAX_CHECKS_DEPTH) { - trace(TRACE_ERROR, - "%s,%s: maximum checking depth reached, there probably is a loop in your alias table",__FILE__,__func__); - return -1; - } - - list_init(&templist); - - snprintf(query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s%s))", - _ldap_cfg.field_mail, address, _ldap_cfg.field_mailalt, - _ldap_cfg.mailaltprefix, address); - - /* we're just using a little counter variable, since we'll use it in the for loop later */ - j = __auth_get_every_match(query, fields, &templist); - - if (j < 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 */ - - list_nodeadd(userids, address, - strlen(address) + 1); - trace(TRACE_DEBUG, - "%s,%s: adding [%s] to deliver_to address",__FILE__,__func__, - address); - list_freelist(&templist.start); - return 1; - } else { - trace(TRACE_DEBUG, - "%s,%s: user [%s] not in aliases table",__FILE__,__func__, - address); - list_freelist(&templist.start); - return 0; - } - } - - /* do the first entry here */ - tempelem1 = list_getstart(&templist); - - count1 = templist.total_nodes; - for (c1 = 0; c1 < count1; c1++) { - tempelem2 = list_getstart((struct list *) tempelem1->data); - count2 = ((struct list *) tempelem1->data)->total_nodes; - for (c2 = 0; c2 < count2; c2++) { - tempelem3 = - list_getstart((struct list *) tempelem2->data); - count3 = - ((struct list *) tempelem2->data)->total_nodes; - for (c3 = 0; c3 < count3; c3++) { -// here begins the meat - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: checking user [%s] to [%s]",__FILE__,__func__, - address, (char *) tempelem3->data); - - r = auth_check_user((char *) tempelem3-> - data, userids, - (checks < - 0) ? 1 : checks + 1); - - if (r < 0) { - /* loop detected */ - - if (checks > 0) - return -1; /* still in recursive call */ - - if (userids->start) { - list_freelist(&userids-> - start); - userids->total_nodes = 0; - } - - return 0; /* report to calling routine: no results */ - } - - occurences += r; -// here ends the meat - tempelem3 = tempelem3->nextnode; - } - list_freelist(&((struct list *) tempelem2->data)-> - start); - tempelem2 = tempelem2->nextnode; - } - list_freelist(&((struct list *) tempelem1->data)->start); - tempelem1 = tempelem1->nextnode; - } - list_freelist(&templist.start); - - trace(TRACE_DEBUG, - "%s,%s: executing query, checks [%d]",__FILE__,__func__, checks); - /* trace(TRACE_INFO,"%s,%s: user [%s] has [%d] entries",__FILE__,__func__,address,occurences); */ + GList *users; + GList *entlist; + + GString *t = g_string_new(_ldap_cfg.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); + trace(TRACE_ERROR, "%s,%s: found %d users", + __FILE__,__func__, + g_list_length(entlist)); - return occurences; + users = dm_ldap_entlist_get_values(entlist); + + dm_ldap_freeresult(entlist); + return users; } - - /* * auth_check_user_ext() * @@ -945,50 +725,33 @@ int auth_check_user(const char *address, struct list *userids, int checks) * * returns the number of occurences. */ + + + int auth_check_user_ext(const char *address, struct list *userids, struct list *fwds, int checks) { - /*int i; unused variable */ - int j; int occurences = 0; u64_t id; char *endptr = NULL; char query[AUTH_QUERY_SIZE]; - char *fields[] = - { _ldap_cfg.field_nid, _ldap_cfg.field_members, - _ldap_cfg.field_fwd, _ldap_cfg.field_fwdsave, - _ldap_cfg.field_fwdtarget, NULL }; - int c1, c2, c3; - int count1, count2, count3; - struct list templist; - struct element *tempelem1, *tempelem2, *tempelem3; + char *fields[] = { _ldap_cfg.field_nid, _ldap_cfg.field_fwdtarget, NULL }; + unsigned c2; + char *attrvalue; + GList *entlist, *fldlist, *attlist; 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 */ - if (checks < -1) { - snprintf(query, AUTH_QUERY_SIZE, "%s", address); - j = __auth_get_one_entry(query, fields, &templist); - } else { - snprintf(query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s%s))", - _ldap_cfg.field_mail, address, - _ldap_cfg.field_mailalt, _ldap_cfg.mailaltprefix, - address); - /* we're just using a little counter variable, - * since we'll use it in the for loop later */ - j = __auth_get_every_match(query, fields, &templist); - } - + snprintf(query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_mail, address); + entlist = __auth_get_every_match(query, fields); - trace(TRACE_DEBUG, - "%s,%s: searching with query [%s]",__FILE__,__func__, query); - trace(TRACE_DEBUG, - "%s,%s: executing query, checks [%d]",__FILE__,__func__, - checks); + trace(TRACE_DEBUG, "%s,%s: searching with query [%s], checks [%d]", + __FILE__,__func__, query, checks); - if (j < 1) { + 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 @@ -997,181 +760,56 @@ int auth_check_user_ext(const char *address, struct list *userids, 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); list_nodeadd(userids, &id, sizeof(id)); } else { - list_nodeadd(fwds, address, - strlen(address) + 1); + trace(TRACE_DEBUG, "%s,%s: adding [%s] to forwards",__FILE__,__func__, address); + list_nodeadd(fwds, address, strlen(address) + 1); dm_free(endptr); } - - trace(TRACE_DEBUG, - "%s,%s: adding [%s] to deliver_to address",__FILE__,__func__, - address); - list_freelist(&templist.start); + dm_ldap_freeresult(entlist); return 1; } else { - trace(TRACE_DEBUG, - "%s,%s: user [%s] not in aliases table",__FILE__,__func__, - address); - list_freelist(&templist.start); + 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__); - - /* do the first entry here */ - tempelem1 = list_getstart(&templist); - - count1 = templist.total_nodes; - for (c1 = 0; c1 < count1; c1++) { - int fwdsave = 1; - int fwdmaysave = 1; - tempelem2 = list_getstart((struct list *) tempelem1->data); - count2 = ((struct list *) tempelem1->data)->total_nodes; - for (c2 = 0; c2 < count2; c2++) { - tempelem3 = - list_getstart((struct list *) tempelem2->data); - count3 = - ((struct list *) tempelem2->data)->total_nodes; - for (c3 = 0; c3 < count3; c3++) { -// here begins the meat - /* Note that the fields are in *reverse* - * order from the definition above! */ - if (4 == c2) { - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: looks like a user id",__FILE__,__func__); - if (fwdsave) { - trace(TRACE_DEBUG, - "%s,%s: checking user %s to %s",__FILE__,__func__, - address, - (char *) tempelem3-> - data); - occurences += - auth_check_user_ext((char *) tempelem3->data, userids, fwds, 1); - } else { - trace(TRACE_DEBUG, - "%s,%s: not checking user %s to %s due to fwdsave=0",__FILE__,__func__, - address, - (char *) tempelem3-> - data); - } - } else if (3 == c2) { - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: looks like a group member",__FILE__,__func__); - trace(TRACE_DEBUG, - "%s,%s: checking user %s to %s",__FILE__,__func__, - address, - (char *) tempelem3->data); - occurences += - auth_check_user_ext((char *) - tempelem3-> - data, - userids, - fwds, -2); - } else if (2 == c2) { - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: looks like a forwarding dn",__FILE__,__func__); - trace(TRACE_DEBUG, - "%s,%s: checking user %s to %s",__FILE__,__func__, - address, - (char *) tempelem3->data); - occurences += - auth_check_user_ext((char *) - tempelem3-> - data, - userids, - fwds, -2); - /* if the user does not have a forward, their fwdsave will be false - * but logically, it is true: "save, then forward to nowhere" - * so here we make sure that before we don't deliver we check: - * - that the fwdsave value is false - * AND - that there is a forwarding address */ - if (0 == fwdmaysave) - fwdsave = 0; - } else if (1 == c2) { - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: looks like a forwarding state",__FILE__,__func__); - trace(TRACE_DEBUG, - "%s,%s: checking user %s to %s",__FILE__,__func__, - address, - (char *) tempelem3->data); - if (0 == - strcasecmp((char *) tempelem3-> - data, "true")) - fwdmaysave = 1; - else if (0 == - strcasecmp((char *) - tempelem3-> - data, "false")) - fwdmaysave = 0; - } else if (0 == c2) { - /* do a recursive search for deliver_to */ - trace(TRACE_DEBUG, - "%s,%s: looks like a forwarding target",__FILE__,__func__); - /* rip the prefix off of the result */ - { - char target - [AUTH_QUERY_SIZE]; - /* I am much happier now that this is case insensitive :-) - * albeit at the cost of complication and uglification... - * perhaps this could be made into a separate function... */ - if (0 == - strncasecmp((char *) - tempelem3-> - data, - _ldap_cfg. - fwdtargetprefix, - strlen - (_ldap_cfg. - fwdtargetprefix))) - { - /* Offset the pointer by the length of the prefix to skip */ - sscanf((char *) - tempelem3-> - data + - strlen - (_ldap_cfg. - fwdtargetprefix), - " %s ", - &target[0]); - } else { - /* The prefix wasn't in there, so just use what we got */ - snprintf(target, - AUTH_QUERY_SIZE, - "%s", - (char *) - tempelem3-> - data); - } - trace(TRACE_DEBUG, - "%s,%s: checking user %s to %s",__FILE__,__func__, - address, target); - occurences += 1; - list_nodeadd(fwds, target, - strlen(target) - + 1); - } + entlist = g_list_first(entlist); + while (entlist) { + fldlist = g_list_first(entlist->data); + for (c2 = 0; c2 < g_list_length(fldlist); c2++) { + attlist = g_list_first(fldlist->data); + while(attlist) { + attrvalue = (char *)attlist->data; + if ((strcmp(fields[c2],_ldap_cfg.field_nid)==0)) { + trace(TRACE_DEBUG, "%s,%s: restart with user_idnr [%s]", + __FILE__,__func__, + attrvalue); + + occurences += auth_check_user_ext(attrvalue, userids, fwds, 1); + } + + if ((strcmp(fields[c2],_ldap_cfg.field_fwdtarget)==0)) { + trace(TRACE_DEBUG, "%s,%s: add forwarding target [%s]", + __FILE__,__func__, + attrvalue); + + list_nodeadd(fwds, attrvalue, strlen(attrvalue) + 1); + occurences += 1; } - tempelem3 = tempelem3->nextnode; + + attlist = g_list_next(attlist); } - list_freelist(&((struct list *) tempelem2->data)-> - start); - tempelem2 = tempelem2->nextnode; + fldlist = g_list_next(fldlist); } - list_freelist(&((struct list *) tempelem1->data)->start); - tempelem1 = tempelem1->nextnode; + entlist = g_list_next(entlist); } - list_freelist(&templist.start); + dm_ldap_freeresult(entlist); - trace(TRACE_DEBUG, - "%s,%s: executing query, checks [%d]",__FILE__,__func__, - checks); - /* trace(TRACE_INFO,"auth_check_user(): user [%s] has [%d] entries",address,occurences); */ + trace(TRACE_DEBUG, "%s,%s: executing query, checks [%d]",__FILE__,__func__, checks); return occurences; } @@ -1193,55 +831,52 @@ int auth_adduser(const char *username, const char *password, int i, j; /*int ret; unused variable */ int NUM_MODS = 9; - char *kaboom = "123"; - char *cid = (char *)dm_malloc(sizeof(char *)*64); - char *maxm = (char *)dm_malloc(sizeof(char *)*64); - sprintf(cid,"%llu",clientid); - sprintf(maxm,"%llu",maxmail); + GString *nid = g_string_new(""); + GString *cid = g_string_new(""); + GString *maxm = g_string_new(""); + + g_string_printf(nid,"%llu",dm_ldap_get_freeid(_ldap_cfg.field_nid)); + g_string_printf(cid,"%llu",clientid); + g_string_printf(maxm,"%llu",maxmail); - char *cn_values[] = { (char *)username, NULL }; - char *sn_values[] = { (char *)username, NULL }; + char **obj_values = g_strsplit(_ldap_cfg.objectclass,",",0); char *pw_values[] = { (char *)password, NULL }; - char *obj_values[] = - { "top", "person", _ldap_cfg.objectclass, NULL }; char *uid_values[] = { (char *)username, NULL }; - char *cid_values[] = { cid, NULL }; - char *nid_values[] = { kaboom, NULL }; - char *max_values[] = { maxm, NULL }; - field_t cn_type = "cn"; - field_t sn_type = "sn"; + 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"; unsigned _ldap_dn_len; - + + GString *t=g_string_new(""); + assert(user_idnr != NULL); *user_idnr = 0; auth_reconnect(); /* Make the malloc for all of the pieces we're about to to sprintf into it */ - _ldap_dn_len = - strlen("cn=,") + strlen(username) + strlen(_ldap_cfg.base_dn); - _ldap_dn = (char *) dm_malloc(_ldap_dn_len + 1); - snprintf(_ldap_dn, _ldap_dn_len, "cn=%s,%s", username, - _ldap_cfg.base_dn); + g_string_printf(t,"%s=%s,%s", _ldap_cfg.cn_string, username, _ldap_cfg.base_dn); + _ldap_dn=g_strdup(t->str); + _ldap_dn_len=t->len; + g_string_free(t,FALSE); + trace(TRACE_DEBUG, "%s,%s: Adding user with DN of [%s]", __FILE__, __func__, _ldap_dn); /* Construct the array of LDAPMod structures representing the attributes * of the new entry. There's a 12 byte leak here, better find it... */ - _ldap_mod = - (LDAPMod **) dm_malloc((NUM_MODS + 1) * sizeof(LDAPMod *)); + _ldap_mod = (LDAPMod **) dm_malloc((NUM_MODS + 1) * sizeof(LDAPMod *)); if (_ldap_mod == NULL) { - trace(TRACE_ERROR, - "%s,%s: Cannot allocate memory for mods array", __FILE__, __func__); + 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))) == NULL) { + if ((_ldap_mod[i] = (LDAPMod *) dm_malloc(sizeof(LDAPMod))) == NULL) { trace(TRACE_ERROR, "%s,%s: Cannot allocate memory for mods element %d", __FILE__, __func__, i); @@ -1257,27 +892,11 @@ int auth_adduser(const char *username, const char *password, i = 0; trace(TRACE_DEBUG, "%s,%s: Starting to define LDAPMod element %d type %s value %s", __FILE__, __func__, i, - "objectclass", obj_values[0]); + "objectclass", g_strjoinv(",",obj_values)); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = obj_type; _ldap_mod[i]->mod_values = obj_values; - - i++; - trace(TRACE_DEBUG, - "%s,%s: Starting to define LDAPMod element %d type %s value %s", __FILE__, __func__, i, - "cn", cn_values[0]); - _ldap_mod[i]->mod_op = LDAP_MOD_ADD; - _ldap_mod[i]->mod_type = cn_type; - _ldap_mod[i]->mod_values = cn_values; - - i++; - trace(TRACE_DEBUG, - "%s,%s: Starting to define LDAPMod element %d type %s value %s", __FILE__, __func__, i, - "sn", cn_values[0]); - _ldap_mod[i]->mod_op = LDAP_MOD_ADD; - _ldap_mod[i]->mod_type = sn_type; - _ldap_mod[i]->mod_values = cn_values; - + if (strlen(_ldap_cfg.field_passwd) > 0) { i++; trace(TRACE_DEBUG, @@ -1285,16 +904,16 @@ int auth_adduser(const char *username, const char *password, i, _ldap_cfg.field_passwd, pw_values[0]); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.field_passwd; - _ldap_mod[i]->mod_values = cn_values; + _ldap_mod[i]->mod_values = pw_values; } i++; trace(TRACE_DEBUG, "%s,%s: Starting to define LDAPMod element %d type %s value %s", __FILE__, __func__, i, - "mail", sn_values[0]); + "mail", uid_values[0]); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = mail_type; - _ldap_mod[i]->mod_values = sn_values; + _ldap_mod[i]->mod_values = uid_values; i++; trace(TRACE_DEBUG, @@ -1340,6 +959,8 @@ int auth_adduser(const char *username, const char *password, /* make sure to free this stuff even if we do bomb out! */ /* there's a 12 byte leak here, but I can't figure out how to fix it :-( */ + g_strfreev(obj_values); + for (i = 0; i < NUM_MODS; i++) dm_free(_ldap_mod[i]); dm_free(_ldap_mod); @@ -1575,96 +1196,89 @@ int auth_change_password(u64_t user_idnr UNUSED, return -1; } - -int auth_change_clientid(u64_t user_idnr, u64_t newcid) -{ - int i, j, NUM_MODS = 2; - char newcid_str[100]; - char *new_values[] = { newcid_str, NULL }; - - auth_reconnect(); - - if (!user_idnr) { - trace(TRACE_ERROR, - "%s,%s: got NULL as useridnr",__FILE__,__func__); - return 0; - } - - if (!newcid) { - trace(TRACE_ERROR, - "%s,%s: got NULL as newcid",__FILE__,__func__); - return 0; - } - - snprintf(new_values[0], 100, "%llu", newcid); // Yeah, something like this... - - snprintf(_ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", - _ldap_cfg.field_nid, user_idnr); - trace(TRACE_DEBUG, - "%s,%s: searching with query [%s]",__FILE__,__func__, - _ldap_query); - _ldap_err = - ldap_search_s(_ldap_conn, _ldap_cfg.base_dn, - _ldap_cfg.scope_int, _ldap_query, _ldap_attrs, - _ldap_attrsonly, &_ldap_res); +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); + + _ldap_err = ldap_search_s(_ldap_conn, + _ldap_cfg.base_dn, + _ldap_cfg.scope_int, + t->str, + _ldap_attrs, + _ldap_attrsonly, + &_ldap_res); + if (_ldap_err) { - trace(TRACE_ERROR, - "%s,%s: could not execute query: %s",__FILE__,__func__, - ldap_err2string(_ldap_err)); - return 0; + trace(TRACE_ERROR, "%s,%s: could not execute query: %s", + __FILE__,__func__, + ldap_err2string(_ldap_err)); + 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__); + trace(TRACE_DEBUG, "%s,%s: no entries found",__FILE__,__func__); + g_string_free(t,TRUE); ldap_msgfree(_ldap_res); - return 0; + return NULL; } - _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)); + 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 0; + return NULL; } - _ldap_dn = ldap_get_dn(_ldap_conn, _ldap_msg); - if (_ldap_dn == NULL) { - 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)); + 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 -1; + return NULL; } - trace(TRACE_DEBUG, - "%s,%s: found something at [%s]",__FILE__,__func__, _ldap_dn); + return dn; +} - /* Construct the array of LDAPMod structures representing the attributes - * of the new entry. */ - _ldap_mod = - (LDAPMod **) dm_malloc((NUM_MODS + 1) * sizeof(LDAPMod *)); - if (_ldap_mod == NULL) { - trace(TRACE_ERROR, - "%s,%s: Cannot allocate memory for mods array", __FILE__, __func__); +int auth_change_clientid(u64_t user_idnr, u64_t newcid) +{ + int i, j, NUM_MODS = 2; + char newcid_str[100]; + char *new_values[] = { newcid_str, NULL }; + + auth_reconnect(); + + if (!user_idnr) + return 0; + if (!newcid) + return 0; + + snprintf(new_values[0], 100, "%llu", newcid); + + if (! (_ldap_dn = dm_ldap_user_getdn(user_idnr))) + return -1; + + if (! (_ldap_mod = (LDAPMod **) dm_malloc((NUM_MODS + 1) * sizeof(LDAPMod *)))) { ldap_memfree(_ldap_dn); ldap_msgfree(_ldap_res); return -1; } for (i = 0; i < NUM_MODS; i++) { - if ((_ldap_mod[i] = - (LDAPMod *) dm_malloc(sizeof(LDAPMod))) == NULL) { - trace(TRACE_ERROR, - "%s,%s: Cannot allocate memory for mods element %d", __FILE__, __func__, - i); + if ((_ldap_mod[i] = (LDAPMod *) dm_malloc(sizeof(LDAPMod))) == NULL) { + trace(TRACE_ERROR, "%s,%s: Cannot allocate memory for mods element %d", + __FILE__, __func__, + i); /* Free everything that did get allocated, which is (i-1) elements */ for (j = 0; j < (i - 1); j++) dm_free(_ldap_mod[j]); @@ -1876,8 +1490,6 @@ int auth_validate(char *username, char *password, u64_t * user_idnr) create_current_timestring(×tring); snprintf(query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid, username); -// ldap_dn = __auth_get_first_match( query, fields ); -// id_char = __auth_get_first_match( query, _ldap_cfg.field_nid ); /* now, try to rebind as the given DN using the supplied password */ trace(TRACE_ERROR, @@ -1948,24 +1560,6 @@ int auth_get_users_from_clientid(u64_t client_id, } /** - * \brief get deliver_to from alias. Gets a list of deliver_to - * addresses - * \param alias the alias - * \return - * - NULL on failure - * - "" if no such alias found - * - deliver_to address otherwise - * \attention caller needs to free the return value - */ -char *auth_get_deliver_from_alias(const char *alias) -{ - char *deliver_to = (char *)dm_malloc(sizeof(char *)); - deliver_to = NULL; - - - return deliver_to; -} -/** * \brief get a list of aliases associated with a user's user_idnr * \param user_idnr idnr of user * \param aliases list of aliases @@ -1976,9 +1570,29 @@ char *auth_get_deliver_from_alias(const char *alias) * \attention aliases list needs to be empty. Method calls list_init() * which sets list->start to NULL. */ -int auth_get_user_aliases(u64_t user_idnr, struct list *aliases) + + + +GList * auth_get_user_aliases(u64_t user_idnr) { - return 0; + 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)); + attlist = g_list_next(attlist); + } + dm_ldap_freeresult(entlist); + } + g_string_free(t,TRUE); + return aliases; } @@ -1992,8 +1606,58 @@ int auth_get_user_aliases(u64_t user_idnr, struct list *aliases) * - 0 on success * - 1 if alias already exists for given user */ -int auth_addalias(u64_t user_idnr, const char *alias, u64_t clientid) +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; + int modNumber = 1; + + 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; + } + 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); + 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; } @@ -2025,6 +1689,65 @@ int auth_addalias_ext(const char *alias, const char *deliver_to, */ int auth_removealias(u64_t user_idnr, const char *alias) { + char *userid = NULL; + char **mailValues = NULL; + LDAPMod *modify[2], delMail; + GList *aliases; + int modNumber = 1; + + 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; + + 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; } @@ -2043,43 +1766,3 @@ int auth_removealias_ext(const char *alias, const char *deliver_to) } -/* -// { -// int c1, c2, c3; -// int count1, count2, count3; -// struct list templist; -// struct element *tempelem1, *tempelem2, *tempelem3; -// -// // do the first entry here -// tempelem1 = list_getstart( retlist ); -// count1 = retlist->total_nodes; -// -// // we'll get the next entry at the _end_ of the loop! -// printf( "retlist has %d nodes\n", retlist->total_nodes ); -// for( c1 = 0; c1 < count1; c1++ ) -// { -// tempelem2 = list_getstart( (struct list *)tempelem1->data ); -// count2 = ((struct list *)tempelem1->data)->total_nodes; -// for( c2 = 0; c2 < count2; c2++ ) -// { -// //if( tempelem2 ) -// tempelem3 = list_getstart( (struct list *)tempelem2->data ); -// count3 = ((struct list *)tempelem2->data)->total_nodes; -// for( c3 = 0; c3 < count3; c3++ ) -// { -// printf( "I've got %s\n", tempelem3->data ); -// tempelem3 = tempelem3->nextnode; -// //if( tempelem3->nextnode ) tempelem3 = tempelem3->nextnode; -// // else { printf(" break at %d\n", __LINE__ ); break; } -// } -// //if( tempelem2->nextnode ) tempelem2 = tempelem2->nextnode; -// tempelem2 = tempelem2->nextnode; -// // else { printf(" break at %d\n", __LINE__ ); break; } -// } -// tempelem1 = tempelem1->nextnode; -// //if( tempelem1->nextnode ) tempelem1 = tempelem1->nextnode; -// // else { printf(" break at %d\n", __LINE__ ); break; } -// } -// } -//*/ - diff --git a/auth/authsql.c b/auth/authsql.c index 7d479f42..d279f771 100644 --- a/auth/authsql.c +++ b/auth/authsql.c @@ -87,45 +87,7 @@ int auth_disconnect() int auth_user_exists(const char *username, u64_t * user_idnr) { - const char *query_result; - char *escaped_username; - - assert(user_idnr != NULL); - *user_idnr = 0; - if (!username) { - trace(TRACE_ERROR, "%s,%s: got NULL as username", - __FILE__, __func__); - return 0; - } - - if (!(escaped_username = (char *) dm_malloc(strlen(username) * 2 + 1))) { - trace(TRACE_ERROR, "%s,%s: out of memory allocating " - "escaped username", __FILE__, __func__); - return -1; - } - - db_escape_string(escaped_username, username, strlen(username)); - - snprintf(__auth_query_data, AUTH_QUERY_SIZE, - "SELECT user_idnr FROM %susers WHERE userid='%s'",DBPFX, - escaped_username); - dm_free(escaped_username); - - if (__auth_query(__auth_query_data) == -1) { - trace(TRACE_ERROR, "%s,%s: could not execute query", - __FILE__, __func__); - return -1; - } - - if (db_num_rows() == 0) { - db_free_result(); - return 0; - } - - query_result = db_get_result(0, 0); - *user_idnr = (query_result) ? strtoull(query_result, 0, 10) : 0; - db_free_result(); - return 1; + return db_user_exists(username, user_idnr); } GList * auth_get_known_users(void) @@ -249,115 +211,7 @@ char *auth_getencryption(u64_t user_idnr) return __auth_encryption_desc_string; } -int auth_check_user(const char *username, struct list *userids, int checks) -{ - int occurences = 0; - int r; - void *saveres; - u64_t counter; - unsigned num_rows; - const char *query_result; - char *escaped_username; - - trace(TRACE_DEBUG, "%s,%s: checking user [%s] in alias table", - __FILE__, __func__, username); - - saveres = db_get_result_set(); - db_set_result_set(NULL); - - if (checks > MAX_CHECKS_DEPTH) { - trace(TRACE_ERROR, - "%s,%s: maximum checking depth reached, " - "there probably is a loop in your alias table", - __FILE__, __func__); - return -1; - } - - if (!(escaped_username = (char *) dm_malloc(strlen(username) * 2 + 1))) { - trace(TRACE_ERROR, "%s,%s: out of memory allocating " - "escaped username", __FILE__, __func__); - return -1; - } - - db_escape_string(escaped_username, username, strlen(username)); - - snprintf(__auth_query_data, AUTH_QUERY_SIZE, - "SELECT deliver_to FROM %saliases WHERE " - "lower(alias) = lower('%s')",DBPFX, escaped_username); - dm_free(escaped_username); - - trace(TRACE_DEBUG, "%s,%s: checks [%d]", __FILE__, __func__, - checks); - - if (__auth_query(__auth_query_data) == -1) { - /* copy the old result set */ - db_set_result_set(saveres); - return 0; - } - num_rows = db_num_rows(); - if (num_rows < 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 */ - list_nodeadd(userids, username, - strlen(username) + 1); - trace(TRACE_DEBUG, - "%s,%s: adding [%s] to deliver_to address", - __FILE__, __func__, username); - db_free_result(); - db_set_result_set(saveres); - return 1; - } else { - trace(TRACE_DEBUG, - "%s,%s: user %s not in aliases table", - __FILE__, __func__, username); - db_free_result(); - db_set_result_set(saveres); - return 0; - } - } - - trace(TRACE_DEBUG, "%s,%s: into checking loop", __FILE__, - __func__); - - if (num_rows > 0) { - for (counter = 0; counter < num_rows; counter++) { - /* do a recursive search for deliver_to */ - query_result = db_get_result(counter, 0); - trace(TRACE_DEBUG, "%s,%s: checking user %s to %s", - __FILE__, __func__, username, - query_result); - - r = auth_check_user(query_result, userids, - (checks < 0) ? 1 : checks + 1); - if (r < 0) { - /* loop detected */ - db_free_result(); - db_set_result_set(saveres); - - if (checks > 0) - return -1; /* still in recursive call */ - - if (userids->start) { - list_freelist(&userids->start); - userids->total_nodes = 0; - } - - return 0; /* report to calling routine: no results */ - } - - occurences += r; - } - } - - db_free_result(); - db_set_result_set(saveres); - return occurences; -} - -int auth_check_user_ext(const char *username, struct list *userids, - struct list *fwds, int checks) +int auth_check_user_ext(const char *username, struct list *userids, struct list *fwds, int checks) { int occurences = 0; void *saveres; @@ -434,11 +288,8 @@ int auth_check_user_ext(const char *username, struct list *userids, /* do a recursive search for deliver_to */ query_result = db_get_result(counter, 0); trace(TRACE_DEBUG, "%s,%s: checking user %s to %s", - __FILE__, __func__, username, - query_result); - occurences += - auth_check_user_ext(query_result, userids, - fwds, 1); + __FILE__, __func__, username, query_result); + occurences += auth_check_user_ext(query_result, userids, fwds, 1); } } db_free_result(); @@ -1195,18 +1046,11 @@ int auth_removealias_ext(const char *alias, const char *deliver_to) } -int auth_get_user_aliases(u64_t user_idnr, struct list *aliases) +GList * auth_get_user_aliases(u64_t user_idnr) { int i, n; const char *query_result; - - if (!aliases) { - trace(TRACE_ERROR, "%s,%s: got a NULL pointer as argument", - __FILE__, __func__); - return -2; - } - - list_init(aliases); + GList *aliases = NULL; /* do a inverted (DESC) query because adding the names to the * final list inverts again */ @@ -1217,23 +1061,21 @@ int auth_get_user_aliases(u64_t user_idnr, struct list *aliases) if (__auth_query(__auth_query_data) == -1) { trace(TRACE_ERROR, "%s,%s: could not retrieve list", __FILE__, __func__); - return -1; + return NULL; } n = db_num_rows(); for (i = 0; i < n; i++) { query_result = db_get_result(i, 0); - if (!query_result || !list_nodeadd(aliases, - query_result, - strlen(query_result) + - 1)) { - list_freelist(&aliases->start); + if (!query_result || ! (aliases = g_list_append(aliases,g_strdup(query_result)))) { + g_list_foreach(aliases, (GFunc)g_free, NULL); + g_list_free(aliases); db_free_result(); - return -2; + return NULL; } } db_free_result(); - return 0; + return aliases; } diff --git a/check_dbmail.h b/check_dbmail.h index 0a676cdd..727bacb3 100644 --- a/check_dbmail.h +++ b/check_dbmail.h @@ -6,7 +6,7 @@ char *raw_message = "From: <vol@inter7.com>\n" "Received: at mx.inter7.com from localhost\n" "Received: at localhost from localhost\n" "MIME-Version: 1.0\n" - "Content-type: multipart/mixed; boundary=\"boundary\"\n" + "Content-type: multipart/mixed; boundary=boundary\n" "X-Dbmail-ID: 12345\n" "\n" "MIME multipart messages specify that there are multiple\n" @@ -27,7 +27,7 @@ char *raw_message = "From: <vol@inter7.com>\n" "\n" "Test message one\n" "--boundary\n" - "Content-type: text/plain; charset=us-ascii; name=\"testfile\"\n" + "Content-type: text/plain; charset=us-ascii; name=testfile\n" "Content-transfer-encoding: base64\n" "\n" "IyEvYmluL2Jhc2gNCg0KY2xlYXINCmVjaG8gIi4tLS0tLS0tLS0tLS0tLS0t\n" diff --git a/check_dbmail_deliver.c b/check_dbmail_deliver.c index 7b414099..636c40eb 100644 --- a/check_dbmail_deliver.c +++ b/check_dbmail_deliver.c @@ -41,6 +41,7 @@ #include "debug.h" #include "db.h" #include "auth.h" +#include "misc.h" #include "check_dbmail.h" @@ -73,7 +74,7 @@ u64_t get_first_user_idnr(void) void setup(void) { - configure_debug(4,0,1); + configure_debug(5,0,1); config_read(configFile); GetDBParams(&_db_params); db_connect(); @@ -194,6 +195,7 @@ START_TEST(test_auth_getmaxmailsize) u64_t user_idnr = get_first_user_idnr(); result = auth_getmaxmailsize(user_idnr, &maxmail_size); fail_unless(result>=0,"auth_getmaxmailsize failed"); + //fail_unless(maxmail_size>=0,"auth_getmaxmailsize return illegal maxmail_size"); } END_TEST @@ -220,18 +222,6 @@ END_TEST /** - * \brief find all deliver_to addresses for a username (?, code is not exactly - * clear to me at the moment, IB 21-08-03) - * \param username - * \param userids list of user ids (empty on call) - * \param checks nr of checks. Used internally in recursive calls. It \b should - * be set to -1 when called! - * \return number of deliver_to addresses found - */ -//int auth_check_user(const char *username, struct list *userids, -// int checks); - -/** * \brief as auth_check_user() but adds the numeric ID of the user found to * userids or the forward to the fwds list * \param username @@ -242,6 +232,17 @@ END_TEST */ //int auth_check_user_ext(const char *username, struct list *userids, // struct list *fwds, int checks); +START_TEST(test_auth_check_user_ext) +{ + struct list uids; + struct list fwds; + int checks = -1; + int result; + list_init(&uids); + list_init(&fwds); + result = auth_check_user_ext("foobar@foobar.org",&uids,&fwds,checks); +} +END_TEST /** * \brief add a new user to the database (whichever type of database is * implemented) @@ -294,6 +295,20 @@ END_TEST * - 0 on success */ //int auth_change_username(u64_t user_idnr, const char *new_name); +START_TEST(test_auth_change_username) +{ + u64_t user_idnr; + char *userid; + char *old="testuser1"; + char *new="asdfasdf1"; + auth_user_exists(old,&user_idnr); + + userid = auth_get_userid(user_idnr); + printf("change username %s -> %s\n", old, new); + +} +END_TEST + /** * \brief change a users password * \param user_idnr @@ -358,6 +373,16 @@ END_TEST * \attention caller should free username string */ //char *auth_get_userid(u64_t user_idnr); +START_TEST(test_auth_get_userid) +{ + u64_t testidnr; + u64_t user_idnr = get_first_user_idnr(); + char *username = auth_get_userid(user_idnr); + fail_unless(strlen(username)>3,"auth_get_userid failed"); + auth_user_exists(username, &testidnr); + fail_unless(testidnr==user_idnr,"auth_get_userid: auth_user_exists returned wrong idnr"); +} +END_TEST /** * \brief get user ids belonging to a client id @@ -386,15 +411,20 @@ END_TEST /** * \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 list_init() - * which sets list->start to NULL. + * \return aliases list of aliases */ -//int auth_get_user_aliases(u64_t user_idnr, struct list *aliases); +//GList * auth_get_user_aliases(u64_t user_idnr); +START_TEST(test_auth_get_user_aliases) +{ + u64_t user_idnr; + char *username="testuser1"; + GList *aliases; + int result; + result = auth_user_exists(username, &user_idnr); + aliases = auth_get_user_aliases(user_idnr); +// fail_unless(g_list_length(aliases)>1,"auth_get_user_aliases failed"); +} +END_TEST /** * \brief add an alias for a user * \param user_idnr user's id @@ -406,6 +436,17 @@ END_TEST * - 1 if alias already exists for given user */ //int auth_addalias(u64_t user_idnr, const char *alias, u64_t clientid); + +START_TEST(test_auth_addalias) +{ + int result; + u64_t user_idnr; + char *username="testuser1"; + result = auth_user_exists(username,&user_idnr); + result = auth_addalias(user_idnr,"addalias@foobar.org",0); + fail_unless(result==0,"auth_addalias failed"); +} +END_TEST /** * \brief add an alias to deliver to an extern address * \param alias the alias @@ -427,6 +468,17 @@ END_TEST * - 0 on success */ //int auth_removealias(u64_t user_idnr, const char *alias); +START_TEST(test_auth_removealias) +{ + int result; + u64_t user_idnr; + char *username="testuser1"; + result = auth_user_exists(username,&user_idnr); + result = auth_removealias(user_idnr,"addalias@foobar.org"); + fail_unless(result==0,"auth_removealias failed"); +} +END_TEST + /** * \brief remove external delivery address for an alias * \param alias the alias @@ -439,6 +491,33 @@ END_TEST //int auth_removealias_ext(const char *alias, const char *deliver_to); +#ifdef AUTHLDAP +//char *dm_ldap_get_filter(const gchar boolean, const gchar *attribute, GList *values) + +START_TEST(test_dm_ldap_get_filter) +{ + char *result; + char *expect = "(&(objectClasses=top)(objectClasses=account)(objectClasses=dbmailUser))"; + GString *objclasses = g_string_new("top,account,dbmailUser"); + GList *l = g_string_split(objclasses,","); + result = dm_ldap_get_filter('&',"objectClasses",l); + fail_unless(strcmp(result,expect)==0,"dm_ldap_get_filter failed"); +} +END_TEST + +START_TEST(test_dm_ldap_get_freeid) +{ + u64_t id; + + id = dm_ldap_get_freeid("uidNumber"); + fail_unless(id != 0,"dm_ldap_get_freeid failed"); + + return; +} +END_TEST + +#endif + Suite *dbmail_deliver_suite(void) { @@ -455,29 +534,27 @@ Suite *dbmail_deliver_suite(void) tcase_add_test(tc_auth, test_auth_getclientid); tcase_add_test(tc_auth, test_auth_getmaxmailsize); tcase_add_test(tc_auth, test_auth_getencryption); - /* - tcase_add_test(tc_auth, test_auth_check_user); tcase_add_test(tc_auth, test_auth_check_user_ext); - */ tcase_add_test(tc_auth, test_auth_adduser); tcase_add_test(tc_auth, test_auth_delete_user); - /* - tcase_add_test(tc_auth, test_auth_change_username); - tcase_add_test(tc_auth, test_auth_change_password); - tcase_add_test(tc_auth, test_auth_change_clientid); - tcase_add_test(tc_auth, test_auth_change_mailboxsize); - tcase_add_test(tc_auth, test_auth_validate); - tcase_add_test(tc_auth, test_auth_md5_validate); - tcase_add_test(tc_auth, test_get_userid); - tcase_add_test(tc_auth, test_get_users_from_clientid); - tcase_add_test(tc_auth, test_get_deliver_from_alias); - tcase_add_test(tc_auth, test_get_user_aliases); +// tcase_add_test(tc_auth, test_auth_change_username); +// tcase_add_test(tc_auth, test_auth_change_password); +// tcase_add_test(tc_auth, test_auth_change_clientid); +// tcase_add_test(tc_auth, test_auth_change_mailboxsize); +// tcase_add_test(tc_auth, test_auth_validate); +// tcase_add_test(tc_auth, test_auth_md5_validate); + tcase_add_test(tc_auth, test_auth_get_userid); +// tcase_add_test(tc_auth, test_auth_get_users_from_clientid); + tcase_add_test(tc_auth, test_auth_get_user_aliases); tcase_add_test(tc_auth, test_auth_addalias); - tcase_add_test(tc_auth, test_auth_addalias_ext); +// tcase_add_test(tc_auth, test_auth_addalias_ext); tcase_add_test(tc_auth, test_auth_removealias); - tcase_add_test(tc_auth, test_auth_removealias_ext); - */ - +// tcase_add_test(tc_auth, test_auth_removealias_ext); +#ifdef AUTHLDAP + tcase_add_test(tc_auth, test_dm_ldap_get_filter); + tcase_add_test(tc_auth, test_dm_ldap_get_freeid); +#endif + return s; } diff --git a/check_dbmail_imapd.c b/check_dbmail_imapd.c index a4e6d82a..bcda695b 100644 --- a/check_dbmail_imapd.c +++ b/check_dbmail_imapd.c @@ -155,7 +155,7 @@ START_TEST(test_mime_readheader) list_init(&mimelist); res = mime_readheader(raw_message,&blkidx,&mimelist,&headersize); fail_unless(res==9, "number of newlines incorrect"); - fail_unless(blkidx==238, "blkidx incorrect"); + fail_unless(blkidx==236, "blkidx incorrect"); fail_unless(headersize==blkidx+res, "headersize incorrect"); fail_unless(mimelist.total_nodes==7, "number of message-headers incorrect"); list_freelist(&mimelist.start); diff --git a/check_dbmail_message.c b/check_dbmail_message.c index 14c362a8..8e2056bf 100644 --- a/check_dbmail_message.c +++ b/check_dbmail_message.c @@ -175,13 +175,13 @@ START_TEST(test_dbmail_message_get_rfcsize) } END_TEST -//void dbmail_message_delete(struct DbmailMessage *self); -/* -START_TEST(test_dbmail_message_delete) +//void dbmail_message_free(struct DbmailMessage *self); +START_TEST(test_dbmail_message_free) { + struct DbmailMessage *m = dbmail_message_new(); + dbmail_message_free(m); } END_TEST -*/ START_TEST(test_dbmail_message_new_from_stream) { @@ -228,7 +228,7 @@ Suite *dbmail_message_suite(void) tcase_add_test(tc_message, test_dbmail_message_hdrs_to_string); tcase_add_test(tc_message, test_dbmail_message_body_to_string); tcase_add_test(tc_message, test_dbmail_message_get_rfcsize); -// tcase_add_test(tc_message, test_dbmail_message_delete); + tcase_add_test(tc_message, test_dbmail_message_free); return s; } @@ -790,69 +790,6 @@ int db_insert_physmessage(u64_t * physmessage_id) return 1; } -int db_insert_message(u64_t user_idnr, - const char *mailbox, - int create_or_error_mailbox, - const char *unique_id, u64_t * message_idnr) -{ - u64_t mailboxid; - u64_t physmessage_id; - int result; - - assert(message_idnr); - assert(unique_id); - - if (!mailbox) - mailbox = dm_strdup("INBOX"); - - switch (create_or_error_mailbox) { - case CREATE_IF_MBOX_NOT_FOUND: - result = - db_find_create_mailbox(mailbox, user_idnr, &mailboxid); - break; - case ERROR_IF_MBOX_NOT_FOUND: - default: - result = db_findmailbox(mailbox, user_idnr, &mailboxid); - break; - } - - if (result == -1) { - trace(TRACE_ERROR, - "%s,%s: error finding and/or creating mailbox [%s]", - __FILE__, __func__, mailbox); - return -1; - } - if (mailboxid == 0) { - trace(TRACE_WARNING, - "%s,%s: mailbox [%s] could not be found!", __FILE__, - __func__, mailbox); - return -1; - } - - /* insert a new physmessage entry */ - if (db_insert_physmessage(&physmessage_id) == -1) { - trace(TRACE_ERROR, "%s,%s: error inserting physmessage", - __FILE__, __func__); - return -1; - } - - /* now insert an entry into the messages table */ - snprintf(query, DEF_QUERYSIZE, "INSERT INTO " - "%smessages(mailbox_idnr, physmessage_id, unique_id," - "recent_flag, status) " - "VALUES ('%llu', '%llu', '%s', '1', '%d')", - DBPFX, mailboxid, physmessage_id, unique_id, - MESSAGE_STATUS_INSERT); - - if (db_query(query) == -1) { - trace(TRACE_STOP, "%s,%s: query failed", __FILE__, __func__); - return -1; - } - - *message_idnr = db_insert_result("message_idnr"); - return 1; -} - int db_message_set_unique_id(u64_t message_idnr, const char *unique_id) { assert(unique_id); @@ -2663,15 +2600,12 @@ int db_find_create_mailbox(const char *name, u64_t owner_idnr, if (db_findmailbox_owner(name, owner_idnr, &mboxidnr) != 1) { /* Did we fail to create the mailbox? */ if (db_createmailbox(name, owner_idnr, &mboxidnr) != 0) { - /* Serious failure situation! */ - trace(TRACE_ERROR, - "%s, %s: seriously could not create mailbox [%s]", - __FILE__, __func__, name); + trace(TRACE_ERROR, "%s, %s: could not create mailbox [%s]", + __FILE__, __func__, name); return -1; } - trace(TRACE_DEBUG, - "%s, %s: mailbox [%s] created on the fly", __FILE__, - __func__, name); + trace(TRACE_DEBUG, "%s, %s: mailbox [%s] created on the fly", + __FILE__, __func__, name); } trace(TRACE_DEBUG, "%s, %s: mailbox [%s] found", __FILE__, __func__, name); @@ -4024,4 +3958,46 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m return 0; } +int db_user_exists(const char *username, u64_t * user_idnr) +{ + const char *query_result; + char *escaped_username; + + assert(user_idnr != NULL); + *user_idnr = 0; + if (!username) { + trace(TRACE_ERROR, "%s,%s: got NULL as username", + __FILE__, __func__); + return 0; + } + + if (!(escaped_username = (char *) dm_malloc(strlen(username) * 2 + 1))) { + trace(TRACE_ERROR, "%s,%s: out of memory allocating " + "escaped username", __FILE__, __func__); + return -1; + } + + db_escape_string(escaped_username, username, strlen(username)); + + snprintf(query, DEF_QUERYSIZE, + "SELECT user_idnr FROM %susers WHERE userid='%s'",DBPFX, + escaped_username); + dm_free(escaped_username); + + if (db_query(query) == -1) { + trace(TRACE_ERROR, "%s,%s: could not execute query", + __FILE__, __func__); + return -1; + } + + if (db_num_rows() == 0) { + db_free_result(); + return 0; + } + + query_result = db_get_result(0, 0); + *user_idnr = (query_result) ? strtoull(query_result, 0, 10) : 0; + db_free_result(); + return 1; +} @@ -473,29 +473,6 @@ int db_insert_physmessage_with_internal_date(timestring_t internal_date, u64_t * physmessage_id); /** - * \brief insert a message into inbox. This function creates an entry - * into the messages table and an entry into the physmessage table - * \param user_idnr user idnr - * \param deliver_to mailbox to deliver to - * \param create_or_error_mailbox responds to the constants - * - CREATE_IF_MBOX_NOT_FOUND - * - ERROR_IF_MBOX_NOT_FOUND - * \param unique_id unique id of message - * \param messge_idnr call by reference to new message id number - * \return - * - -1 on failure - * - 1 on success - */ -int db_insert_message(u64_t user_idnr, - const char *deliver_to, - int create_or_error_mailbox, - const char *unique_id, u64_t * message_idnr); - -#define CREATE_IF_MBOX_NOT_FOUND 1 -#define ERROR_IF_MBOX_NOT_FOUND -1 - - -/** * \brief update unique_id, message_size and rfc_size of * a message identified by message_idnr * \param message_idnr @@ -1261,4 +1238,11 @@ char *date2char_str(const char *column); int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * mb); + +/* + * db-user accessors + */ + +int db_user_exists(const char *username, u64_t * user_idnr); + #endif diff --git a/dbmail-message.c b/dbmail-message.c index 23e94868..e29a38bc 100644 --- a/dbmail-message.c +++ b/dbmail-message.c @@ -70,6 +70,10 @@ static void _map_headers(struct DbmailMessage *self); static void _set_content(struct DbmailMessage *self, const GString *content); static void _set_content_from_stream(struct DbmailMessage *self, GMimeStream *stream, int type); +static int _message_insert(struct DbmailMessage *self, + u64_t user_idnr, + const char *mailbox, + const char *unique_id); struct DbmailMessage * dbmail_message_new(void) { @@ -126,7 +130,6 @@ struct DbmailMessage * dbmail_message_init_with_string(struct DbmailMessage *sel } _map_headers(self); - self->rfcsize = dbmail_message_get_rfcsize(self); return self; } @@ -134,7 +137,6 @@ struct DbmailMessage * dbmail_message_init_with_stream(struct DbmailMessage *sel { _set_content_from_stream(self,stream,type); _map_headers(self); - self->rfcsize = dbmail_message_get_rfcsize(self); return self; } @@ -194,7 +196,6 @@ static void _set_content_from_stream(struct DbmailMessage *self, GMimeStream *st break; } - self->size = g_mime_stream_length(ostream); g_object_unref(filter); g_object_unref(fstream); @@ -226,11 +227,9 @@ size_t dbmail_message_get_rfcsize(struct DbmailMessage *self) * the rfcsize */ + size_t rfcsize; GMimeStream *ostream, *fstream; GMimeFilter *filter; - - if (self->rfcsize) - return self->rfcsize; ostream = g_mime_stream_mem_new(); fstream = g_mime_stream_filter_new_with_stream(ostream); @@ -239,42 +238,60 @@ size_t dbmail_message_get_rfcsize(struct DbmailMessage *self) g_mime_stream_filter_add((GMimeStreamFilter *) fstream, filter); g_mime_object_write_to_stream((GMimeObject *)self->content,fstream); - self->rfcsize = g_mime_stream_length(ostream); + rfcsize = g_mime_stream_length(ostream); g_object_unref(filter); g_object_unref(fstream); g_object_unref(ostream); - return self->rfcsize; + return rfcsize; } +/* dump message(parts) to char ptrs */ gchar * dbmail_message_to_string(struct DbmailMessage *self) { gchar *s; - GString *msg = g_string_new(g_mime_object_to_string(GMIME_OBJECT(self->content))); - s=msg->str; - g_string_free(msg,FALSE); + GString *t; + assert(self->content); + + t = g_string_new(g_mime_object_to_string(GMIME_OBJECT(self->content))); + + s = t->str; + g_string_free(t,FALSE); return s; } - gchar * dbmail_message_hdrs_to_string(struct DbmailMessage *self) { char *s; - GString *headers = g_string_new(g_mime_object_get_headers((GMimeObject *)(self->content))); - s = headers->str; - g_string_free(headers,FALSE); + GString *t; + assert(self->headers); + + t = g_string_new(g_mime_object_get_headers((GMimeObject *)(self->content))); + + s = t->str; + g_string_free(t,FALSE); return s; } - gchar * dbmail_message_body_to_string(struct DbmailMessage *self) { char *s; - GString *body; - body = g_string_new(g_mime_object_to_string((GMimeObject *)(self->content))); - body = g_string_erase(body,0,dbmail_message_get_hdrs_size(self)); - s = body->str; - g_string_free(body,FALSE); + GString *t; + assert(self->content); + + t = g_string_new(g_mime_object_to_string((GMimeObject *)(self->content))); + t = g_string_erase(t,0,dbmail_message_get_hdrs_size(self)); + + s = t->str; + g_string_free(t,FALSE); return s; } +/* + * we don't cache these values + * to allow changes in message content + */ +size_t dbmail_message_get_size(struct DbmailMessage *self) +{ + return strlen(dbmail_message_to_string(self)); +} size_t dbmail_message_get_hdrs_size(struct DbmailMessage *self) { return strlen(dbmail_message_hdrs_to_string(self)); @@ -284,20 +301,15 @@ size_t dbmail_message_get_body_size(struct DbmailMessage *self) return strlen(dbmail_message_body_to_string(self)); } -size_t dbmail_message_get_size(struct DbmailMessage *self) +void dbmail_message_free(struct DbmailMessage *self) { - return self->size; -} - -void dbmail_message_delete(struct DbmailMessage *self) -{ - g_relation_destroy(self->headers); - g_object_unref(self->content); + if (self->headers) + g_relation_destroy(self->headers); + if (self->content) + g_object_unref(self->content); self->headers=NULL; self->content=NULL; self->id=0; - self->size=0; - self->rfcsize=0; dm_free(self); } @@ -393,20 +405,15 @@ struct DbmailMessage * dbmail_message_retrieve(struct DbmailMessage *self, u64_t /** * store a temporary copy of a message. - * \param header the header to the message - * \param body body of the message - * \param headersize size of header - * \param bodysize size of body - * \param rfcsize rfc size of message - * \param[out] temp_message_idnr message idnr of temporary message + * \param self + * \param[out] temp_message_idnr message idnr of temporary message * \return * - -1 on error * - 1 on success */ -int dbmail_message_store_temp(struct DbmailMessage *self, /*@out@*/ u64_t * temp_message_idnr) +int dbmail_message_store_temp(struct DbmailMessage *self) { u64_t user_idnr; - u64_t msgidnr; u64_t messageblk_idnr; char unique_id[UID_SIZE]; char *hdrs, *body; @@ -430,7 +437,7 @@ int dbmail_message_store_temp(struct DbmailMessage *self, /*@out@*/ u64_t * temp create_unique_id(unique_id, user_idnr); /* create a message record */ - if(db_insert_message(user_idnr, DBMAIL_TEMPMBOX, CREATE_IF_MBOX_NOT_FOUND, unique_id, &msgidnr) < 0) + if(_message_insert(self, user_idnr, DBMAIL_TEMPMBOX, unique_id) < 0) return -1; hdrs = dbmail_message_hdrs_to_string(self); @@ -439,26 +446,66 @@ int dbmail_message_store_temp(struct DbmailMessage *self, /*@out@*/ u64_t * temp body_size = (u64_t)dbmail_message_get_body_size(self); rfcsize = (u64_t)dbmail_message_get_rfcsize(self); - - if(db_insert_message_block(hdrs, hdrs_size, msgidnr, &messageblk_idnr,1) < 0) + if(db_insert_message_block(hdrs, hdrs_size, self->id, &messageblk_idnr,1) < 0) return -1; trace(TRACE_DEBUG, "%s,%s: allocating [%ld] bytes of memory " "for readblock", __FILE__, __func__, READ_BLOCK_SIZE); /* store body in several blocks (if needed */ - if (store_message_in_blocks(body, body_size, msgidnr) < 0) + if (store_message_in_blocks(body, body_size, self->id) < 0) return -1; - if (db_update_message(msgidnr, unique_id, (hdrs_size + body_size), rfcsize) < 0) + if (db_update_message(self->id, unique_id, (hdrs_size + body_size), rfcsize) < 0) return -1; - *temp_message_idnr = msgidnr; - g_free(hdrs); g_free(body); return 1; } +int _message_insert(struct DbmailMessage *self, + u64_t user_idnr, + const char *mailbox, + const char *unique_id) +{ + u64_t mailboxid; + u64_t physmessage_id; + + assert(unique_id); + + if (!mailbox) + mailbox = dm_strdup("INBOX"); + + if (db_find_create_mailbox(mailbox, user_idnr, &mailboxid) == -1) + return -1; + + if (mailboxid == 0) { + trace(TRACE_ERROR, "%s,%s: mailbox [%s] could not be found!", + __FILE__, __func__, mailbox); + return -1; + } + + /* insert a new physmessage entry */ + if (db_insert_physmessage(&physmessage_id) == -1) + return -1; + + /* now insert an entry into the messages table */ + snprintf(query, DEF_QUERYSIZE, "INSERT INTO " + "%smessages(mailbox_idnr, physmessage_id, unique_id," + "recent_flag, status) " + "VALUES ('%llu', '%llu', '%s', '1', '%d')", + DBPFX, mailboxid, physmessage_id, unique_id, + MESSAGE_STATUS_INSERT); + + if (db_query(query) == -1) { + trace(TRACE_STOP, "%s,%s: query failed", __FILE__, __func__); + return -1; + } + + self->id = db_insert_result("message_idnr"); + return 1; +} + diff --git a/dbmail-message.h b/dbmail-message.h index 90497eb4..d1830393 100644 --- a/dbmail-message.h +++ b/dbmail-message.h @@ -64,10 +64,8 @@ enum DBMAIL_STREAM_TYPE { }; struct DbmailMessage { - gulong id; + u64_t id; enum DBMAIL_MESSAGE_CLASS klass; - size_t size; - size_t rfcsize; GMimeObject *content; GRelation *headers; }; @@ -95,13 +93,12 @@ gchar * dbmail_message_to_string(struct DbmailMessage *self); gchar * dbmail_message_hdrs_to_string(struct DbmailMessage *self); gchar * dbmail_message_body_to_string(struct DbmailMessage *self); -size_t dbmail_message_get_hdrs_size(struct DbmailMessage *self); -size_t dbmail_message_get_body_size(struct DbmailMessage *self); - size_t dbmail_message_get_size(struct DbmailMessage *self); size_t dbmail_message_get_rfcsize(struct DbmailMessage *self); +size_t dbmail_message_get_hdrs_size(struct DbmailMessage *self); +size_t dbmail_message_get_body_size(struct DbmailMessage *self); -void dbmail_message_delete(struct DbmailMessage *self); +void dbmail_message_free(struct DbmailMessage *self); /* * @@ -112,13 +109,11 @@ void dbmail_message_delete(struct DbmailMessage *self); /** * store a temporary copy of a message. - * \param message pointer to dbmailmessage struct - * \param[out] temp_message_idnr message idnr of temporary message * \return * - -1 on error * - 1 on success */ -int dbmail_message_store_temp(struct DbmailMessage *message, /*@out@*/ u64_t * temp_message_idnr); +int dbmail_message_store_temp(struct DbmailMessage *message); #endif @@ -165,4 +165,5 @@ void GetDBParams(db_param_t * db_params); */ void SetTraceLevel(const char *service_name); + #endif diff --git a/debian/rules b/debian/rules index af10bfeb..d55319e5 100755 --- a/debian/rules +++ b/debian/rules @@ -10,7 +10,8 @@ export DH_COMPAT=3 export DEB_BUILD_OPTIONS=debug #export WITH_GC="--with-gc" -export WITH_CHECK="--with-check" +export WITH_CHECK=--with-check +export NOSHARED=--enable-share=no CFLAGS = -Wall -O1 LDFLAGS = -lcrypt @@ -35,7 +36,7 @@ include /usr/share/dpatch/dpatch.make CONFFLAGS=--host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) \ --prefix=/usr --mandir=\$${prefix}/share/man --sysconfdir=/etc/dbmail/ \ - --infodir=\$${prefix}/share/info $(WITH_GC) $(WITH_CHECK) + --infodir=\$${prefix}/share/info $(WITH_GC) $(WITH_CHECK) $(NOSHARED) build: stamps/build stamps/build: stamps patch configure $(PACKAGES) @@ -102,56 +102,6 @@ const char *envelope_items[] = { static const char *search_cost[] = { "b","b","c","c","c","d","d","d","d","c","e","e","b","b","j","j","j" }; -/* - * - * - * Some basic string handling utilities - * - * - * - */ -GString * g_list_join(GList * list, char * sep) -{ - GString *string = g_string_new(""); - if (sep == NULL) - sep=""; - if (list == NULL) - return string; - list = g_list_first(list); - string = g_string_append(string, (gchar *)list->data); - while((list = g_list_next(list))) { - string = g_string_append(string,sep); - string = g_string_append(string,(gchar *)list->data); - } - return string; -} - -GList * g_string_split(GString * string, char * sep) -{ - GList * list = NULL; - char **array = (char **)g_strsplit((const gchar *)string->str, (const gchar *)sep,0); - int i, len = 0; - while(array[len++]); - len--; - for (i=0; i<len; i++) - list = g_list_append(list,g_strdup(array[i])); - g_strfreev(array); - return list; -} -/* - * append a formatted GString to a GList - */ -GList * g_list_append_printf(GList * list, char * format, ...) -{ - char *str = (char *)dm_malloc(sizeof(char) * BUFLEN); - va_list argp; - va_start(argp, format); - vsnprintf(str, sizeof(char) * BUFLEN, format, argp); - list = g_list_append(list, strdup(str)); - dm_free(str); - return list; -} - /* some basic imap type utils */ /* @@ -98,10 +98,6 @@ char * dbmail_imap_astring_as_string(const char *s); char * dbmail_imap_plist_as_string(GList *plist); GList *dbmail_imap_list_slices(GList *list, unsigned limit); -GString * g_list_join(GList * list, char * sep); -GList * g_string_split(GString * string, char * sep); -GList * g_list_append_printf(GList * list, char * format, ...); - int mime_unwrap(char *to, const char *from); int sort_search(struct list *searchlist); @@ -217,6 +217,19 @@ void list_showlist(struct list *tlist) temp = temp->nextnode; } } +/* + * shallow copy of struct list into GList + */ + +GList * g_list_copy_list(GList *dst, struct element *el) +{ + while(el) { + dst = g_list_append(dst, el->data); + el = el->nextnode; + } + return dst; +} + /* basic binary tree */ void list_btree_insert(sortitems_t ** tree, sortitems_t * item) { @@ -57,6 +57,8 @@ long list_totalnodes(struct list *tlist); void list_showlist(struct list *tlist); void list_init(struct list *tlist); +GList * g_list_copy_list(GList *dst, struct element *el); + /* this function had to be renamed because some MySQL versions * export a function with the name list_reverse(). Nice of them, * but a pretty "strange" way to pollute the global namespace @@ -392,7 +392,7 @@ int main(int argc, char *argv[]) list_freelist(&returnpath.start); list_freelist(&users.start); - dbmail_message_delete(msg); + dbmail_message_free(msg); trace(TRACE_DEBUG, "main(): they're all free. we're done."); @@ -491,3 +491,54 @@ int find_bounded(char *value, char left, char right, char **retchar, return 0; } } + +/* + * + * + * Some basic string handling utilities + * + * + * + */ +GString * g_list_join(GList * list, char * sep) +{ + GString *string = g_string_new(""); + if (sep == NULL) + sep=""; + if (list == NULL) + return string; + list = g_list_first(list); + string = g_string_append(string, (gchar *)list->data); + while((list = g_list_next(list))) { + string = g_string_append(string,sep); + string = g_string_append(string,(gchar *)list->data); + } + return string; +} + +GList * g_string_split(GString * string, char * sep) +{ + GList * list = NULL; + char **array = (char **)g_strsplit((const gchar *)string->str, (const gchar *)sep,0); + int i, len = 0; + while(array[len++]); + len--; + for (i=0; i<len; i++) + list = g_list_append(list,g_strdup(array[i])); + g_strfreev(array); + return list; +} +/* + * append a formatted GString to a GList + */ +GList * g_list_append_printf(GList * list, char * format, ...) +{ + char *str = (char *)dm_malloc(sizeof(char) * BUFLEN); + va_list argp; + va_start(argp, format); + vsnprintf(str, sizeof(char) * BUFLEN, format, argp); + list = g_list_append(list, strdup(str)); + dm_free(str); + return list; +} + @@ -35,6 +35,8 @@ #include "debug.h" #include "list.h" +#define BUFLEN 2048 + /** \brief drop process privileges. Change change euid and egid to uid and gid of newuser and newgroup @@ -108,4 +110,8 @@ int find_bounded(char *value, char left, char right, char **retchar, int base64_grow_ret(char ***inchar, size_t ** inint, size_t newcount, size_t newchar); +GString * g_list_join(GList * list, char * sep); +GList * g_string_split(GString * string, char * sep); +GList * g_list_append_printf(GList * list, char * format, ...); + #endif @@ -424,7 +424,7 @@ int insert_messages(struct DbmailMessage *message, char *header, *body; u64_t headersize, bodysize, rfcsize; struct element *element, *ret_path; - u64_t msgsize, tmpmsgidnr; + u64_t msgsize; /* first start a new database transaction */ if (db_begin_transaction() < 0) { @@ -434,17 +434,15 @@ int insert_messages(struct DbmailMessage *message, return -1; } - switch (dbmail_message_store_temp(message, &tmpmsgidnr)) { + switch (dbmail_message_store_temp(message)) { case -1: - /* Major trouble. Bail out immediately. */ - trace(TRACE_ERROR, - "%s, %s: failed to store temporary message.", + trace(TRACE_ERROR, "%s, %s: failed to store temporary message.", __FILE__, __func__); db_rollback_transaction(); return -1; default: trace(TRACE_DEBUG, "%s, %s: temporary msgidnr is [%llu]", - __FILE__, __func__, tmpmsgidnr); + __FILE__, __func__, message->id); break; } @@ -474,7 +472,7 @@ int insert_messages(struct DbmailMessage *message, "%s, %s: calling sort_and_deliver for useridnr [%llu]", __FILE__, __func__, useridnr); - switch (sort_and_deliver(tmpmsgidnr, header, headersize, msgsize, useridnr, delivery->mailbox)) { + switch (sort_and_deliver(message->id, header, headersize, msgsize, useridnr, delivery->mailbox)) { case DSN_CLASS_OK: /* Indicate success. */ trace(TRACE_DEBUG, @@ -548,7 +546,7 @@ int insert_messages(struct DbmailMessage *message, ret_path = list_getstart(returnpath); /* Forward using the temporary stored message. */ - if (forward(tmpmsgidnr, delivery->forwards, + if (forward(message->id, delivery->forwards, (ret_path ? ret_path-> data : "DBMAIL-MAILER"), header, headersize) < 0) @@ -563,9 +561,9 @@ int insert_messages(struct DbmailMessage *message, /* Always delete the temporary message, even if the delivery failed. * It is the MTA's job to requeue or bounce the message, * and our job to keep a tidy database ;-) */ - if (db_delete_message(tmpmsgidnr) < 0) + if (db_delete_message(message->id) < 0) trace(TRACE_ERROR, "%s,%s: failed to delete temporary message " - "[%llu]", __FILE__, __func__, tmpmsgidnr); + "[%llu]", __FILE__, __func__, message->id); trace(TRACE_DEBUG, "insert_messages(): temporary message deleted from database"); @@ -35,6 +35,7 @@ #include "list.h" #include "debug.h" #include "db.h" +#include "misc.h" #include <time.h> #include <stdarg.h> #include <sys/types.h> @@ -103,8 +104,8 @@ int do_add(const char * const user, const char * const password, const char * const enctype, const u64_t maxmail, const u64_t clientid, - struct list * const alias_add, - struct list * const alias_del); + GList * alias_add, + GList * alias_del); int do_delete(const u64_t useridnr, const char * const user); int do_show(const char * const user); int do_empty(const u64_t useridnr); @@ -116,12 +117,12 @@ int do_password(const u64_t useridnr, const char * const password, const char * const enctype); int do_aliases(const u64_t useridnr, - struct list * const alias_add, - struct list * const alias_del); + GList * alias_add, + GList * alias_del); /* External forwards */ int do_forwards(const char *alias, const u64_t clientid, - struct list * const fwds_add, - struct list * const fwds_del); + GList * fwds_add, + GList * fwds_del); /* Helper functions */ int is_valid(const char * const str); @@ -185,14 +186,10 @@ int main(int argc, char *argv[]) *passwdfile = NULL; char *password = NULL, *enctype = NULL; u64_t useridnr = 0, clientid = 0, maxmail = 0; - struct list alias_add, alias_del, fwds_add, fwds_del; + GList *alias_add = NULL, *alias_del = NULL, *fwds_add = NULL, *fwds_del = NULL; struct change_flags change_flags; size_t len = 0; - list_init(&alias_add); - list_init(&alias_del); - list_init(&fwds_add); - list_init(&fwds_del); openlog(PNAME, LOG_PID, LOG_MAIL); setvbuf(stdout, 0, _IONBF, 0); @@ -299,25 +296,25 @@ int main(int argc, char *argv[]) case 's': // Add this item to the user's aliases. if (optarg && (len = strlen(optarg))) - list_nodeadd(&alias_add, optarg, len+1); + alias_add = g_list_append(alias_add, g_strdup(optarg)); break; case 'S': // Delete this item from the user's aliases. if (optarg && (len = strlen(optarg))) - list_nodeadd(&alias_del, optarg, len+1); + alias_del = g_list_append(alias_del, g_strdup(optarg)); break; case 't': // Add this item to the alias's forwards. if (optarg && (len = strlen(optarg))) - list_nodeadd(&fwds_add, optarg, len+1); + fwds_add = g_list_append(fwds_add, g_strdup(optarg)); break; case 'T': // Delete this item from the alias's forwards. if (optarg && (len = strlen(optarg))) - list_nodeadd(&fwds_del, optarg, len+1); + fwds_del = g_list_append(fwds_del, g_strdup(optarg)); break; /* Common options */ @@ -394,7 +391,6 @@ int main(int argc, char *argv[]) GetDBParams(&_db_params); /* open database connection */ - qprintf("Opening connection to database...\n"); if (db_connect() != 0) { qerrorf ("Failed. Could not connect to database (check log)\n"); @@ -403,7 +399,6 @@ int main(int argc, char *argv[]) } /* open authentication connection */ - qprintf("Opening connection to authentication...\n"); if (auth_connect() != 0) { qerrorf ("Failed. Could not connect to authentication (check log)\n"); @@ -411,8 +406,7 @@ int main(int argc, char *argv[]) goto freeall; } - qprintf("Ok. Connected\n"); - configure_debug(TRACE_ERROR, 1, 0); + //configure_debug(TRACE_ERROR, 1, 0); switch (mode) { case 'c': @@ -482,7 +476,7 @@ int main(int argc, char *argv[]) switch (mode) { case 'a': result = do_add(user, password, enctype, maxmail, clientid, - &alias_add, &alias_del); + alias_add, alias_del); break; case 'd': result = do_delete(useridnr, user); @@ -501,7 +495,7 @@ int main(int argc, char *argv[]) if (change_flags.newmaxmail) { result |= do_maxmail(useridnr, maxmail); } - result |= do_aliases(useridnr, &alias_add, &alias_del); + result |= do_aliases(useridnr, alias_add, alias_del); break; case 'e': result = do_empty(useridnr); @@ -510,7 +504,7 @@ int main(int argc, char *argv[]) result = do_show(userspec); break; case 'x': - result = do_forwards(alias, clientid, &fwds_add, &fwds_del); + result = do_forwards(alias, clientid, fwds_add, fwds_del); break; default: result = 1; @@ -521,14 +515,22 @@ int main(int argc, char *argv[]) freeall: /* Free the lists. */ - if (alias_del.start) - list_freelist(&alias_del.start); - if (alias_add.start) - list_freelist(&alias_add.start); - if (fwds_del.start) - list_freelist(&alias_del.start); - if (fwds_add.start) - list_freelist(&alias_add.start); + if (alias_del) { + g_list_foreach(alias_del, (GFunc)g_free, NULL); + g_list_free(alias_del); + } + if (alias_add) { + g_list_foreach(alias_add, (GFunc)g_free, NULL); + g_list_free(alias_add); + } + if (fwds_del) { + g_list_foreach(fwds_del, (GFunc)g_free, NULL); + g_list_free(fwds_del); + } + if (fwds_add) { + g_list_foreach(fwds_add, (GFunc)g_free, NULL); + g_list_free(fwds_add); + } db_disconnect(); auth_disconnect(); @@ -542,8 +544,8 @@ freeall: int do_add(const char * const user, const char * const password, const char * const enctype, const u64_t maxmail, const u64_t clientid, - struct list * const alias_add, - struct list * const alias_del) + GList * alias_add, + GList * alias_del) { u64_t useridnr; u64_t mailbox_idnr; @@ -775,18 +777,17 @@ int do_maxmail(u64_t useridnr, u64_t maxmail) } int do_forwards(const char * const alias, const u64_t clientid, - struct list * const fwds_add, - struct list * const fwds_del) + GList * fwds_add, + GList * fwds_del) { int result = 0; char *forward; - struct element *tmp; /* Delete aliases for the user. */ if (fwds_del) { - tmp = list_getstart(fwds_del); - while (tmp) { - forward = (char *)tmp->data; + fwds_del = g_list_first(fwds_del); + while (fwds_del) { + forward = (char *)fwds_del->data; qprintf("[%s]\n", forward); @@ -795,15 +796,15 @@ int do_forwards(const char * const alias, const u64_t clientid, forward); result = -1; } - tmp = tmp->nextnode; + fwds_del = g_list_next(fwds_del); } } /* Add aliases for the user. */ if (fwds_add) { - tmp = list_getstart(fwds_add); - while (tmp) { - forward = (char *)tmp->data; + fwds_add = g_list_first(fwds_add); + while (fwds_add) { + forward = (char *)fwds_add->data; qprintf("[%s]\n", forward); if (auth_addalias_ext(alias, forward, clientid) < 0) { @@ -811,7 +812,7 @@ int do_forwards(const char * const alias, const u64_t clientid, alias); result = -1; } - tmp = tmp->nextnode; + fwds_add = g_list_next(fwds_add); } } @@ -840,53 +841,43 @@ int do_forwards(const char * const alias, const u64_t clientid, } int do_aliases(const u64_t useridnr, - struct list * const alias_add, - struct list * const alias_del) + GList * alias_add, + GList * alias_del) { int result = 0; + char *alias; u64_t clientid; auth_getclientid(useridnr, &clientid); /* Delete aliases for the user. */ if (alias_del) { - char *alias; - struct element *tmp; - - tmp = list_getstart(alias_del); - while (tmp) { - alias = (char *)tmp->data; + alias_del = g_list_first(alias_del); + while (alias_del) { + alias = (char *)alias_del->data; qprintf("[%s]\n", alias); - if (auth_removealias(useridnr, alias) < - 0) { - qerrorf("Error: could not remove alias [%s] \n", - alias); + if (auth_removealias(useridnr, alias) < 0) { + qerrorf("Error: could not remove alias [%s] \n", alias); result = -1; } - tmp = tmp->nextnode; + alias_del = g_list_next(alias_del); } } /* Add aliases for the user. */ if (alias_add) { - char *alias; - struct element *tmp; - - - tmp = list_getstart(alias_add); - while (tmp) { - alias = (char *)tmp->data; + alias_add = g_list_first(alias_add); + while (alias_add) { + alias = (char *)alias_add->data; qprintf("[%s]\n", alias); - if (auth_addalias - (useridnr, alias, clientid) < 0) { - qerrorf("Error: could not add alias [%s]\n", - alias); + if (auth_addalias (useridnr, alias, clientid) < 0) { + qerrorf("Error: could not add alias [%s]\n", alias); result = -1; } - tmp = tmp->nextnode; + alias_add = g_list_next(alias_add); } } @@ -899,11 +890,11 @@ int do_aliases(const u64_t useridnr, int do_delete(const u64_t useridnr, const char * const name) { int result; - struct list aliases; + GList *aliases = NULL; qprintf("Deleting aliases for user [%s]...\n", name); - auth_get_user_aliases(useridnr, &aliases); - do_aliases(useridnr, NULL, &aliases); + aliases = auth_get_user_aliases(useridnr); + do_aliases(useridnr, NULL, aliases); qprintf("Deleting user [%s]...\n", name); result = auth_delete_user(name); @@ -921,19 +912,21 @@ int do_show(const char * const name) { u64_t useridnr, cid, quotum, quotumused; GList *users = NULL; - struct list userlist; - struct element *tmp; - char *deliver_to; + GList *userlist = NULL; + char *username; + int result; + struct list uids; + struct list fwds; + GList *userids = NULL; + GList *forwards = NULL; if (!name) { /* show all users */ - qprintf("Existing users:\n"); - users = auth_get_known_users(); if (g_list_length(users) > 0) { users = g_list_first(users); while (users) { - qprintf("[%s]\n", (char *) users->data); + do_show(users->data); users = g_list_next(users); } g_list_foreach(users,(GFunc)g_free,NULL); @@ -941,74 +934,79 @@ int do_show(const char * const name) g_list_free(users); } else { - qprintf("Info for user [%s]", name); - if (auth_user_exists(name, &useridnr) == -1) { - qerrorf("Error: cannot verify existence of user [%s].\n", - name); + qerrorf("Error while verifying user [%s].\n", name); return -1; } if (useridnr == 0) { - /* 'name' is not a user, try it as an alias */ - qprintf - ("..is not a user, trying as an alias"); - - deliver_to = auth_get_deliver_from_alias(name); - - if (!deliver_to) { - qerrorf("Error: cannot verify existence of alias [%s].\n", - name); + /* not a user, search aliases */ + list_init(&fwds); + list_init(&uids); + result = auth_check_user_ext(name,&uids,&fwds,-1); + + if (!result) { + qerrorf("Nothing found searching for [%s].\n", name); return -1; } - - if (deliver_to[0] == '\0') { - qprintf("..is not an alias.\n"); - return -1; + + if (list_getstart(&uids)) + userids = g_list_copy_list(userids,list_getstart(&uids)); + if (list_getstart(&fwds)) + forwards = g_list_copy_list(forwards,list_getstart(&fwds)); + + forwards = g_list_first(forwards); + if (forwards) { + while(forwards) { + qerrorf("forward [%s] to [%s]\n", name, (char *)forwards->data); + forwards = g_list_next(forwards); + } + g_list_foreach(forwards,(GFunc)g_free, NULL); + g_list_free(forwards); } - - useridnr = strtoul(deliver_to, NULL, 10); - if (useridnr == 0) { - qprintf - ("\n[%s] is an alias for [%s]\n", name, - deliver_to); - dm_free(deliver_to); - return 0; + + userids = g_list_first(userids); + if (userids) { + while (userids) { + username = auth_get_userid(*(u64_t *)userids->data); + qerrorf("deliver [%s] to [%s]\n-------\n", name, username); + do_show(username); + userids = g_list_next(userids); + } + g_list_free(userids); } - - dm_free(deliver_to); - qprintf("\nFound user for alias [%s]:\n\n", - name); + return 0; } auth_getclientid(useridnr, &cid); auth_getmaxmailsize(useridnr, "um); db_get_quotum_used(useridnr, "umused); - qprintf("\n"); - qprintf("User ID : %llu\n", useridnr); - qprintf("Username : %s\n", - auth_get_userid(useridnr)); - qprintf("Client ID : %llu\n", cid); - qprintf("Max. mailboxsize: %.02f MB\n", - (double) quotum / (1024.0 * 1024.0)); - qprintf("Quotum used : %.02f MB (%.01f%%)\n", - (double) quotumused / (1024.0 * 1024.0), - (100.0 * quotumused) / (double) quotum); - qprintf("\n"); - - qprintf("Aliases:\n"); - auth_get_user_aliases(useridnr, &userlist); - - tmp = list_getstart(&userlist); - while (tmp) { - qprintf("%s\n", (char *) tmp->data); - tmp = tmp->nextnode; + GList *out = NULL; + GString *s = g_string_new(""); + out = g_list_append_printf(out,"%s", auth_get_userid(useridnr)); + out = g_list_append_printf(out,"x"); + out = g_list_append_printf(out,"%llu", useridnr); + out = g_list_append_printf(out,"%llu", cid); + out = g_list_append_printf(out,"%.02f", + (double) quotum / (1024.0 * 1024.0)); + out = g_list_append_printf(out,"%.02f", + (double) quotumused / (1024.0 * 1024.0)); + out = g_list_append_printf(out,"%.01f%%", + (100.0 * quotumused) / ( quotum ? (double) quotum: 1)); + + userlist = auth_get_user_aliases(useridnr); + + if (g_list_length(userlist)) { + userlist = g_list_first(userlist); + s = g_list_join(userlist,","); + g_list_append_printf(out,"%s", s->str); + g_list_foreach(userlist,(GFunc)g_free, NULL); } - - qprintf("\n"); - if (userlist.start) - list_freelist(&userlist.start); + g_list_free(userlist); + s = g_list_join(out,":"); + qprintf("%s\n", s->str); + g_string_free(s,TRUE); } return 0; |