Here's another installment of the authldap module. This time, the
functions which have been implemented are actually mostly working ;-)
I'm also including authtest, which is my verification code. It's not quite
done yet, but has been very useful for testing the authentication module
on a function-by-function basis. Test users now welcome with this code!

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;
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;
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("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);

}


/*
 * auth_connect()
 *
 * initializes the connection for authentication.
 * 
 * returns 0 on success, -1 on failure
 */
int auth_connect()
{
  _get_ldap_config();

  trace(TRACE_DEBUG, "auth_connect(): 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_connect(): 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_connect(): ldap_bind_s failed: %s",
            ldap_err2string( _ldap_err ) );
      return -1;
    }

  trace(TRACE_DEBUG, "auth_connect(): successfully bound to ldap server");
  return 0;
}


int auth_disconnect()
{
  ldap_unbind( _ldap_conn );
  return 0;
}


u64_t auth_user_exists(const char *username)
{
  u64_t id;

  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;
    }

  _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 ) );
      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;

  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_vals == 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;

  if (!useridnr)
    {
      trace(TRACE_ERROR,"auth_getclientid(): got NULL as useridnr");
      return 0;
    }

  snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_cid, 
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(): user has no clientid?");
      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_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_cid );
  cid = ( _ldap_vals[0] ) ? strtoull( _ldap_vals[0], 0, 0 ) : 0;

  ldap_msgfree( _ldap_res );
  ldap_value_free( _ldap_vals );

  return cid;
}


u64_t auth_getmaxmailsize(u64_t useridnr)
{
  u64_t maxmailsize;

  if (!useridnr)
    {
      trace(TRACE_ERROR,"auth_getmaxmailsize(): got NULL as useridnr");
      return 0;
    }

  snprintf( _ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)", _cfg_ldap_field_maxmail, 
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_getmaxmailsizeid(): user has no maxmailsize?");
      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_vals = ldap_get_values( _ldap_conn, _ldap_msg, _cfg_ldap_field_cid );
  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 */
  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;
  
  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");

  /* 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;

  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");

  /* 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)
{
  return -1;
}


int auth_delete_user(const char *username)
{
  return -1;
}
  
int auth_change_username(u64_t useridnr, const char *newname)
{
  return -1;
}


int auth_change_password(u64_t useridnr, const char *newpass, const char 
*enctype)
{
  return -1;
}


int auth_change_clientid(u64_t useridnr, u64_t newcid)
{
  return -1;
}

int auth_change_mailboxsize(u64_t useridnr, u64_t newsize)
{
  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;

  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 */
  
  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;
  
  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(): user has no username?");
      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_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 = "";
        char *password = "";
        char *enctype = "";
        char *clientid = "";
        char *maxmail = "";

        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" );
        do
        {
                printf( "   generating fake user data...\n" );

                /*
                 * Generate some testing data
                 */
                /*
                 * Make sure that the generated data is really available
                 */
                printf( "Testing auth_user_exists( \"fake data\" )...\n" );
                printf( "   testing fake user data...\n" );
        } while( !auth_user_exists( "bdole" ) ); // FIXME: make this part 
actually be fake...
        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]\n", (char*)tmp->data);
                tmp = tmp->nextnode;
        }

        if (userlist.start)
                list_freelist(&userlist.start);
        printf( "   done with listing users.\n" );

        /* 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);

int auth_delete_user(const char *username);

int auth_change_username(u64_t useridnr, const char *newname);
int auth_change_password(u64_t useridnr, const char *newpass, const char 
*enctype);
int auth_change_clientid(u64_t useridnr, u64_t newcid);
int auth_change_mailboxsize(u64_t useridnr, u64_t newsize);

u64_t auth_validate (char *user, char *password);
u64_t auth_md5_validate (char *username,unsigned char *md5_apop_he, char 
*apop_stamp);
*/

Reply via email to