Here we are with the fifth installment of the LDAP authentication module.
Everything is now implemented except for the change_password routine
because that needs a lot more work.
This version also has no apparent memory leaks, checked with the excellent
ccmalloc tool, http://www.inf.ethz.ch/personal/biere/projects/ccmalloc/
At this point, I'd like to ask the IC&S folks to include authldap.c with
the dbmail distribution. Please let me know the status of getting into the
next release, either a point release or a minor version bump.
As for my discussion of the aliases table, for now I'm not worrying about
it. The auth_check_user routine actually take an email address as
an argument (desprite the function and the variable both calling it a
'username'... and so that works to find the user by their 'aliases' in the
ldap (the FIELD_MAIL and FIELD_MAILALT, equally). Additionally, the
aliases are only tied to a specific user if the deliver_to field is
numeric. If it is not, then the alias is pointing to an outside address or
to a program. I'm not sure if these should go into the directory, or stay
in the database... if anybody cares, we should start a thread on my
previous mailings and figure out a good way to handle this!
Here's the necessary config file section, just drop it into
/etc/dbmail.conf and customize as needed (this one works with the
qmail-ldap patch, at http://nrg4u.com):
[LDAP]
BASE_DN=ou=Users,dc=Acme,dc=Com
BIND_DN=cn=Manager,dc=Acme,dc=Com
BIND_PW=secret
SCOPE=SubTree
PORT=389
HOSTNAME=localhost
OBJECTCLASS=qmailuser
FIELD_UID=uid
FIELD_CID=qmailgid
FIELD_NID=qmailuid
FIELD_MAIL=mail
FIELD_MAILALT=mailalternateaddress
FIELD_QUOTA=mailquota
Aaron
/*
* 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( "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" );
/* 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);
*/
/*
* 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);
*/