userdb-ldap.c revision a30b52af112bc98b74b8624e9a5d20cb754b2ab7
/* Copyright (C) 2003 Timo Sirainen */
#include "config.h"
#undef HAVE_CONFIG_H
#ifdef USERDB_LDAP
#include "common.h"
#include "str.h"
#include "var-expand.h"
#include "db-ldap.h"
#include "userdb.h"
#include <ldap.h>
#include <stdlib.h>
/* using posixAccount */
#define DEFAULT_ATTRIBUTES "uid,homeDirectory,,,uidNumber,gidNumber"
enum ldap_user_attr {
ATTR_VIRTUAL_USER = 0,
ATTR_HOME,
ATTR_MAIL,
ATTR_SYSTEM_USER,
ATTR_UID_NUMBER,
ATTR_GID_NUMBER,
ATTR_COUNT
};
struct userdb_ldap_connection {
struct ldap_connection *conn;
unsigned int *attrs;
char **attr_names;
};
struct userdb_ldap_request {
struct ldap_request request;
userdb_callback_t *userdb_callback;
};
static struct userdb_ldap_connection *userdb_ldap_conn;
static void parse_attr(struct userdb_ldap_connection *conn,
struct user_data *user,
const char *attr, const char *value)
{
enum ldap_user_attr i;
for (i = 0; i < ATTR_COUNT; i++) {
if (strcasecmp(conn->attr_names[i], attr) == 0)
break;
}
if (i == ATTR_COUNT) {
i_error("LDAP: Unknown attribute '%s'", attr);
return;
}
switch (conn->attrs[i]) {
case ATTR_VIRTUAL_USER:
user->virtual_user = t_strdup(value);
break;
case ATTR_HOME:
user->home = t_strdup(value);
break;
case ATTR_MAIL:
user->mail = t_strdup(value);
break;
case ATTR_SYSTEM_USER:
user->system_user = t_strdup(value);
break;
case ATTR_UID_NUMBER:
user->uid = atoi(value);
break;
case ATTR_GID_NUMBER:
user->gid = atoi(value);
break;
case ATTR_COUNT:
break;
}
}
static void handle_request(struct ldap_connection *conn,
struct ldap_request *request, LDAPMessage *res)
{
struct userdb_ldap_request *urequest =
(struct userdb_ldap_request *) request;
struct user_data user;
LDAPMessage *entry;
BerElement *ber;
char *attr, **vals;
int ret;
ret = ldap_result2error(conn->ld, res, 0);
if (ret != LDAP_SUCCESS) {
i_error("LDAP: ldap_search() failed: %s",
ldap_err2string(ret));
urequest->userdb_callback(NULL, request->context);
i_free(urequest);
return;
}
entry = res == NULL ? NULL : ldap_first_entry(conn->ld, res);
if (entry == NULL) {
if (res != NULL)
i_error("LDAP: Authenticated user not found");
urequest->userdb_callback(NULL, request->context);
i_free(urequest);
return;
}
t_push();
memset(&user, 0, sizeof(user));
user.uid = conn->set.user_global_uid;
user.gid = conn->set.user_global_gid;
attr = ldap_first_attribute(conn->ld, entry, &ber);
while (attr != NULL) {
vals = ldap_get_values(conn->ld, entry, attr);
if (vals != NULL && vals[0] != NULL && vals[1] == NULL)
parse_attr(userdb_ldap_conn, &user, attr, vals[0]);
ldap_value_free(vals);
ldap_memfree(attr);
attr = ldap_next_attribute(conn->ld, entry, ber);
}
if (user.virtual_user == NULL)
i_error("LDAP: No username in reply");
else if (user.uid == (uid_t)-1) {
i_error("ldap(%s): uidNumber not set and no default given in "
"user_global_uid", user.virtual_user);
} else if (user.gid == (gid_t)-1) {
i_error("ldap(%s): gidNumber not set and no default given in "
"user_global_gid", user.virtual_user);
} else if (ldap_next_entry(conn->ld, entry) != NULL) {
i_error("ldap(%s): Multiple replies found for user",
user.virtual_user);
} else {
urequest->userdb_callback(&user, request->context);
i_free(urequest);
t_pop();
return;
}
/* error */
urequest->userdb_callback(NULL, request->context);
i_free(urequest);
t_pop();
}
static void userdb_ldap_lookup(struct auth_request *auth_request,
userdb_callback_t *callback, void *context)
{
struct ldap_connection *conn = userdb_ldap_conn->conn;
struct userdb_ldap_request *request;
const char *filter;
string_t *str;
if (conn->set.user_filter == NULL) {
filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))",
userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER],
ldap_escape(auth_request->user));
} else {
str = t_str_new(512);
var_expand(str, conn->set.user_filter,
auth_request_get_var_expand_table(auth_request,
ldap_escape));
filter = str_c(str);
}
request = i_new(struct userdb_ldap_request, 1);
request->request.callback = handle_request;
request->request.context = context;
request->userdb_callback = callback;
db_ldap_search(conn, conn->set.base, conn->set.ldap_scope,
filter, userdb_ldap_conn->attr_names,
&request->request);
}
static void userdb_ldap_preinit(const char *args)
{
struct ldap_connection *conn;
userdb_ldap_conn = i_new(struct userdb_ldap_connection, 1);
userdb_ldap_conn->conn = conn = db_ldap_init(args);
db_ldap_set_attrs(conn, conn->set.user_attrs ?
conn->set.user_attrs : DEFAULT_ATTRIBUTES,
&userdb_ldap_conn->attrs,
&userdb_ldap_conn->attr_names);
}
static void userdb_ldap_init(const char *args __attr_unused__)
{
(void)db_ldap_connect(userdb_ldap_conn->conn);
}
static void userdb_ldap_deinit(void)
{
db_ldap_unref(userdb_ldap_conn->conn);
i_free(userdb_ldap_conn);
}
struct userdb_module userdb_ldap = {
userdb_ldap_preinit,
userdb_ldap_init,
userdb_ldap_deinit,
userdb_ldap_lookup
};
#endif