Or perhaps a few hours later ;-) There's still a major todo left, and that's that I wrote the auth_check_user_ext() function to work really well and nice, but forgot to take care of auth_check_user(). At this point, I don't understand the difference, except that one is used by injector.c and the other in pipe.c, respectively. Is the list returned by auth_check_user() really just the two lists, userids and forwards, from auth_check_user_ext() concatenated?
If that's the case, let's just delete the auth_check_user() function and rewrite pipe.c to use _ext()... or to be lazy, do this: int auth_check_user( const char *address, struct list *userids, int checks ) { int occurences=0; int c1, c2 } int count1, count2; struct list templist1, templist2; struct element *tempelem1, *tempelem2; char tempchar[AUTH_QUERY_SIZE]; list_init( templist1 ); list_init( templist2 ); occurences = auth_check_user_ext( address, templist1, templist2, checks ); tempelem1 = list_getstart( templist1 ); count1 = templist1.total_nodes; for( c1 = 0; c1 < count1; c1++ ) { /* _ext() gives us a list of numeric user ids, so convert to char */ snprintf( tempchar, AUTH_QUERY_SIZE, "%llu", tempelem1->data ); list_nodeadd( userids, tempchar ); tempelem1 = tempelem1->nextnode; } tempelem2 = list_getstart( templist2 ); count2 = templist2.total_nodes; for( c2 = 0; c2 < count2; c2++ ) { list_nodeadd( userids, tempelem2->data ); tempelem2 = tempelem2->nextnode; } tempelem2 = list_getstart( templist2 ); } Aaron On Sun, 30 Mar 2003, Aaron Stone wrote: count2 = templist2.total_nodes;> Just finished a full rewrite, actually ;-) so the ldap sections are for( c2 = 0; c2 < count2; c2++ )> now internally abstracted and a few extra config options specifically with {> drop-in Exchange replacement in mind... now supported are external list_nodeadd( userids, tempelem2->data );> forwards through a Contact, and distribution groups (naturally, it's tempelem2 = tempelem2->nextnode;> recursive to allow a member of a I'm busy right now cleaning up all of the printf()'s I stuck everywhere. > Most will become trace(DEBUG) but a few were just to see the program flow. > There's also a 12 byte leak in auth_adduser, but I can't figure out what's > happening there; I've tried free()'ing everything in sight, but only get > segfaults :-( I guess the good news is that the daemons never call > auth_adduser() so it's practically a moot point. > > Thanks for asking, btw! I'll post the new version in a few days! > > Aaron > > > On 27 Mar 2003, Ryan Butler wrote: > > > On Thu, 2003-03-27 at 04:27, Roel Rozendaal - IC&S wrote: > > > Hi all, > > > > > > i regret to admit that i have lost pretty much track of the LDAP auth > > > system :$ > > > > > > What's the status? Is it ready to be included in cvs? > > > > > > regards roel > > > > > > > > > ______ > > > > I think it is/was ready to be committed and once its in there, Myself > > and/or Jesse need to update autoconf to work with it. > > > > > > Ryan > > > > > > _______________________________________________ > > Dbmail-dev mailing list > > Dbmail-dev@dbmail.org > > http://twister.fastxs.net/mailman/listinfo/dbmail-dev > > > > _______________________________________________ > Dbmail-dev mailing list > Dbmail-dev@dbmail.org > http://twister.fastxs.net/mailman/listinfo/dbmail-dev >
/* * $Id: authldap.c $ * (c) 2002 Aaron Stone, [EMAIL PROTECTED] * User authentication functions for LDAP. */ #include "auth.h" #include "dbmail.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]; typedef struct _ldap_cfg { field_t bind_dn, bind_pw, base_dn, port, scope, hostname, objectclass; field_t field_uid, field_cid, field_nid, field_mail, field_mailalt, mailaltprefix, field_maxmail, field_passwd, field_fwd, field_fwdsave, field_fwdtarget, fwdtargetprefix, field_members; int scope_int, port_int; } _ldap_cfg_t; _ldap_cfg_t _ldap_cfg; /* Define a macro to cut down on code duplication... */ #define GETCONFIGVALUE( func, list, val, var ) \ GetConfigValue(val, list, var); \ if (strlen(var) == 0) \ trace(TRACE_DEBUG, #func ": no value for " #val " in config file"); \ trace(TRACE_DEBUG, #func ": value for " #val " stored in " #var " as [%s]", var) /* that's correct, no final ; so when the macro is called, it looks "normal" */ static void __auth_get_config() { struct list ldapItems; ReadConfig("LDAP", configFile, &ldapItems); SetTraceLevel(&ldapItems); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "BIND_DN", _ldap_cfg.bind_dn ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "BIND_PW", _ldap_cfg.bind_pw ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "BASE_DN", _ldap_cfg.base_dn ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "PORT", _ldap_cfg.port ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "HOSTNAME", _ldap_cfg.hostname ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "OBJECTCLASS", _ldap_cfg.objectclass ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_UID", _ldap_cfg.field_uid ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_CID", _ldap_cfg.field_cid ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_NID", _ldap_cfg.field_nid ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_MAIL", _ldap_cfg.field_mail ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_MAILALT",_ldap_cfg.field_mailalt); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "MAILALTPREFIX",_ldap_cfg.mailaltprefix); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_QUOTA", _ldap_cfg.field_maxmail); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_PASSWD", _ldap_cfg.field_passwd); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_FORWARD", _ldap_cfg.field_fwd ); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_FWDSAVE", _ldap_cfg.field_fwdsave); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_FWDTARGET", _ldap_cfg.field_fwdtarget); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FWDTARGETPREFIX", _ldap_cfg.fwdtargetprefix); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "FIELD_MEMBERS", _ldap_cfg.field_members); GETCONFIGVALUE(__auth_get_config(), &ldapItems, "SCOPE", _ldap_cfg.scope ); /* Store the port as an integer for later use. */ _ldap_cfg.port_int = atoi( _ldap_cfg.port ); /* Compare the input string with the possible options, * making sure not to exceeed the length of the given string */ { int len = ( strlen( _ldap_cfg.scope ) < 3 ? strlen( _ldap_cfg.scope ) : 3 ); if( strncasecmp( _ldap_cfg.scope, "one", len ) == 0 ) _ldap_cfg.scope_int = LDAP_SCOPE_ONELEVEL; else if( strncasecmp( _ldap_cfg.scope, "bas", len ) == 0 ) _ldap_cfg.scope_int = LDAP_SCOPE_BASE; else if( strncasecmp( _ldap_cfg.scope, "sub", len ) == 0 ) _ldap_cfg.scope_int = LDAP_SCOPE_SUBTREE; else _ldap_cfg.scope_int = LDAP_SCOPE_SUBTREE; } trace(TRACE_DEBUG, "__auth_get_config(): integer ldap scope is [%d]", _ldap_cfg.scope_int); list_freelist( &ldapItems.start ); } /* * auth_connect() * * initializes the connection for authentication. * * returns 0 on success, -1 on failure */ int auth_connect() { __auth_get_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] : [%d]", _ldap_cfg.hostname, _ldap_cfg.port_int ); _ldap_conn = ldap_init( _ldap_cfg.hostname, _ldap_cfg.port_int ); trace(TRACE_DEBUG, "auth_reconnect(): binding to ldap server as [%s] / [%s]", _ldap_cfg.bind_dn, _ldap_cfg.bind_pw ); _ldap_err = ldap_bind_s( _ldap_conn, _ldap_cfg.bind_dn, _ldap_cfg.bind_pw, LDAP_AUTH_SIMPLE ); if( _ldap_err ) { trace(TRACE_ERROR,"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; } int __auth_add(const char *q) { LDAP *__ldap_conn; LDAPMod **__ldap_mod; LDAPMessage *__ldap_res; LDAPMessage *__ldap_msg; int __ldap_err; int __ldap_attrsonly = 0; char *__ldap_dn; char **__ldap_vals; char **__ldap_attrs = NULL; char __ldap_query[AUTH_QUERY_SIZE]; if (!q) { trace(TRACE_ERROR, "__auth_query(): got NULL query"); return 0; } } /* * The list that goes into retlist is really big and scary. * Here's how it works... * * Each node of retlist contains a data field * which is a pointer to another list, "fieldlist". * * Each node of fieldlist contains a data field * which is a pointer to another list, "datalist". * * Each node of datalist contains a data field * which is a (char *) pointer to some actual data. * * Here's a visualization: * * retlist * has the "rows" that matched * { * (struct list *)data * has the fields you requested * { * (struct list *)data * has the values for the field * { * (char *)data * (char *)data * (char *)data * } * } * } * * */ /* returns the number of matches found */ int __auth_get_one_entry(const char *q, char **retfields, struct list *retlist) { LDAPMessage *ldap_res; LDAPMessage *ldap_msg; int ldap_err; int ldap_attrsonly = 0; char *ldap_dn; char **ldap_vals; char **ldap_attrs = NULL; char ldap_query[AUTH_QUERY_SIZE]; int i = 0, j = 0, k = 0, m = 0; struct list fieldlist, datalist; if (!q) { trace(TRACE_ERROR, "__auth_get_one_entry(): got NULL query"); goto endnofree; } auth_reconnect(); snprintf( ldap_query, AUTH_QUERY_SIZE, q ); trace(TRACE_DEBUG, "__auth_get_one_entry(): retrieving entry for DN [%s]", ldap_query ); ldap_err = ldap_search_s( _ldap_conn, ldap_query, LDAP_SCOPE_BASE, "(objectClass=*)", ldap_attrs, ldap_attrsonly, &ldap_res ); if ( ldap_err ) { trace(TRACE_ERROR, "__auth_get_one_entry(): could not retrieve DN: %s", ldap_err2string( ldap_err ) ); goto endnofree; } /* we're just using a little counter variable, * since we'll use it in the for loop later */ j = ldap_count_entries( _ldap_conn, ldap_res ); if ( j < 1 ) { trace (TRACE_DEBUG,"__auth_get_one_entry(): none found"); goto endnofree; } /* do the first entry here */ ldap_msg = ldap_first_entry( _ldap_conn, ldap_res ); if ( ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"__auth_get_one_entry(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); goto endnofree; } list_init( retlist ); /* we'll get the next entry at the _end_ of the loop! */ /* get the entries to populate retlist */ for ( i = 0; i < j; i++ ) { /* init this list for the field values */ list_init( &fieldlist ); /* get the fields to populate fieldlist */ for ( k = 0; retfields[k] != NULL; k++ ) { /* init this list for the data values */ list_init( &datalist ); /* get the values to populate datalist */ ldap_vals = ldap_get_values( _ldap_conn, ldap_msg, retfields[k] ); if ( ldap_vals == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &ldap_err); trace(TRACE_ERROR,"__auth_get_one_entry(): ldap_get_values failed: %s", ldap_err2string( ldap_err ) ); /* no need to break, because we WANT the list to contain an entry * for each attribute, even if it is simply the freshly-initialized * list, which has no nodes -- that's just fine by us and our consumers break; */ } else { for ( m = 0; ldap_vals[m] != NULL; m++ ) { /* add the value to the list */ if ( !list_nodeadd( &datalist, ldap_vals[m], strlen( ldap_vals[m] ) + 1 ) ) { trace(TRACE_ERROR, "__auth_get_one_entry: could not add ldap_vals to &datalist" ); list_freelist( &datalist.start ); break; } } } /* add the value to the list */ if ( !list_nodeadd( &fieldlist, &datalist, sizeof( struct list ) ) ) { trace(TRACE_ERROR, "__auth_get_one_entry(): could not add &datalist to &fieldlist" ); list_freelist( &fieldlist.start ); break; } /* free the values as we use them */ ldap_value_free( ldap_vals ); } /* add the value to the list */ if ( !list_nodeadd( retlist, &fieldlist, sizeof( struct list ) ) ) { trace(TRACE_ERROR, "__auth_get_one_entry(): could not add &fieldlist to retlist" ); list_freelist( &retlist->start ); goto endfree; } /* do the next entry here */ ldap_msg = ldap_next_entry( _ldap_conn, ldap_msg ); if ( ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &ldap_err); trace(TRACE_ERROR,"__auth_get_one_entry(): ldap_next_entry failed: %s", ldap_err2string( ldap_err ) ); //goto endfree; break; } } endfree: if( ldap_res ) ldap_msgfree( ldap_res ); endnofree: return j; /* remember, j = ldap_count_entries() */ } /* returns the number of matches found */ int __auth_get_every_match(const char *q, char **retfields, struct list *retlist) { 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]; int i = 0, j = 0, k = 0, m = 0; struct list fieldlist, datalist; if (!q) { trace(TRACE_ERROR, "__auth_get_every_match(): got NULL query"); goto endnofree; } auth_reconnect(); snprintf( ldap_query, AUTH_QUERY_SIZE, q ); trace(TRACE_DEBUG, "__auth_get_every_match(): searching with query [%s]", ldap_query ); ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, ldap_query, ldap_attrs, ldap_attrsonly, &ldap_res ); if ( ldap_err ) { trace(TRACE_ERROR, "__auth_get_every_match(): could not execute query: %s", ldap_err2string( ldap_err ) ); if( ldap_res != NULL ) ldap_msgfree( ldap_res ); goto endnofree; } /* we're just using a little counter variable, * since we'll use it in the for loop later */ j = ldap_count_entries( _ldap_conn, ldap_res ); if ( j < 1 ) { trace (TRACE_DEBUG,"__auth_get_every_match(): none found"); if( ldap_res != NULL ) ldap_msgfree( ldap_res ); goto endnofree; } /* do the first entry here */ ldap_msg = ldap_first_entry( _ldap_conn, ldap_res ); if ( ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &_ldap_err); trace(TRACE_ERROR,"__auth_get_every_match(): ldap_first_entry failed: %s", ldap_err2string( _ldap_err ) ); if( ldap_res != NULL ) ldap_msgfree( ldap_res ); goto endnofree; } list_init( retlist ); /* we'll get the next entry at the _end_ of the loop! */ /* get the entries to populate retlist */ for ( i = 0; i < j; i++ ) { /* init this list for the field values */ list_init( &fieldlist ); /* get the fields to populate fieldlist */ for ( k = 0; retfields[k] != NULL; k++ ) { /* init this list for the data values */ list_init( &datalist ); /* get the values to populate datalist */ ldap_vals = ldap_get_values( _ldap_conn, ldap_msg, retfields[k] ); if ( ldap_vals == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &ldap_err); trace(TRACE_ERROR,"__auth_get_every_match(): ldap_get_values failed: %s", ldap_err2string( ldap_err ) ); /* no need to break, because we WANT the list to contain an entry * for each attribute, even if it is simply the freshly-initialized * list, which has no nodes -- that's just fine by us and our consumers break; */ } else { for ( m = 0; ldap_vals[m] != NULL; m++ ) { /* add the value to the list */ if ( !list_nodeadd( &datalist, ldap_vals[m], strlen( ldap_vals[m] ) + 1 ) ) { trace(TRACE_ERROR, "__auth_get_every_match: could not add ldap_vals to &datalist" ); list_freelist( &datalist.start ); break; } } } /* add the value to the list */ if ( !list_nodeadd( &fieldlist, &datalist, sizeof( struct list ) ) ) { trace(TRACE_ERROR, "__auth_get_every_match(): could not add &datalist to &fieldlist" ); list_freelist( &fieldlist.start ); break; } /* free the values as we use them */ ldap_value_free( ldap_vals ); } /* add the value to the list */ if ( !list_nodeadd( retlist, &fieldlist, sizeof( struct list ) ) ) { trace(TRACE_ERROR, "__auth_get_every_match(): could not add &fieldlist to retlist" ); list_freelist( &retlist->start ); goto endfree; } /* do the next entry here */ ldap_msg = ldap_next_entry( _ldap_conn, ldap_msg ); if ( ldap_msg == NULL ) { ldap_get_option(_ldap_conn, LDAP_OPT_ERROR_NUMBER, &ldap_err); trace(TRACE_ERROR,"__auth_get_every_match(): ldap_next_entry failed: %s", ldap_err2string( ldap_err ) ); //goto endfree; break; } } endfree: if( ldap_res ) ldap_msgfree( ldap_res ); if( ldap_msg ) ldap_msgfree( ldap_msg ); endnofree: return j; /* remember, j = ldap_count_entries() */ } char *__auth_get_first_match(const char *q, char **retfields) { LDAPMessage *ldap_res; LDAPMessage *ldap_msg; int ldap_err; int ldap_attrsonly = 0; char *ldap_dn = NULL; char **ldap_vals = NULL; char **ldap_attrs = NULL; char ldap_query[AUTH_QUERY_SIZE]; int k = 0; char *returnid = NULL; if (!q) { trace(TRACE_ERROR, "__auth_get_first_match(): got NULL query"); goto endnofree; } auth_reconnect(); snprintf( ldap_query, AUTH_QUERY_SIZE, q ); trace(TRACE_DEBUG, "__auth_get_first_match(): searching with query [%s]", ldap_query ); ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, ldap_query, ldap_attrs, ldap_attrsonly, &ldap_res ); if ( ldap_err ) { trace(TRACE_ERROR, "__auth_get_first_match(): could not execute query: %s", ldap_err2string( ldap_err ) ); goto endfree; } if ( ldap_count_entries( _ldap_conn, ldap_res ) < 1 ) { trace (TRACE_DEBUG,"__auth_get_first_match(): none found"); goto endfree; } 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_first_match(): ldap_first_entry failed: %s", ldap_err2string( ldap_err ) ); goto endfree; } for ( k = 0; retfields[k] != NULL; k++ ) { ldap_vals = ldap_get_values( _ldap_conn, ldap_msg, retfields[k] ); //FIXME: something about collecting up the values... if( 0 == strcasecmp( retfields[k], "dn" ) ) { ldap_dn = ldap_get_dn( _ldap_conn, ldap_msg ); if ( ldap_dn ) { if ( !( returnid = (char *)my_malloc( strlen( ldap_dn ) + 1 ) ) ) { trace( TRACE_ERROR, "__auth_get_first_match(): out of memory" ); goto endfree; } /* this is safe because we calculated the size three lines ago */ strcpy( returnid, ldap_dn ); } } else { ldap_vals = ldap_get_values( _ldap_conn, ldap_msg, retfields[k] ); if ( ldap_vals ) { if ( !( returnid = (char *)my_malloc( strlen( ldap_vals[0] ) + 1 ) ) ) { trace( TRACE_ERROR, "__auth_get_first_match(): out of memory" ); goto endfree; } /* this is safe because we calculated the size three lines ago */ strcpy( returnid, ldap_vals[0] ); } } } endfree: if( !(NULL == ldap_dn) ) ldap_memfree( ldap_dn ); if( !(NULL == ldap_vals) ) ldap_value_free( ldap_vals ); // if( !((LDAPMessage *)0 == ldap_res) ) ldap_msgfree( ldap_res ); if( !((LDAPMessage *)0 == ldap_res) ) ldap_msgfree( ldap_res ); endnofree: return returnid; } u64_t auth_user_exists(const char *username) { u64_t id; char *id_char; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_nid, NULL }; if (!username) { trace(TRACE_ERROR,"auth_user_exists(): got NULL as username"); return 0; } snprintf( query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid, username ); id_char = __auth_get_first_match( query, fields ); id = ( id_char ) ? strtoull( id_char, NULL, 0 ) : 0; trace(TRACE_DEBUG, "auth_user_exists(): returned value is [%llu]", id ); if( id_char ) free( id_char ); return id; } /* 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; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_uid, NULL }; if (!useridnr) { trace(TRACE_ERROR,"auth_get_userid(): got NULL as useridnr"); return 0; } snprintf( query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid, *useridnr ); returnid = __auth_get_first_match( query, fields ); trace(TRACE_DEBUG, "auth_getuserid(): returned value is [%s]", returnid ); return returnid; } /* * 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; char *cid_char = NULL; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_cid, NULL }; if (!useridnr) { trace(TRACE_ERROR,"auth_getclientid(): got NULL as useridnr"); return 0; } snprintf( query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid, useridnr ); cid_char = __auth_get_first_match( query, fields ); cid = ( cid_char ) ? strtoull( cid_char, NULL, 0 ) : 0; trace(TRACE_DEBUG, "auth_getclientid(): returned value is [%llu]", cid ); if( cid_char ) free( cid_char ); return cid; } u64_t auth_getmaxmailsize(u64_t useridnr) { u64_t max; char *max_char; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_cid, NULL }; if (!useridnr) { trace(TRACE_ERROR,"auth_getmaxmailsize(): got NULL as useridnr"); return 0; } snprintf( query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid, useridnr ); max_char = __auth_get_first_match( query, fields ); max = ( max_char ) ? strtoull( max_char, 0, 10 ) : 0; trace(TRACE_DEBUG, "auth_getmaxmailsize(): returned value is [%llu]", max ); if( max_char ) free( max_char ); return max; } /* * 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; } /* Fills the users list with all existing users * return -2 on mem error, -1 on db-error, 0 on success */ int auth_get_known_users(struct list *users) { u64_t known, curr; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_uid, NULL }; struct list templist; struct element *tempelem1, *tempelem2, *tempelem3; if (!users) { trace(TRACE_ERROR,"auth_get_known_users(): got a NULL pointer as argument"); return -2; } list_init(users); snprintf( query, AUTH_QUERY_SIZE, "(objectClass=%s)", _ldap_cfg.objectclass ); known = __auth_get_every_match( query, fields, &templist ); trace(TRACE_ERROR,"auth_get_known_users(): found %llu users", known ); /* do the first entry here */ tempelem1 = list_getstart( &templist ); /* we'll get the next entry at the _end_ of the loop! */ while( tempelem1 != NULL ) { tempelem2 = list_getstart( (struct list *)tempelem1->data ); while( tempelem2 != NULL ) { tempelem3 = list_getstart( (struct list *)tempelem2->data ); while( tempelem3 != NULL ) { list_nodeadd( users, (char *)tempelem3->data, strlen( (char *)tempelem3->data ) + 1 ); tempelem3 = tempelem3->nextnode; } tempelem2 = tempelem2->nextnode; } tempelem1 = tempelem1->nextnode; } /* pass through any error from __auth_get_every_match() */ return ( known < 0 ? known : 0 ); } /* recursive function, should be called with checks == -1 from main routine */ int auth_check_user (const char *address, struct list *userids, int checks) { int occurences=0, r; int i, j; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_nid, NULL }; int c1, c2, c3; int count1, count2, count3; struct list templist; struct element *tempelem1, *tempelem2, *tempelem3; trace(TRACE_DEBUG,"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; } list_init( &templist ); snprintf ( query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s%s))", _ldap_cfg.field_mail, address, _ldap_cfg.field_mailalt, _ldap_cfg.mailaltprefix, address ); /* we're just using a little counter variable, since we'll use it in the for loop later */ j = __auth_get_every_match( query, fields, &templist ); if ( j < 1 ) { if ( checks > 0 ) { /* found the last one, this is the deliver to * but checks needs to be bigger then 0 because * else it could be the first query failure */ list_nodeadd( userids, address, strlen( address ) + 1 ); trace (TRACE_DEBUG,"auth_check_user(): adding [%s] to deliver_to address",address); list_freelist( &templist.start ); return 1; } else { trace (TRACE_DEBUG,"auth_check_user(): user [%s] not in aliases table",address); list_freelist( &templist.start ); return 0; } } /* do the first entry here */ tempelem1 = list_getstart( &templist ); count1 = templist.total_nodes; for( c1 = 0; c1 < count1; c1++ ) { tempelem2 = list_getstart( (struct list *)tempelem1->data ); count2 = ((struct list *)tempelem1->data)->total_nodes; for( c2 = 0; c2 < count2; c2++ ) { tempelem3 = list_getstart( (struct list *)tempelem2->data ); count3= ((struct list *)tempelem2->data)->total_nodes; for( c3 = 0; c3 < count3; c3++ ) { // here begins the meat /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user(): checking user [%s] to [%s]",address, (char *)tempelem3->data); r = auth_check_user ((char *)tempelem3->data, userids, (checks < 0) ? 1 : checks+1); if (r < 0) { /* loop detected */ if (checks > 0) return -1; /* still in recursive call */ if (userids->start) { list_freelist(&userids->start); userids->total_nodes = 0; } return 0; /* report to calling routine: no results */ } occurences += r; // here ends the meat tempelem3 = tempelem3->nextnode; } list_freelist( &((struct list *)tempelem2->data)->start ); tempelem2 = tempelem2->nextnode; } list_freelist( &((struct list *)tempelem1->data)->start ); tempelem1 = tempelem1->nextnode; } list_freelist( &templist.start ); trace(TRACE_DEBUG,"auth_check_user(): executing query, checks [%d]", checks); /* trace(TRACE_INFO,"auth_check_user(): user [%s] has [%d] entries",address,occurences); */ 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; char query[AUTH_QUERY_SIZE]; char *fields[] = { _ldap_cfg.field_nid, _ldap_cfg.field_members, _ldap_cfg.field_fwd, _ldap_cfg.field_fwdsave, _ldap_cfg.field_fwdtarget, NULL }; int c1, c2, c3; int count1, count2, count3; struct list templist; struct element *tempelem1, *tempelem2, *tempelem3; trace(TRACE_DEBUG,"auth_check_user_ext(): checking user [%s] in alias table",address); /* This is my private line for sending a DN rather than a search */ if( checks < -1 ) { snprintf( query, AUTH_QUERY_SIZE, "%s", address ); j = __auth_get_one_entry( query, fields, &templist ); } else { snprintf( query, AUTH_QUERY_SIZE, "(|(%s=%s)(%s=%s%s))", _ldap_cfg.field_mail, address, _ldap_cfg.field_mailalt, _ldap_cfg.mailaltprefix, address ); /* we're just using a little counter variable, * since we'll use it in the for loop later */ j = __auth_get_every_match( query, fields, &templist ); } trace(TRACE_DEBUG,"auth_check_user_ext(): searching with query [%s]",query); trace(TRACE_DEBUG,"auth_check_user_ext(): executing query, checks [%d]", checks); 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 */ id = strtoull(address, &endptr, 10); if (*endptr == 0) { /* numeric deliver-to --> this is a userid */ list_nodeadd(userids, &id, sizeof(id)); } else { list_nodeadd(fwds, address, strlen(address)+1); free( endptr ); } trace (TRACE_DEBUG,"auth_check_user_ext(): adding [%s] to deliver_to address", address); list_freelist( &templist.start ); return 1; } else { trace (TRACE_DEBUG,"auth_check_user_ext(): user [%s] not in aliases table", address); list_freelist( &templist.start ); return 0; } } trace (TRACE_DEBUG,"auth_check_user_ext(): into checking loop"); /* do the first entry here */ tempelem1 = list_getstart( &templist ); count1 = templist.total_nodes; for( c1 = 0; c1 < count1; c1++ ) { int fwdsave = 1; int fwdmaysave = 1; tempelem2 = list_getstart( (struct list *)tempelem1->data ); count2 = ((struct list *)tempelem1->data)->total_nodes; for( c2 = 0; c2 < count2; c2++ ) { tempelem3 = list_getstart( (struct list *)tempelem2->data ); count3= ((struct list *)tempelem2->data)->total_nodes; for( c3 = 0; c3 < count3; c3++ ) { // here begins the meat /* Note that the fields are in *reverse* * order from the definition above! */ if( 4 == c2 ) { /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): looks like a user id" ); if( fwdsave ) { trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, (char *)tempelem3->data); occurences += auth_check_user_ext((char *)tempelem3->data, userids, fwds, 1); } else { trace (TRACE_DEBUG,"auth_check_user_ext(): not checking user %s to %s due to fwdsave=0",address, (char *)tempelem3->data); } } else if( 3 == c2 ) { /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): looks like a group member" ); trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, (char *)tempelem3->data); occurences += auth_check_user_ext((char *)tempelem3->data, userids, fwds, -2); } else if( 2 == c2 ) { /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): looks like a forwarding dn" ); trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, (char *)tempelem3->data); occurences += auth_check_user_ext((char *)tempelem3->data, userids, fwds, -2); /* if the user does not have a forward, their fwdsave will be false * but logically, it is true: "save, then forward to nowhere" * so here we make sure that before we don't deliver we check: * - that the fwdsave value is false * AND - that there is a forwarding address */ if( 0 == fwdmaysave ) fwdsave = 0; } else if( 1 == c2 ) { /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): looks like a forwarding state" ); trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, (char *)tempelem3->data); if( 0 == strcasecmp( (char *)tempelem3->data, "true" ) ) fwdmaysave = 1; else if( 0 == strcasecmp( (char *)tempelem3->data, "false" ) ) fwdmaysave = 0; } else if( 0 == c2 ) { /* do a recursive search for deliver_to */ trace (TRACE_DEBUG,"auth_check_user_ext(): looks like a forwarding target" ); /* rip the prefix off of the result */ { char target[AUTH_QUERY_SIZE]; /* I am much happier now that this is case insensitive :-) * albeit at the cost of complication and uglification... * perhaps this could be made into a separate function... */ if( 0 == strncasecmp( (char *)tempelem3->data, _ldap_cfg.fwdtargetprefix, strlen( _ldap_cfg.fwdtargetprefix ) ) ) { /* Offset the pointer by the length of the prefix to skip */ sscanf( (char *)tempelem3->data + strlen( _ldap_cfg.fwdtargetprefix ), " %s ", &target ); } else { /* The prefix wasn't in there, so just use what we got */ snprintf( target, AUTH_QUERY_SIZE, (char *)tempelem3->data ); } trace (TRACE_DEBUG,"auth_check_user_ext(): checking user %s to %s",address, target); occurences += 1; list_nodeadd(fwds, target, strlen(target)+1); } } tempelem3 = tempelem3->nextnode; } list_freelist( &((struct list *)tempelem2->data)->start ); tempelem2 = tempelem2->nextnode; } list_freelist( &((struct list *)tempelem1->data)->start ); tempelem1 = tempelem1->nextnode; } list_freelist( &templist.start ); trace(TRACE_DEBUG,"auth_check_user_ext(): executing query, checks [%d]", checks); /* trace(TRACE_INFO,"auth_check_user(): user [%s] has [%d] entries",address,occurences); */ 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", _ldap_cfg.objectclass, NULL }; char *uid_values[] = { username, NULL }; char *cid_values[] = { clientid, NULL }; char *nid_values[] = { kaboom, NULL }; char *max_values[] = { maxmail, NULL }; field_t cn_type = "cn"; field_t sn_type = "sn"; field_t mail_type = "mail"; field_t obj_type = "objectClass"; 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( _ldap_cfg.base_dn ) + 1 ); sprintf( _ldap_dn, "cn=%s,%s", username, _ldap_cfg.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. There's a 12 byte leak here, better find it... */ _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 = obj_type; _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_type; _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_type; _ldap_mod[i]->mod_values = cn_values; if( strlen( _ldap_cfg.field_passwd ) > 0 ) { i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _ldap_cfg.field_passwd, pw_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.field_passwd; _ldap_mod[i]->mod_values = cn_values; } 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_type; _ldap_mod[i]->mod_values = sn_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _ldap_cfg.field_uid, uid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.field_uid; _ldap_mod[i]->mod_values = uid_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _ldap_cfg.field_cid, cid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.field_cid; _ldap_mod[i]->mod_values = cid_values; i++; trace( TRACE_DEBUG, "Starting to define LDAPMod element %d type %s value %s", i, _ldap_cfg.field_maxmail, max_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.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, _ldap_cfg.field_nid, nid_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_ADD; _ldap_mod[i]->mod_type = _ldap_cfg.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! */ /* there's a 12 byte leak here, but I can't figure out how to fix it :-( */ for( i = 0; i < NUM_MODS; i++ ) my_free( _ldap_mod[i] ); my_free( _ldap_mod ); /* this function should clear the leak, but it segfaults instead :-\ */ /* ldap_mods_free( _ldap_mod, 1 ); */ 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)", _ldap_cfg.field_uid, username ); trace(TRACE_DEBUG,"auth_delete_user(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "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)", _ldap_cfg.field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_username(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "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, _ldap_cfg.field_uid, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _ldap_cfg.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) { 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)", _ldap_cfg.field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_clientid(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "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, _ldap_cfg.field_cid, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _ldap_cfg.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)", _ldap_cfg.field_nid, useridnr ); trace(TRACE_DEBUG,"auth_change_mailboxsize(): searching with query [%s]", _ldap_query ); _ldap_err = ldap_search_s( _ldap_conn, _ldap_cfg.base_dn, _ldap_cfg.scope_int, _ldap_query, _ldap_attrs, _ldap_attrsonly, &_ldap_res ); if ( _ldap_err ) { trace(TRACE_ERROR, "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, _ldap_cfg.field_maxmail, new_values[0] ); _ldap_mod[i]->mod_op = LDAP_MOD_REPLACE; _ldap_mod[i]->mod_type = _ldap_cfg.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; char timestr[30]; time_t td; struct tm tm; int ldap_err; char *ldap_dn = NULL; char *id_char = NULL; char query[AUTH_QUERY_SIZE]; char *fields[] = { "dn", _ldap_cfg.field_nid, NULL }; time(&td); /* get time */ tm = *localtime(&td); /* get components */ strftime(timestr, sizeof(timestr), "%G-%m-%d %H:%M:%S", &tm); snprintf( query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid, user ); // ldap_dn = __auth_get_first_match( query, fields ); // id_char = __auth_get_first_match( query, _ldap_cfg.field_nid ); /* now, try to rebind as the given DN using the supplied password */ trace (TRACE_ERROR,"auth_validate(): rebinding as [%s] to validate password", ldap_dn); ldap_err = ldap_bind_s( _ldap_conn, ldap_dn, password, LDAP_AUTH_SIMPLE ); // FIXME: do we need to bind back to the dbmail "superuser" again? // FIXME: not at the moment because the db_reconnect() will do it for us if( ldap_err ) { trace(TRACE_ERROR,"auth_validate(): ldap_bind_s failed: %s", ldap_err2string( ldap_err ) ); id = 0; } else { id = (id_char) ? strtoull(id_char, NULL, 10) : 0; trace (TRACE_ERROR,"auth_validate(): return value is [%llu]",id); /* FIXME: implement this in LDAP... log login in the database 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"); */ } if( id_char ) free( id_char ); if( ldap_dn ) ldap_memfree( ldap_dn ); return id; } /* returns useridnr on OK, 0 on validation failed, -1 on error */ u64_t auth_md5_validate (char *username,unsigned char *md5_apop_he, char *apop_stamp) { return 0; } /* // { // int c1, c2, c3; // int count1, count2, count3; // struct list templist; // struct element *tempelem1, *tempelem2, *tempelem3; // // /* do the first entry here */ // tempelem1 = list_getstart( retlist ); // count1 = retlist->total_nodes; // // /* we'll get the next entry at the _end_ of the loop! */ // printf( "retlist has %d nodes\n", retlist->total_nodes ); // for( c1 = 0; c1 < count1; c1++ ) // { // tempelem2 = list_getstart( (struct list *)tempelem1->data ); // count2 = ((struct list *)tempelem1->data)->total_nodes; // for( c2 = 0; c2 < count2; c2++ ) // { // //if( tempelem2 ) // tempelem3 = list_getstart( (struct list *)tempelem2->data ); // count3 = ((struct list *)tempelem2->data)->total_nodes; // for( c3 = 0; c3 < count3; c3++ ) // { // printf( "I've got %s\n", tempelem3->data ); // tempelem3 = tempelem3->nextnode; // //if( tempelem3->nextnode ) tempelem3 = tempelem3->nextnode; // // else { printf(" break at %d\n", __LINE__ ); break; } // } // //if( tempelem2->nextnode ) tempelem2 = tempelem2->nextnode; // tempelem2 = tempelem2->nextnode; // // else { printf(" break at %d\n", __LINE__ ); break; } // } // tempelem1 = tempelem1->nextnode; // //if( tempelem1->nextnode ) tempelem1 = tempelem1->nextnode; // // else { printf(" break at %d\n", __LINE__ ); break; } // } // } //*/