As I began moving from pure-testing to a production-test, I noticed a major problem: LDAP connections expire! This revision adds a function called auth_reconnect() which... reconnects... to the server. It does so in the most dumb way possible, by killing and then recreating the connection regardless of its current state. It works, though ;-)
For a future revision, I'll find a better way to see if the LDAP connection has gone stale and needs to be recreated, or if it's fine and just return right away to use what's there already. There's also a bug I found that if you have any of the dbmail.conf values for the fields set incorrectly, causing ldap_get_values to return NULL, we segfault. Oops! I'll address that shortly, too. Eelco, Roel... any indications about including this into the distribution? Aaron
/* * $Id: authldap.c $ * (c) 2002 Aaron Stone, [EMAIL PROTECTED] * User authentication functions for LDAP. */ #include "auth.h" #include <ldap.h> #include "list.h" #include "debug.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include "db.h" #include "dbmd5.h" #include <crypt.h> #include "config.h" #include <time.h> #define AUTH_QUERY_SIZE 1024 extern char *configFile; 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]; field_t _cfg_ldap_bind_dn, _cfg_ldap_bind_pw, _cfg_ldap_base_dn, _cfg_ldap_port, _cfg_ldap_scope, _cfg_ldap_hostname, _cfg_ldap_objectclass, _cfg_ldap_field_uid, _cfg_ldap_field_cid, _cfg_ldap_field_nid, _cfg_ldap_field_mail, _cfg_ldap_field_mailalt, _cfg_ldap_field_maxmail, _cfg_ldap_field_passwd; int _cfg_ldap_scope_int; static void _get_ldap_config() { struct list ldapItems; ReadConfig("LDAP", configFile, &ldapItems); SetTraceLevel(&ldapItems); GetConfigValue("BIND_DN", &ldapItems, _cfg_ldap_bind_dn); if (strlen(_cfg_ldap_bind_dn) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for BIND_DN in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): bind dn [%s]", _cfg_ldap_bind_dn); GetConfigValue("BIND_PW", &ldapItems, _cfg_ldap_bind_pw); if (strlen(_cfg_ldap_bind_pw) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for BIND_PW in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): bind pw [%s]", _cfg_ldap_bind_pw); GetConfigValue("BASE_DN", &ldapItems, _cfg_ldap_base_dn); if (strlen(_cfg_ldap_base_dn) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for BASE_DN in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): base dn [%s]", _cfg_ldap_base_dn); GetConfigValue("PORT", &ldapItems, _cfg_ldap_port); if (strlen(_cfg_ldap_port) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for PORT in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): port [%s]", _cfg_ldap_port); GetConfigValue("HOSTNAME", &ldapItems, _cfg_ldap_hostname); if (strlen(_cfg_ldap_hostname) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for HOSTNAME in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): hostname [%s]", _cfg_ldap_hostname); GetConfigValue("OBJECTCLASS", &ldapItems, _cfg_ldap_objectclass); if (strlen(_cfg_ldap_objectclass) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for OBJECTCLASS in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): objectclass [%s]", _cfg_ldap_objectclass); GetConfigValue("FIELD_UID", &ldapItems, _cfg_ldap_field_uid); if (strlen(_cfg_ldap_field_uid) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_UID in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): uid field [%s] ", _cfg_ldap_field_uid); GetConfigValue("FIELD_CID", &ldapItems, _cfg_ldap_field_cid); if (strlen(_cfg_ldap_field_cid) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_CID in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): cid field [%s]", _cfg_ldap_field_cid); GetConfigValue("FIELD_NID", &ldapItems, _cfg_ldap_field_nid); if (strlen(_cfg_ldap_field_nid) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_NID in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): nid field [%s]", _cfg_ldap_field_nid); GetConfigValue("FIELD_MAIL", &ldapItems, _cfg_ldap_field_mail); if (strlen(_cfg_ldap_field_mail) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_MAIL in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): mail field [%s]", _cfg_ldap_field_mail); GetConfigValue("FIELD_MAILALT", &ldapItems, _cfg_ldap_field_mailalt); if (strlen(_cfg_ldap_field_mailalt) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_MAILALT in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): mail alt field [%s]", _cfg_ldap_field_mailalt); GetConfigValue("FIELD_QUOTA", &ldapItems, _cfg_ldap_field_maxmail); if (strlen(_cfg_ldap_field_maxmail) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_QUOTA in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): quota field [%s]", _cfg_ldap_field_maxmail); GetConfigValue("FIELD_PASSWD", &ldapItems, _cfg_ldap_field_passwd); if (strlen(_cfg_ldap_field_maxmail) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for FIELD_PASSWD in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): password field [%s]", _cfg_ldap_field_passwd); GetConfigValue("SCOPE", &ldapItems, _cfg_ldap_scope); if (strlen(_cfg_ldap_scope) == 0) trace(TRACE_DEBUG, "_get_ldap_config(): no value for SCOPE in config file"); trace(TRACE_DEBUG, "_get_ldap_config(): raw ldap scope is [%s]", _cfg_ldap_scope); /* Compare the input string with the possible options, * making sure not to exceeed the length of the given string */ if( strncasecmp( _cfg_ldap_scope, "one", ( strlen( _cfg_ldap_scope ) < 3 ? strlen( _cfg_ldap_scope ) : 3 ) ) == 0 ) _cfg_ldap_scope_int = LDAP_SCOPE_ONELEVEL; else if( strncasecmp( _cfg_ldap_scope, "bas", ( strlen( _cfg_ldap_scope ) < 3 ? strlen( _cfg_ldap_scope ) : 3 ) ) == 0 ) _cfg_ldap_scope_int = LDAP_SCOPE_BASE; else if( strncasecmp( _cfg_ldap_scope, "sub", ( strlen( _cfg_ldap_scope ) < 3 ? strlen( _cfg_ldap_scope ) : 3 ) ) == 0 ) _cfg_ldap_scope_int = LDAP_SCOPE_SUBTREE; else _cfg_ldap_scope_int = LDAP_SCOPE_SUBTREE; trace(TRACE_DEBUG, "_get_ldap_config(): integer ldap scope is [%d]", _cfg_ldap_scope_int); list_freelist( &ldapItems.start ); } /* * auth_connect() * * initializes the connection for authentication. * * returns 0 on success, -1 on failure */ int auth_connect() { _get_ldap_config(); return 0; } int auth_disconnect() { /* Destroy the connection */ if( _ldap_conn != NULL ) { trace(TRACE_DEBUG, "auth_disconnect(): disconnecting from ldap server" ); ldap_unbind( _ldap_conn ); } else { trace(TRACE_DEBUG, "auth_disconnect(): was already disconnected from ldap server" ); } return 0; } /* * At the top of each function, rebind to the server * * Someday, this will be smart enough to know if the * connection has a problem, and only then will it * do the unbind->init->bind dance. * * For now, we are lazy and resource intensive! Why? * Because we leave the connection open to lag to death * at the end of each function. It's a trade off, really. * We could always close it at the end, but then we'd * never be able to recycle a connection for a flurry of * calls. OTOH, if the calls are always far between, we'd * rather just be connected strictly as needed... */ int auth_reconnect() { /* Destroy the old... */ if( _ldap_conn != NULL ) { trace(TRACE_DEBUG, "auth_reconnect(): disconnecting from ldap server" ); ldap_unbind( _ldap_conn ); } else { trace(TRACE_DEBUG, "auth_reconnect(): was already disconnected from ldap server" ); } /* ...and make anew! */ trace(TRACE_DEBUG, "auth_reconnect(): connecting to ldap server on [%s] : [%s]", _cfg_ldap_hostname, _cfg_ldap_port ); _ldap_conn = ldap_init( _cfg_ldap_hostname, atoi( _cfg_ldap_port ) ); trace(TRACE_DEBUG, "auth_reconnect(): binding to ldap server as [%s] / [%s]", _cfg_ldap_bind_dn, _cfg_ldap_bind_pw ); _ldap_err = ldap_bind_s( _ldap_conn, _cfg_ldap_bind_dn, _cfg_ldap_bind_pw, LDAP_AUTH_SIMPLE ); if( _ldap_err ) { trace(TRACE_ERROR,"auth_reconnect(): ldap_bind_s failed: %s", ldap_err2string( _ldap_err ) ); return -1; } trace(TRACE_DEBUG, "auth_reconnect(): successfully bound to ldap server"); return 0; } u64_t auth_user_exists(const char *username) { u64_t id; auth_reconnect(); if (!username) { trace(TRACE_ERROR,"auth_user_exists(): got NULL as username"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%s)", _cfg_ldap_field_uid, username ); trace(TRACE_DEBUG, "auth_user_exists(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_user_exists(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return -1; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_user_exists(): none found"); ldap_msgfree( _ldap_res ); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_user_exists(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return -1; } _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_nid ); id = ( _ldap_vals[0] ) ? strtoull( _ldap_vals[0], NULL, 0 ) : 0; trace(TRACE_DEBUG, "auth_user_exists(): returned value is [%s]", _ldap_vals[0] ); ldap_msgfree( _ldap_res ); ldap_value_free( _ldap_vals ); return id; } /* return a list of existing users. -2 on mem error, -1 on db-error, 0 on succes */ int auth_get_known_users(struct list *users) { int i, j; auth_reconnect(); if (!users) { trace(TRACE_ERROR,"auth_get_known_users(): got a NULL pointer as argument"); return -2; } list_init(users); snprintf( _ldap_query, AUTH_QUERY_SIZE, "(objectClass=%s)", _cfg_ldap_objectclass ); trace(TRACE_DEBUG,"auth_get_known_users(): searching with query [%s]",_ldap_query); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace( TRACE_ERROR, "auth_get_known_users(): could not retrieve user list: %s", ldap_err2string( _ldap_err ) ); return -1; } /* find out how many results for our query */ j = ldap_count_entries( _ldap_conn, _ldap_res ); if( j > 0 ) { /* for the first result we use ldap_first_entry */ _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,"auth_get_known_users(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } /* for subsequent results we use ldap_next_entry at the end of the loop */ for ( i = 0; i < j; i++ ) { /* the LDAPMessage structure has entries for "res" and "msg" so we use just one of them here */ _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,"auth_get_known_users(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); return -1; } trace(TRACE_DEBUG,"auth_get_known_users(): found something at [%s]", _ldap_dn ); ldap_memfree( _ldap_dn ); _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_uid ); if ( _ldap_vals == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_get_known_users(): ldap_get_values failed for [%s]: %s", _cfg_ldap_field_uid, ldap_err2string( _ldap_err ) ); return -1; } if ( !list_nodeadd( users, _ldap_vals[0], strlen( _ldap_vals[0] ) + 1 ) ) { list_freelist( &users->start ); return -2; } /* gotta free each result as we're done using it */ ldap_value_free( _ldap_vals ); /* if we're not yet at the last entry, then pull up the next one */ if( i + 1 < j ) { _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,"auth_get_known_users(): ldap_next_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } } } } else { trace(TRACE_ERROR,"auth_get_known_users(): no users found" ); } /* we already freed that values as we used them in the for loop, just do the result set now */ ldap_msgfree( _ldap_res ); return 0; } /* * Get the Client ID number * Return 0 on successful failure * Return -1 on really big failures */ u64_t auth_getclientid(u64_t useridnr) { u64_t cid; auth_reconnect(); if (!useridnr) { trace(TRACE_ERROR,"auth_getclientid(): got NULL as useridnr"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, useridnr ); trace (TRACE_DEBUG,"auth_getclientid(): searching with query [%s]",_ldap_query); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_getclientid(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return -1; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_getclientid(): no entries found"); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_getclientid(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } _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,"auth_getclientid(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); return -1; } trace(TRACE_DEBUG,"auth_getclientid(): found something at [%s]", _ldap_dn ); ldap_memfree( _ldap_dn ); _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_cid ); if( _ldap_vals == NULL ) { trace (TRACE_DEBUG,"auth_getclientid(): no values found"); cid = 0; } else { cid = ( _ldap_vals[0] ) ? strtoull( _ldap_vals[0], NULL, 0 ) : 0; } ldap_msgfree( _ldap_res ); ldap_value_free( _ldap_vals ); return cid; } u64_t auth_getmaxmailsize(u64_t useridnr) { u64_t maxmailsize; auth_reconnect(); if (!useridnr) { trace(TRACE_ERROR,"auth_getmaxmailsize(): got NULL as useridnr"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, useridnr ); trace (TRACE_DEBUG,"auth_getmaxmailsize(): searching with query [%s]",_ldap_query); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_getmaxmailsize(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return -1; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_getmaxmailsize(): no entries found"); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_getmaxmailsize(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } _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,"auth_getmaxmailsize(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); return -1; } trace(TRACE_DEBUG,"auth_getmaxmailsize(): found something at [%s]", _ldap_dn ); ldap_memfree( _ldap_dn ); _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_maxmail ); if( _ldap_vals == NULL ) { trace (TRACE_DEBUG,"auth_getmaxmailsize(): no values found"); maxmailsize = 0; } else { maxmailsize = ( _ldap_vals[0] ) ? strtoull( _ldap_vals[0], 0, 10 ) : -1; } ldap_msgfree( _ldap_res ); ldap_value_free( _ldap_vals ); return maxmailsize; } /* * auth_getencryption() * * returns a string describing the encryption used for the passwd storage * for this user. * The string is valid until the next function call; in absence of any * encryption the string will be empty (not null). * * If the specified user does not exist an empty string will be returned. */ char *auth_getencryption(u64_t useridnr) { /* ldap does not support fancy passwords */ auth_reconnect(); return 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, j; auth_reconnect(); trace(TRACE_DEBUG,"auth_check_user(): checking for user [%s]",address); if (checks > MAX_CHECKS_DEPTH) { trace(TRACE_ERROR, "auth_check_user(): maximum checking depth reached, there probably is a loop in your alias table"); return -1; } snprintf ( _ldap_query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s))", _cfg_ldap_field_mail, address, _cfg_ldap_field_mailalt, address ); trace(TRACE_DEBUG,"auth_check_user(): searching with query [%s]",_ldap_query); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_check_user(): could not execute query [%s]", ldap_err2string( _ldap_err ) ); return -1; } /* 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 ) { 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,"auth_check_user(): adding [%s] to deliver_to address",address); return 1; } else { trace (TRACE_DEBUG,"auth_check_user(): user [%s] not in aliases table",address); return 0; } } trace (TRACE_DEBUG,"auth_check_user(): into checking loop"); if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_check_user(): none found"); return 0; } /* 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,"auth_check_user(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } /* we'll get the next entry at the _end_ of the loop! */ for ( i = 0; i < j; i++ ) { _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_cid ); // FIXME: what field is this? /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user(): checking user [%s] to [%s]",address, _ldap_vals[0]); r = auth_check_user (_ldap_vals[0], userids, (checks < 0) ? 1 : checks+1); /* remember, this is freed as soon as it's no longer needed */ ldap_value_free( _ldap_vals ); 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; /* 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,"auth_check_user(): ldap_next_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } } trace(TRACE_DEBUG,"auth_check_user(): executing query, checks [%d]", checks); /* trace(TRACE_INFO,"auth_check_user(): user [%s] has [%d] entries",address,occurences); */ ldap_msgfree( _ldap_res ); return occurences; } /* * auth_check_user_ext() * * As auth_check_user() but adds the numeric ID of the user found * to userids or the forward to the fwds. * * returns the number of occurences. */ int auth_check_user_ext(const char *address, struct list *userids, struct list *fwds, int checks) { int i, j; int occurences=0; u64_t id; char *endptr = NULL; auth_reconnect(); trace(TRACE_DEBUG,"auth_check_user_ext(): checking user [%s] in alias table",address); snprintf( _ldap_query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s)", _cfg_ldap_field_mail, address, _cfg_ldap_field_mailalt, address ); trace(TRACE_DEBUG,"auth_check_user_ext(): searching with query [%s]",_ldap_query); trace(TRACE_DEBUG,"auth_check_user_ext(): executing query, checks [%d]", checks); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_check_user_ext(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return -1; } /* 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 ( i < 1 ) { if (checks>0) { /* found the last one, this is the deliver to * but checks needs to be bigger then 0 because * else it could be the first query failure */ id = strtoull(address, &endptr, 10); if (*endptr == 0) list_nodeadd(userids, &id, sizeof(id)); /* numeric deliver-to --> this is a userid */ else list_nodeadd(fwds, address, strlen(address)+1); trace (TRACE_DEBUG,"auth_check_user_ext(): adding [%s] to deliver_to address", address); return 1; } else { trace (TRACE_DEBUG,"auth_check_user_ext(): user [%s] not in aliases table", address); return 0; } } trace (TRACE_DEBUG,"auth_check_user_ext(): into checking loop"); if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_check_user_ext(): none found"); return 0; } /* 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,"auth_check_user_ext(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } /* we'll get the next entry at the _end_ of the loop! */ for ( i = 0; i < j; i++ ) { _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_cid ); // FIXME: what field is this? /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, _ldap_vals[0]); occurences += auth_check_user_ext(_ldap_vals[0], userids, fwds, 1); ldap_value_free( _ldap_vals ); /* 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,"auth_check_user_ext(): ldap_next_entry failed: %s", ldap_err2string( _ldap_err ) ); return -1; } } trace(TRACE_DEBUG,"auth_check_user_ext(): executing query, checks [%d]", checks); /* trace(TRACE_INFO,"auth_check_user(): user [%s] has [%d] entries",address,occurences); */ ldap_msgfree( _ldap_res ); return occurences; } /* * auth_adduser() * * adds a new user to the database * and adds a INBOX * returns a useridnr on succes, -1 on failure */ u64_t auth_adduser (char *username, char *password, char *enctype, char *clientid, char *maxmail) { int i, j, ret; int NUM_MODS = 9; char *kaboom = "123"; char *cn_values[] = { username, NULL }; char *sn_values[] = { username, NULL }; char *pw_values[] = { password, NULL }; char *obj_values[] = { "top", "person", _cfg_ldap_objectclass, NULL }; char *uid_values[] = { username, NULL }; char *cid_values[] = { clientid, NULL }; char *nid_values[] = { kaboom, NULL }; char *max_values[] = { maxmail, NULL }; auth_reconnect(); /* Make the malloc for all of the pieces we're about to to sprintf into it */ _ldap_dn = (char *)my_malloc( strlen( "cn=," ) + strlen( username ) + strlen( _cfg_ldap_base_dn ) + 1 ); sprintf( _ldap_dn, "cn=%s,%s", username, _cfg_ldap_base_dn ); trace( TRACE_DEBUG, "Adding user with DN of [%s]", _ldap_dn ); /* Construct the array of LDAPMod structures representing the attributes * of the new entry. */ _ldap_mod = ( LDAPMod ** ) my_malloc( ( NUM_MODS + 1 ) * sizeof( LDAPMod * ) ); if ( _ldap_mod == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods array" ); return -1; } for ( i = 0; i < NUM_MODS; i++ ) { if ( ( _ldap_mod[ i ] = ( LDAPMod * ) my_malloc( sizeof( LDAPMod ) ) ) == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods element %d", i ); /* Free everything that did get allocated, which is (i-1) elements */ for( j = 0; j < (i-1); j++ ) my_free( _ldap_mod[j] ); my_free( _ldap_mod ); ldap_msgfree( _ldap_res ); return -1; } } i=0; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, "objectclass", obj_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = "objectclass"; _ldap_mod[i]->mod_values = obj_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, "cn", cn_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = "cn"; _ldap_mod[i]->mod_values = cn_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, "sn", cn_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = "sn"; _ldap_mod[i]->mod_values = cn_values; if( strlen( _cfg_ldap_field_passwd ) > 0 ) { i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_passwd, pw_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _cfg_ldap_field_passwd; _ldap_mod[i]->mod_values = cn_values; } i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, "mail", sn_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = "mail"; _ldap_mod[i]->mod_values = sn_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_uid, uid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _cfg_ldap_field_uid; _ldap_mod[i]->mod_values = uid_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_cid, cid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _cfg_ldap_field_cid; _ldap_mod[i]->mod_values = cid_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_maxmail, max_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _cfg_ldap_field_maxmail; _ldap_mod[i]->mod_values = max_values; /* FIXME: need to quackulate a free numeric user id number */ i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_nid, nid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _cfg_ldap_field_nid; _ldap_mod[i]->mod_values = nid_values; i++; trace( TRACE_DEBUG, "Placing a NULL to terminate the LDAPMod array at element %d", i ); _ldap_mod[i] = NULL; trace( TRACE_DEBUG, "auth_adduser(): calling ldap_add_s( _ldap_conn, _ldap_dn, _ldap_mod )" ); _ldap_err = ldap_add_s( _ldap_conn, _ldap_dn, _ldap_mod ); /* make sure to free this stuff even if we do bomb out! */ for( i = 0; i < NUM_MODS; i++ ) my_free( _ldap_mod[i] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_adduser(): could not add user: %s", ldap_err2string( _ldap_err ) ); return -1; } return strtoull( nid_values[0], 0, 0 ); } int auth_delete_user(const char *username) { auth_reconnect(); /* look up who's got that username, get their dn, and delete it! */ if ( !username ) { trace(TRACE_ERROR,"auth_get_userid(): got NULL as useridnr"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%s)", _cfg_ldap_field_uid, username ); trace(TRACE_DEBUG,"auth_delete_user(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_delete_user(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return -1; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_delete_user(): no entries found"); ldap_msgfree( _ldap_res ); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_delete_user(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return -1; } _ldap_dn = ldap_get_dn( _ldap_conn, _ldap_msg ); if ( _ldap_dn ) { trace(TRACE_DEBUG,"auth_delete_user(): deleting user at dn [%s]", _ldap_dn ); _ldap_err = ldap_delete_s( _ldap_conn, _ldap_dn ); if( _ldap_err ) { trace(TRACE_ERROR, "auth_delete_user(): could not delete dn: %s", ldap_err2string( _ldap_err ) ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } } ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return 0; } int auth_change_username(u64_t useridnr, const char *newname) { int i, j, NUM_MODS = 2; char *new_values[] = { newname, NULL }; auth_reconnect(); if ( !useridnr ) { trace(TRACE_ERROR,"auth_change_username(): got NULL as useridnr"); return 0; } if ( !newname ) { trace(TRACE_ERROR,"auth_change_username(): got NULL as newname"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_username(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_username(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return 0; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_change_username(): no entries found"); ldap_msgfree( _ldap_res ); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_change_username(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return 0; } _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,"auth_change_username(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return -1; } trace(TRACE_DEBUG,"auth_change_username(): found something at [%s]", _ldap_dn ); /* Construct the array of LDAPMod structures representing the attributes * of the new entry. */ _ldap_mod = ( LDAPMod ** ) my_malloc( ( NUM_MODS + 1 ) * sizeof( LDAPMod * ) ); if ( _ldap_mod == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods array" ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } for ( i = 0; i < NUM_MODS; i++ ) { if ( ( _ldap_mod[ i ] = ( LDAPMod * ) my_malloc( sizeof( LDAPMod ) ) ) == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods element %d", i ); /* Free everything that did get allocated, which is (i-1) elements */ for( j = 0; j < (i-1); j++ ) my_free( _ldap_mod[j] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } } i=0; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_uid, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _cfg_ldap_field_uid; _ldap_mod[i]->mod_values = new_values; i++; trace( TRACE_DEBUG, "Placing a NULL to terminate the LDAPMod array at element %d", i ); _ldap_mod[i] = NULL; trace( TRACE_DEBUG, "auth_change_username(): calling ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod )" ); _ldap_err = ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod ); /* make sure to free this stuff even if we do bomb out! */ for( i = 0; i < NUM_MODS; i++ ) my_free( _ldap_mod[i] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_username(): could not change username: %s", ldap_err2string( _ldap_err ) ); return -1; } return 1; } int auth_change_password(u64_t useridnr, const char *newpass, const char *enctype) { auth_reconnect(); return -1; } int auth_change_clientid(u64_t useridnr, u64_t newcid) { int i, j, NUM_MODS = 2; char *newcid_str[100]; char *new_values[] = { newcid_str, NULL }; auth_reconnect(); if ( !useridnr ) { trace(TRACE_ERROR,"auth_change_clientid(): got NULL as useridnr"); return 0; } if ( !newcid ) { trace(TRACE_ERROR,"auth_change_clientid(): got NULL as newcid"); return 0; } snprintf( new_values[0], 100, "%llu", newcid ); // Yeah, something like this... snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_clientid(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_clientid(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return 0; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_change_clientid(): no entries found"); ldap_msgfree( _ldap_res ); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_change_clientid(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return 0; } _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,"auth_change_clientid(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return -1; } trace(TRACE_DEBUG,"auth_change_clientid(): found something at [%s]", _ldap_dn ); /* Construct the array of LDAPMod structures representing the attributes * of the new entry. */ _ldap_mod = ( LDAPMod ** ) my_malloc( ( NUM_MODS + 1 ) * sizeof( LDAPMod * ) ); if ( _ldap_mod == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods array" ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } for ( i = 0; i < NUM_MODS; i++ ) { if ( ( _ldap_mod[ i ] = ( LDAPMod * ) my_malloc( sizeof( LDAPMod ) ) ) == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods element %d", i ); /* Free everything that did get allocated, which is (i-1) elements */ for( j = 0; j < (i-1); j++ ) my_free( _ldap_mod[j] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } } i=0; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_cid, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _cfg_ldap_field_cid; _ldap_mod[i]->mod_values = new_values; i++; trace( TRACE_DEBUG, "Placing a NULL to terminate the LDAPMod array at element %d", i ); _ldap_mod[i] = NULL; trace( TRACE_DEBUG, "auth_change_clientid(): calling ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod )" ); _ldap_err = ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod ); /* make sure to free this stuff even if we do bomb out! */ for( i = 0; i < NUM_MODS; i++ ) my_free( _ldap_mod[i] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_clientid(): could not change clientid: %s", ldap_err2string( _ldap_err ) ); return -1; } return 1; } int auth_change_mailboxsize(u64_t useridnr, u64_t newsize) { int i, j, NUM_MODS = 2; char *newsize_str[100]; char *new_values[] = { newsize_str, NULL }; auth_reconnect(); if ( !useridnr ) { trace(TRACE_ERROR,"auth_change_mailboxsize(): got NULL as useridnr"); return 0; } if ( !newsize ) { trace(TRACE_ERROR,"auth_change_mailboxsize(): got NULL as newsize"); return 0; } snprintf( new_values[0], 100, "%llu", newsize ); snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_mailboxsize(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_mailboxsize(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return 0; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_change_mailboxsize(): no entries found"); ldap_msgfree( _ldap_res ); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_change_mailboxsize(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return 0; } _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,"auth_change_mailboxsize(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); ldap_msgfree( _ldap_res ); return -1; } trace(TRACE_DEBUG,"auth_change_mailboxsize(): found something at [%s]", _ldap_dn ); /* Construct the array of LDAPMod structures representing the attributes * of the new entry. */ _ldap_mod = ( LDAPMod ** ) my_malloc( ( NUM_MODS + 1 ) * sizeof( LDAPMod * ) ); if ( _ldap_mod == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods array" ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } for ( i = 0; i < NUM_MODS; i++ ) { if ( ( _ldap_mod[ i ] = ( LDAPMod * ) my_malloc( sizeof( LDAPMod ) ) ) == NULL ) { trace( TRACE_ERROR, "Cannot allocate memory for mods element %d", i ); /* Free everything that did get allocated, which is (i-1) elements */ for( j = 0; j < (i-1); j++ ) my_free( _ldap_mod[j] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); return -1; } } i=0; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _cfg_ldap_field_maxmail, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _cfg_ldap_field_maxmail; _ldap_mod[i]->mod_values = new_values; i++; trace( TRACE_DEBUG, "Placing a NULL to terminate the LDAPMod array at element %d", i ); _ldap_mod[i] = NULL; trace( TRACE_DEBUG, "auth_change_mailboxsize(): calling ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod )" ); _ldap_err = ldap_modify_s( _ldap_conn, _ldap_dn, _ldap_mod ); /* make sure to free this stuff even if we do bomb out! */ for( i = 0; i < NUM_MODS; i++ ) my_free( _ldap_mod[i] ); my_free( _ldap_mod ); ldap_memfree( _ldap_dn ); ldap_msgfree( _ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_change_mailboxsize(): could not change mailboxsize: %s", ldap_err2string( _ldap_err ) ); return -1; } return 1; } /* * auth_validate() * * tries to validate user 'user' * * returns useridnr on OK, 0 on validation failed, -1 on error */ u64_t auth_validate (char *user, char *password) { u64_t id; int is_validated = 0; char timestr[30]; time_t td; struct tm tm; auth_reconnect(); time(&td); /* get time */ tm = *localtime(&td); /* get components */ strftime(timestr, sizeof(timestr), "%G-%m-%d %H:%M:%S", &tm); snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%s)", _cfg_ldap_field_uid, user ); trace (TRACE_DEBUG,"auth_validate(): searching with query [%s]",_ldap_query); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_validate(): could not search for user: %s", ldap_err2string( _ldap_err ) ); return -1; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) > 0 ) { _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if( _ldap_msg == NULL ) { trace(TRACE_ERROR, "auth_validate(): could not get first entry: %s", ldap_err2string( _ldap_err ) ); return -1; } } else { /* user does not exist */ trace (TRACE_DEBUG,"auth_validate(): user [%s] not found",user); return 0; } _ldap_dn = ldap_get_dn( _ldap_conn, _ldap_msg ); /* now, try to rebind as the given DN using the supplied password */ trace (TRACE_ERROR,"auth_validate(): rebinding as [%s] to validate password",_ldap_dn); _ldap_err = ldap_bind_s( _ldap_conn, _ldap_dn, password, LDAP_AUTH_SIMPLE ); ldap_memfree( _ldap_dn ); // FIXME: do we need to bind back to the dbmail "superuser" again? if( _ldap_err ) { trace(TRACE_ERROR,"auth_validate(): ldap_bind_s failed: %s", ldap_err2string( _ldap_err ) ); return 0; } else { _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_nid ); trace (TRACE_ERROR,"auth_validate(): returning numeric id [%s]",_ldap_vals[0]); id = (_ldap_vals[0]) ? strtoull(_ldap_vals[0], NULL, 10) : 0; /* FIXME: implement this in LDAP... log login in the dbase snprintf(__auth_query_data, AUTH_QUERY_SIZE, "UPDATE users SET last_login = '%s' " "WHERE user_idnr = %llu", timestr, id); if (__auth_query(__auth_query_data)==-1) trace(TRACE_ERROR, "auth_validate(): could not update user login time"); */ } ldap_msgfree( _ldap_res ); ldap_value_free( _ldap_vals ); return id; } u64_t auth_md5_validate (char *username,unsigned char *md5_apop_he, char *apop_stamp) { /* returns useridnr on OK, 0 on validation failed, -1 on error */ auth_reconnect(); return 0; } /* Given a useridnr, find the account/login name * return 0 if not found, NULL on error */ char *auth_get_userid (u64_t *useridnr) { char *returnid = NULL; auth_reconnect(); if ( !useridnr ) { trace(TRACE_ERROR,"auth_get_userid(): got NULL as useridnr"); return 0; } snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_nid, *useridnr ); trace(TRACE_DEBUG,"auth_get_userid(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _cfg_ldap_base_dn, _cfg_ldap_scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "auth_get_userid(): could not execute query: %s", ldap_err2string( _ldap_err ) ); return NULL; } if ( ldap_count_entries( _ldap_conn, _ldap_res ) < 1 ) { trace (TRACE_DEBUG,"auth_get_userid(): no entries found"); return 0; } _ldap_msg = ldap_first_entry( _ldap_conn, _ldap_res ); if ( _ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"auth_get_userid(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); 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,"auth_get_userid(): ldap_get_dn failed: %s", ldap_err2string( _ldap_err ) ); return NULL; } trace(TRACE_DEBUG,"auth_get_userid(): found something at [%s]", _ldap_dn ); ldap_memfree( _ldap_dn ); _ldap_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_uid ); if ( _ldap_vals ) { if ( !( returnid = (char *)my_malloc( strlen( _ldap_vals[0] ) + 1 ) ) ) { trace( TRACE_ERROR, "auth_get_userid(): out of memory" ); return NULL; } /* this is safe because we calculated the size three lines ago */ strcpy ( returnid, _ldap_vals[0] ); } ldap_value_free( _ldap_vals ); ldap_msgfree( _ldap_res ); return returnid; }
/* * authtest.c * * Conformance tests for authentication modules * * (c) 2002 Aaron Stone * * Procedure: * - Connect to the authentication provider * - Generate some user information (could be DEFINE'd, or rand() or whatever) * - Check if a user by this name and/or number exists (don't clobber!) * - Create a user with the information we have secured * - Get the user's information: * User ID * Client ID * Max Mail Size * Encryption Type * - Authenticate with the user data * - Change the user's information: * Password * Username * Client ID * Mailbox Size * - Authenticate again with the new user data * - Get a list of all known users: * Make sure that the test user is in there * - Delete the test user * - Get another list of all known users: * Make sure that the test user is gone * - Disconnect from the authentication provider */ #include "auth.h" #include "list.h" #include "debug.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #define MAX_CHECKS_DEPTH 1000 /* #define DBMAIL_USE_SAME_CONNECTION */ /* #define _DBAUTH_STRICT_USER_CHECK */ char *configFile = "/etc/dbmail.conf"; int TRACE_TO_SYSLOG = 1; int main() { int ret_int; char *ret_char; u64_t ret_u64_t; u64_t useridnr; char *username, *chng_username; char *password, *chng_password; char *enctype = "blah"; char *clientid = "123"; char *maxmail = "456"; struct list userlist; struct element *tmp; /* * Set up the authentication provider's connection */ printf( "Testing auth_connect()...\n" ); ret_int = auth_connect(); printf( " return value is %d\n", ret_int ); printf( "Preparing a test user account...\n" ); username = (char *)my_malloc( 16 ); password = (char *)my_malloc( 16 ); do { /* * Generate some testing data */ printf( " generating fake user data...\n" ); snprintf( username, 16, "testuser.XXXXXX" ); snprintf( password, 16, "testpass.XXXXXX" ); mktemp( username ); mktemp( password ); /* No freeing needed, we'll be dying anyhow */ /* * Make sure that the generated data is really available */ printf( "Testing auth_user_exists( \"%s\" )...\n", username ); printf( " testing fake user data...\n" ); } while( auth_user_exists( username ) != 0 ); printf( " fake data confirmed!\n" ); printf( "Testing auth_adduser( \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" )...\n", username, password, enctype, clientid, maxmail ); ret_u64_t = auth_adduser( username, password, enctype, clientid, maxmail ); if( ret_u64_t != -1 ) { useridnr = ret_u64_t; printf( " user created with useridnr %llu\n", useridnr ); } else { printf( " user was NOT created\n" ); // return 0 } printf( "Testing auth_getclientid( \"%llu\" )...\n", useridnr ); ret_u64_t = auth_getclientid( useridnr ); printf( " return value is %llu\n", ret_u64_t ); printf( "Testing auth_getmaxmailsize( \"%llu\" )...\n", useridnr ); ret_u64_t = auth_getmaxmailsize( useridnr ); printf( " return value is %llu\n", ret_u64_t ); printf( "Testing auth_getencryption( \"%llu\" )...\n", useridnr ); ret_char = auth_getencryption( useridnr ); printf( " return value is %s\n", ret_char ); if( ret_char != NULL ) /* free() doesn't like to get NULL pointers... */ free( ret_char ); printf( "Testing auth_get_userid( \"%llu\" )...\n", useridnr ); ret_char = auth_get_userid( &useridnr ); printf( " return value is %s\n", ret_char ); if( ret_char != NULL ) /* free() doesn't like to get NULL pointers... */ free( ret_char ); /* print a list of all known users */ printf( "Testing auth_get_known_users( &userlist )...\n" ); ret_int = auth_get_known_users( &userlist ); printf( " return value is %d\n", ret_int ); printf( " here's the list of users:\n" ); tmp = list_getstart(&userlist); while (tmp) { printf(" [%s]", (char *)tmp->data); if( strcmp( (char *)tmp->data, username) == 0 ) printf(" --- test user found!\n" ); else printf("\n"); tmp = tmp->nextnode; } if (userlist.start) list_freelist(&userlist.start); printf( " done with listing users.\n" ); printf( "Testing auth_validate( \"%s\", \"%s\")...\n", username, password ); ret_u64_t = auth_validate( username, password ); printf( " return value is %llu\n", ret_u64_t ); printf( "Preparing a change user account...\n" ); chng_username = (char *)my_malloc( 16 ); chng_password = (char *)my_malloc( 16 ); do { /* * Generate some testing data */ printf( " generating fake user data...\n" ); snprintf( chng_username, 16, "chnguser.XXXXXX" ); snprintf( chng_password, 16, "chngpass.XXXXXX" ); mktemp( chng_username ); mktemp( chng_password ); /* No freeing needed, we'll be dying anyhow */ /* * Make sure that the generated data is really available */ printf( "Testing auth_user_exists( \"%s\" )...\n", chng_username ); printf( " testing fake user data...\n" ); } while( auth_user_exists( chng_username ) != 0 ); printf( " fake data confirmed!\n" ); /* let's change up the values, and test it all again */ printf( "Testing auth_change_username( \"%llu\", \"%s\" )...\n", useridnr, chng_username ); ret_int = auth_change_username( useridnr, chng_username ); printf( " return value is %d\n", ret_int ); /* let's change up the values, and test it all again */ printf( "Testing auth_change_password( \"%llu\", \"%s\", \"%s\" )...\n", useridnr, chng_password, enctype ); ret_int = auth_change_password( useridnr, chng_password, enctype ); printf( " return value is %d\n", ret_int ); /* let's change up the values, and test it all again */ printf( "Testing auth_change_clientid( \"%llu\", \"%llu\" )...\n", useridnr, strtoull( clientid, 0, 0 ) ); ret_int = auth_change_clientid( useridnr, strtoull( clientid, 0, 0 ) ); printf( " return value is %d\n", ret_int ); /* let's change up the values, and test it all again */ printf( "Testing auth_change_mailboxsize( \"%llu\", \"%llu\" )...\n", useridnr, strtoull( maxmail, 0, 0 ) ); ret_int = auth_change_mailboxsize( useridnr, strtoull( maxmail, 0, 0 ) ); printf( " return value is %d\n", ret_int ); /* print a list of all known users */ printf( "Testing auth_get_known_users( &userlist )...\n" ); ret_int = auth_get_known_users( &userlist ); printf( " return value is %d\n", ret_int ); printf( " here's the list of users:\n" ); tmp = list_getstart(&userlist); while (tmp) { printf(" [%s]", (char *)tmp->data); if( strcmp( (char *)tmp->data, chng_username) == 0 ) printf(" --- test user found!\n" ); else printf("\n"); tmp = tmp->nextnode; } if (userlist.start) list_freelist(&userlist.start); printf( " done with listing users.\n" ); printf( "Testing auth_validate( \"%s\", \"%s\")...\n", chng_username, chng_password ); ret_u64_t = auth_validate( chng_username, chng_password ); printf( " return value is %llu\n", ret_u64_t ); /* delete the test user */ printf( "Testing auth_delete_user( %s )...\n", username ); ret_int = auth_delete_user( username ); printf( " return value is %d\n", ret_int ); /* delete the test user */ printf( "Testing auth_delete_user( %s )...\n", chng_username ); ret_int = auth_delete_user( chng_username ); printf( " return value is %d\n", ret_int ); /* disconnect from the authentication service */ printf( "Testing auth_disconnect()...\n" ); ret_int = auth_disconnect(); printf( " return value is %d\n", ret_int ); return 0; } void trace (int level, char *formatstring, ...) { va_list argp; va_start(argp, formatstring); fprintf (stdout, " "); /* put some initial spacing */ vfprintf (stdout, formatstring, argp); if (formatstring[strlen(formatstring)]!='\n') fprintf (stdout,"\n"); va_end(argp); } void configure_debug(int level, int trace_syslog, int trace_verbose) { /* do nothing */ } /* int auth_check_user (const char *username, struct list *userids, int checks); int auth_check_user_ext(const char *username, struct list *userids, struct list *fwds, int checks); u64_t auth_validate (char *user, char *password); u64_t auth_md5_validate (char *username,unsigned char *md5_apop_he, char *apop_stamp); */