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