/*
Copyright (c) 2002 Aaron Stone, aaron@serendipity.cx
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Id: authldap.c 1550 2005-01-07 12:23:02Z paul $
* * User authentication functions for LDAP.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "assert.h"
#include "auth.h"
#include "dbmail.h"
#include "db.h"
#include "dbmd5.h"
#include "debug.h"
#include "list.h"
#include "misc.h"
#include <ldap.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include <crypt.h>
#include <time.h>
#define AUTH_QUERY_SIZE 1024
static char *configFile = DEFAULT_CONFIG_FILE;
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(key, sect, var) \
GetConfigValue(key, sect, var); \
if (strlen(var) == 0) \
trace(TRACE_DEBUG, "%s, %s: no value for " \
#key " in config file section " #sect, \
__FILE__, __func__ ); \
trace(TRACE_DEBUG, "%s, %s: value for " \
#key " from section " #sect " stored in " \
#var " as [%s]", __FILE__, __func__, var)
/* No final ; so macro can be called "like a function" */
static void __auth_get_config(void);
static void __auth_get_config()
{
struct list ldapItems;
ReadConfig("LDAP", configFile);
SetTraceLevel("LDAP");
GETCONFIGVALUE("BIND_DN", "LDAP", _ldap_cfg.bind_dn);
GETCONFIGVALUE("BIND_PW", "LDAP", _ldap_cfg.bind_pw);
GETCONFIGVALUE("BASE_DN", "LDAP", _ldap_cfg.base_dn);
GETCONFIGVALUE("PORT", "LDAP", _ldap_cfg.port);
GETCONFIGVALUE("HOSTNAME", "LDAP", _ldap_cfg.hostname);
GETCONFIGVALUE("OBJECTCLASS", "LDAP", _ldap_cfg.objectclass);
GETCONFIGVALUE("FIELD_UID", "LDAP", _ldap_cfg.field_uid);
GETCONFIGVALUE("FIELD_CID", "LDAP", _ldap_cfg.field_cid);
GETCONFIGVALUE("FIELD_NID", "LDAP", _ldap_cfg.field_nid);
GETCONFIGVALUE("FIELD_MAIL", "LDAP", _ldap_cfg.field_mail);
GETCONFIGVALUE("FIELD_MAILALT", "LDAP", _ldap_cfg.field_mailalt);
GETCONFIGVALUE("MAILALTPREFIX", "LDAP", _ldap_cfg.mailaltprefix);
GETCONFIGVALUE("FIELD_QUOTA", "LDAP", _ldap_cfg.field_maxmail);
GETCONFIGVALUE("FIELD_PASSWD", "LDAP", _ldap_cfg.field_passwd);
GETCONFIGVALUE("FIELD_FORWARD", "LDAP", _ldap_cfg.field_fwd);
GETCONFIGVALUE("FIELD_FWDSAVE", "LDAP", _ldap_cfg.field_fwdsave);
GETCONFIGVALUE("FIELD_FWDTARGET", "LDAP", _ldap_cfg.field_fwdtarget);
GETCONFIGVALUE("FWDTARGETPREFIX", "LDAP", _ldap_cfg.fwdtargetprefix);
GETCONFIGVALUE("FIELD_MEMBERS", "LDAP", _ldap_cfg.field_members);
GETCONFIGVALUE("SCOPE", "LDAP", _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(void);
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; this variable is unused */
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, "%s", 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; usunused variable */
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, "%s", 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, "%s", 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 *) dm_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 */
strncpy(returnid, ldap_dn,
strlen(ldap_dn));
}
} else {
ldap_vals =
ldap_get_values(_ldap_conn, ldap_msg,
retfields[k]);
if (ldap_vals) {
if (!
(returnid =
(char *)
dm_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 */
strncpy(returnid, ldap_vals[0],
strlen(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;
}
int auth_user_exists(const char *username, u64_t * user_idnr)
{
char *id_char;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_nid, NULL };
assert(user_idnr != NULL);
*user_idnr = 0;
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);
*user_idnr = (id_char) ? strtoull(id_char, NULL, 0) : 0;
trace(TRACE_DEBUG, "auth_user_exists(): returned value is [%llu]",
*user_idnr);
if (id_char)
free(id_char);
if (*user_idnr == 0)
return 0;
else
return 1;
}
/* Given a useridnr, find the account/login name
* return 0 if not found, NULL on error
*/
char *auth_get_userid(u64_t user_idnr)
{
char *returnid = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_uid, NULL };
/*
if (!user_idnr)
{
trace(TRACE_ERROR,"auth_get_userid(): got NULL as useridnr");
return 0;
}
*/
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid,
user_idnr);
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
*/
int auth_getclientid(u64_t user_idnr, u64_t * client_idnr)
{
char *cid_char = NULL;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_cid, NULL };
assert(client_idnr != NULL);
*client_idnr = 0;
if (!user_idnr) {
trace(TRACE_ERROR,
"auth_getclientid(): got NULL as useridnr");
return -1;
}
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid,
user_idnr);
cid_char = __auth_get_first_match(query, fields);
*client_idnr = (cid_char) ? strtoull(cid_char, NULL, 0) : 0;
trace(TRACE_DEBUG, "auth_getclientid(): returned value is [%llu]",
*client_idnr);
if (cid_char)
free(cid_char);
return 1;
}
int auth_getmaxmailsize(u64_t user_idnr, u64_t * maxmail_size)
{
char *max_char;
char query[AUTH_QUERY_SIZE];
char *fields[] = { _ldap_cfg.field_cid, NULL };
assert(maxmail_size != NULL);
*maxmail_size = 0;
if (!user_idnr) {
trace(TRACE_ERROR,
"auth_getmaxmailsize(): got NULL as useridnr");
return 0;
}
snprintf(query, AUTH_QUERY_SIZE, "(%s=%llu)", _ldap_cfg.field_nid,
user_idnr);
max_char = __auth_get_first_match(query, fields);
*maxmail_size = (max_char) ? strtoull(max_char, 0, 10) : 0;
trace(TRACE_DEBUG,
"auth_getmaxmailsize(): returned value is [%llu]",
*maxmail_size);
if (max_char)
free(max_char);
return 1;
}
/*
* 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 user_idnr UNUSED)
{
/* 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)
{
int64_t known;
/* u64_t curr; unused variable */
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; unused variable */
int 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; unused variable */
int 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[0]);
} else {
/* The prefix wasn't in there, so just use what we got */
snprintf(target,
AUTH_QUERY_SIZE,
"%s",
(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..
* \bug This does not seem to work.. It should. This makes
* this function effectively non-functional!
* returns a 1 on succes, -1 on failure
*/
int auth_adduser(const char *username, const char *password,
const char *enctype UNUSED, u64_t clientid,
u64_t maxmail, u64_t * user_idnr)
{
int i, j;
/*int ret; unused variable */
int NUM_MODS = 9;
char *kaboom = "123";
char *cid = "0";
char *maxm = "0";
sprintf(cid,"%llu",clientid);
sprintf(maxm,"%llu",maxmail);
char *cn_values[] = { (char *)username, NULL };
char *sn_values[] = { (char *)username, NULL };
char *pw_values[] = { (char *)password, NULL };
char *obj_values[] =
{ "top", "person", _ldap_cfg.objectclass, NULL };
char *uid_values[] = { (char *)username, NULL };
char *cid_values[] = { cid, NULL };
char *nid_values[] = { kaboom, NULL };
char *max_values[] = { maxm, NULL };
field_t cn_type = "cn";
field_t sn_type = "sn";
field_t mail_type = "mail";
field_t obj_type = "objectClass";
unsigned _ldap_dn_len;
assert(user_idnr != NULL);
*user_idnr = 0;
auth_reconnect();
/* Make the malloc for all of the pieces we're about to to sprintf into it */
_ldap_dn_len =
strlen("cn=,") + strlen(username) + strlen(_ldap_cfg.base_dn);
_ldap_dn = (char *) dm_malloc(_ldap_dn_len + 1);
snprintf(_ldap_dn, _ldap_dn_len, "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 **) dm_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 *) dm_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++)
dm_free(_ldap_mod[j]);
dm_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++)
dm_free(_ldap_mod[i]);
dm_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;
}
*user_idnr = strtoull(nid_values[0], 0, 0);
return 1;
}
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 user_idnr, const char *new_name)
{
int i, j, NUM_MODS = 2;
char *new_name_str;
char *new_values[2];
new_name_str =
(char *) dm_malloc(sizeof(char) * (strlen(new_name) + 1));
strncpy(new_name_str, new_name, strlen(new_name));
new_values[0] = new_name_str;
new_values[1] = NULL;
auth_reconnect();
if (!user_idnr) {
trace(TRACE_ERROR,
"auth_change_username(): got NULL as useridnr");
return 0;
}
if (!new_name) {
trace(TRACE_ERROR,
"auth_change_username(): got NULL as new_name");
return 0;
}
snprintf(_ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)",
_ldap_cfg.field_nid, user_idnr);
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 **) dm_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 *) dm_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++)
dm_free(_ldap_mod[j]);
dm_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++)
dm_free(_ldap_mod[i]);
dm_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 user_idnr UNUSED,
const char *new_pass UNUSED,
const char *enctype UNUSED)
{
return -1;
}
int auth_change_clientid(u64_t user_idnr, u64_t newcid)
{
int i, j, NUM_MODS = 2;
char newcid_str[100];
char *new_values[] = { newcid_str, NULL };
auth_reconnect();
if (!user_idnr) {
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, user_idnr);
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 **) dm_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 *) dm_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++)
dm_free(_ldap_mod[j]);
dm_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++)
dm_free(_ldap_mod[i]);
dm_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 user_idnr, u64_t new_size)
{
int i, j, NUM_MODS = 2;
char newsize_str[100];
char *new_values[] = { newsize_str, NULL };
auth_reconnect();
if (!user_idnr) {
trace(TRACE_ERROR,
"auth_change_mailboxsize(): got NULL as useridnr");
return 0;
}
if (!new_size) {
trace(TRACE_ERROR,
"auth_change_mailboxsize(): got NULL as newsize");
return 0;
}
snprintf(new_values[0], 100, "%llu", new_size);
snprintf(_ldap_query, AUTH_QUERY_SIZE, "(%s=%llu)",
_ldap_cfg.field_nid, user_idnr);
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 **) dm_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 *) dm_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++)
dm_free(_ldap_mod[j]);
dm_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++)
dm_free(_ldap_mod[i]);
dm_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
*/
int auth_validate(char *username, char *password, u64_t * user_idnr)
{
timestring_t timestring;
int ldap_err;
char *ldap_dn = NULL;
char *id_char = NULL;
char query[AUTH_QUERY_SIZE];
/*char *fields[] = { "dn", _ldap_cfg.field_nid, NULL }; unused variable */
assert(user_idnr != NULL);
if (username == NULL || password == NULL) {
trace(TRACE_DEBUG, "auth__validate() username or password "
"is NULL");
return 0;
}
*user_idnr = 0;
create_current_timestring(×tring);
snprintf(query, AUTH_QUERY_SIZE, "(%s=%s)", _ldap_cfg.field_uid,
username);
// 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));
user_idnr = 0;
} else {
*user_idnr = (id_char) ? strtoull(id_char, NULL, 10) : 0;
trace(TRACE_ERROR,
"auth_validate(): return value is [%llu]",
*user_idnr);
/* 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'", timestring, 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);
if (*user_idnr == 0)
return 0;
else
return 1;
}
/* returns useridnr on OK, 0 on validation failed, -1 on error */
u64_t auth_md5_validate(char *username UNUSED,
unsigned char *md5_apop_he UNUSED,
char *apop_stamp UNUSED)
{
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; }
// }
// }
//*/
syntax highlighted by Code2HTML, v. 0.9.1