/*
* $Id: ftp-ldap.c,v 1.7.2.3 2004/03/10 16:07:13 mt Exp $
*
* FTP Proxy LDAP interface handling
*
* Author(s): Jens-Gero Boehm <jens-gero.boehm@suse.de>
* Pieter Hollants <pieter.hollants@suse.de>
* Marius Tomaschewski <mt@suse.de>
* Volker Wiegand <volker.wiegand@suse.de>
*
* This file is part of the SuSE Proxy Suite
* See also http://proxy-suite.suse.de/
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* A history log can be found at the end of this file.
*/
#ifndef lint
static char rcsid[] = "$Id: ftp-ldap.c,v 1.7.2.3 2004/03/10 16:07:13 mt Exp $";
#endif
#include <config.h>
#define _GNU_SOURCE /* needed for crypt in Linux... */
#if defined(STDC_HEADERS)
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <stdarg.h>
# include <errno.h>
# include <ctype.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined(TIME_WITH_SYS_TIME)
# include <sys/time.h>
# include <time.h>
#else
# if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#if defined(HAVE_LIBLDAP)
# if defined(HAVE_LDAP_UMICH)
# include <lber.h>
# endif
# include <ldap.h>
# if !defined(LDAP_PORT)
# define LDAP_PORT 389
# endif
#endif
#include "com-config.h"
#include "com-debug.h"
#include "com-misc.h"
#include "com-socket.h"
#include "com-syslog.h"
#include "ftp-client.h"
#include "ftp-cmds.h"
#include "ftp-ldap.h"
/* ------------------------------------------------------------ */
#if defined(HAVE_LIBLDAP)
# if defined(HAVE_LDAP_GET_LDERRNO)
/*
** Netscape
*/
# define GET_LDERROR(ld,le) le = ldap_get_lderrno(ld, NULL, NULL)
# elif defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
/*
** OpenLDAP 2.x
*/
# define GET_LDERROR(ld,le) ldap_get_option(ld,LDAP_OPT_ERROR_NUMBER,&le)
# elif defined __sun__
/*
** there is only a forward declaration of the LDAP
** connection handle struct in ldap.h on Solaris7,
** so we have no access to ld_errno.
*/
# define GET_LDERROR(ld,le) le = LDAP_OTHER
# else
/*
** UmichLDAP or OpenLDAP 1.x
*/
# define GET_LDERROR(ld,le) le = (ld)->ld_errno
# endif
#endif
/* ------------------------------------------------------------ */
#if defined(HAVE_LIBLDAP)
static int ldap_fetch(LDAP *ld, CONTEXT *ctx, char *who, char *pwd);
static char *ldap_attrib(LDAP *ld, LDAPMessage *e, char *attr, char *dflt);
static int ldap_exists(LDAP *ld, LDAPMessage *e, char *attr,
char *vstr, int cs);
static int ldap_auth(LDAP *ld, LDAPMessage *e, char *who, char *pwd);
static char* prep_bind_auto(LDAP *ld, char *flt, char *base, char *peer);
static char* prep_bind_fmt(char *str, char *who);
#endif
/* ------------------------------------------------------------ **
**
** Function......: ldap_setup_user
**
** Parameters....: ctx Pointer to user context
** who Pointer to user auth name
** pwd Pointer to user auth pwd
**
** Return........: 0 on success
**
** Purpose.......: Read the user specific parameters from
** LDAP Server if one is known.
**
** ------------------------------------------------------------ */
int ldap_setup_user(CONTEXT *ctx, char *who, char *pwd)
{
char *ptr = 0;
int ver = 0;
/*
** avoid unused... compiler warnings
*/
ver = ver;
ptr = ptr;
pwd = pwd;
/*
** Basic sanity check
*/
if( !(ctx && who && *who))
misc_die(FL, "ldap_setup_user: ?ctx? ?who?");
#if defined(HAVE_LIBLDAP)
/*
** use configured ldap version or prefer v3 since
** OpenLDAP 2.x library defaults to v2, but the
** server does not accept v2 binds per default...
*/
#if defined(LDAP_VERSION3)
ver = LDAP_VERSION3;
#elif defined(LDAP_VERSION2)
ver = LDAP_VERSION2;
#else
ver = 0;
#endif
ptr = config_str(NULL, "LDAPVersion", NULL);
if(NULL != ptr) {
ver = atoi(ptr);
}
/*
** If an LDAP server is configured, insist on using it
*/
if((ptr = config_str(NULL, "LDAPServer", NULL)) != NULL) {
char temp[MAX_PATH_SIZE];
char *host;
u_int16_t port;
int rc;
LDAP *ld;
misc_strncpy(temp, ptr, sizeof(temp));
/*
** Determine LDAP server and port
*/
host = temp;
if(NULL != (ptr = strchr(temp, ':'))) {
*ptr++ = '\0';
port = (int) socket_str2port(ptr, LDAP_PORT);
} else {
port = (int) LDAP_PORT;
}
#if defined(COMPILE_DEBUG)
debug(2, "LDAP server: %s:%d", host, port);
#endif
/*
** Ready to contact the LDAP server
*/
if((ld = ldap_init(host, port)) == NULL) {
syslog_write(T_ERR,
"can't reach LDAP server %s:%u for %s",
host, port, ctx->cli_ctrl->peer);
return -1;
} else {
syslog_write(T_DBG,
"LDAP server %s:%u: initialized for %s",
host, port, ctx->cli_ctrl->peer);
}
if(ver > 0) {
#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION)
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ver);
#else
ld->ld_version = ver;
#endif
}
rc = ldap_fetch(ld, ctx, who, pwd);
ldap_unbind(ld);
return rc;
}
#endif
return 0;
}
#if defined(HAVE_LIBLDAP)
/* ------------------------------------------------------------ **
**
** Function......: prep_bind_auto
**
** Parameters....: ld Pointer ldap struct
** flt LDAP search filter
** base BaseDN to search in
** peer Peer name for syslog
**
** Return........: bind-dn or NULL
**
** Purpose.......: Searches using anonymous bind
** for a dn we want to bind later.
**
** ------------------------------------------------------------ */
static char* prep_bind_auto(LDAP *ld, char *flt, char *base, char *peer)
{
LDAPMessage *result, *e;
char *attrs[] = {0, 0};
char *bind_dn, *p, *d;
int err;
if(NULL == base || '\0' == base[0]) {
misc_die(FL,"prep_bind_auto: ?base?");
}
/*
** pre-bind (anonymously)
*/
if((d = config_str(NULL, "LDAPPreBindDN", NULL)) &&
(p = config_str(NULL, "LDAPPreBindPW", NULL))) {
err = ldap_simple_bind_s(ld, d, p);
} else {
err = ldap_simple_bind_s(ld, 0, 0);
}
if(LDAP_SUCCESS != err) {
syslog_write(T_ERR,
"can't bind LDAP anonymously for %s: %.512s",
peer, ldap_err2string(err));
return NULL;
}
result = 0;
attrs[0] = config_str(NULL, "LDAPIdentifier", "CN");
err = ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE,
flt, attrs, 1, &result);
if(LDAP_SUCCESS != err) {
syslog_write(T_ERR,
"can't find valid bind-dn for %s: %.512s",
peer, ldap_err2string(err));
return NULL;
}
e = ldap_first_entry(ld, result);
if(NULL == e) {
GET_LDERROR(ld, err);
syslog_write(T_ERR,
"can't find valid bind-dn for %s", peer);
return NULL;
}
/*
** OK, we have a DN
*/
if(NULL != (p = ldap_get_dn(ld, e))) {
bind_dn = misc_strdup(FL, p);
ldap_memfree(p);
} else {
bind_dn = NULL;
}
ldap_msgfree(result);
syslog_write(T_DBG, "auto bind-dn='%.256s' for %s",
NIL(bind_dn), peer);
return bind_dn;
}
/* ------------------------------------------------------------ **
**
** Function......: prep_bind_fmt
**
** Parameters....: str Bind-DN fmt string
** who Current user name
**
** Return........: bind-dn or NULL
**
** Purpose.......: Checks if str contains a fmt
** and constructs a new base-dn.
**
** ------------------------------------------------------------ */
static char* prep_bind_fmt(char *str, char *who)
{
char *bind_dn, *p;
int fmt = 0;
size_t len;
/*
** search for exactly one %s; if any other
** fmt's are present report an parse error.
*/
for(p=str; p && p[0] && (p = strchr(p, '%')); p++) {
if(!fmt && ('s' == p[1] || 'S' == p[1])) {
fmt = 1;
} else {
errno = 0;
misc_die(FL,"prep_bind_fmt: ?str?");
}
}
if(fmt) {
/*
** constuct LDAPBind DN and PW
*/
len = strlen(who) + strlen(str);
bind_dn = misc_alloc(FL, len);
#if defined(HAVE_SNPRINTF)
snprintf(bind_dn, len, str, who);
#else
sprintf(bind_dn, str, who);
#endif
return bind_dn;
}
return 0;
}
/* ------------------------------------------------------------ **
**
** Function......: ldap_fetch
**
** Parameters....: ld Pointer ldap struct
** ctx Pointer to user context
** who Pointer to user/auth name
** pwd Pointer to user/auth pwd
**
** Return........: 0 on success
**
** Purpose.......: Read the user specific parameters from
** an LDAP Server.
**
** ------------------------------------------------------------ */
static int ldap_fetch(LDAP *ld, CONTEXT *ctx, char *who, char *pwd)
{
char str[MAX_PATH_SIZE];
char *bind_dn, *bind_pw;
char *base_dn, *auth_dn;
char *idnt, *objc, *ptr, *p, *q;
char lderr, auth_ok;
u_int16_t l, u;
LDAPMessage *result, *e;
/* Basic sanity */
if(ctx == NULL || ld == NULL || who == NULL) {
if(ld) ldap_unbind(ld);
misc_die(FL, "ldap_fetch: ?ctx? ?ld? ?who?");
}
/*
** construct filter for the search
** (by LDAPIdentifier, maybe also ObjectClass)
*/
idnt = config_str(NULL, "LDAPIdentifier", "CN");
objc = config_str(NULL, "LDAPObjectClass", NULL);
if(NULL != objc) {
#if defined(HAVE_SNPRINTF)
snprintf(str, sizeof(str),
"(&(ObjectClass=%.256s)(%.256s=%.256s))",
objc, idnt, who);
#else
sprintf(str,
"(&(ObjectClass=%.256s)(%.256s=%.256s))",
objc, idnt, who);
#endif
} else {
#if defined(HAVE_SNPRINTF)
snprintf(str, sizeof(str), "(%.256s=%.256s)",
idnt, who);
#else
sprintf(str, "(%.256s=%.256s)", idnt, who);
#endif
}
auth_ok = 0; /* OK if non-anonymous bind */
auth_dn = config_str(NULL, "LDAPAuthDN", NULL);
base_dn = config_str(NULL, "LDAPBaseDN", NULL);
if(NULL != (ptr = config_str(NULL, "LDAPBindDN", NULL))) {
/*
** check if we should use auth-/base-dn for bind
*/
bind_pw = pwd;
bind_dn = 0;
if(0 == strcasecmp(ptr, "auto")) {
bind_dn = prep_bind_auto(ld, str, auth_dn ?
auth_dn : base_dn,
ctx->cli_ctrl->peer);
auth_ok = 1;
if(NULL == bind_dn) return -1;
} else
if(0 == strcasecmp(ptr, "AuthDN")) {
bind_dn = prep_bind_auto(ld, str, auth_dn,
ctx->cli_ctrl->peer);
auth_ok = 1;
if(NULL == bind_dn) return -1;
} else
if(0 == strcasecmp(ptr, "BaseDN")) {
bind_dn = prep_bind_auto(ld, str, base_dn,
ctx->cli_ctrl->peer);
auth_ok = 1;
if(NULL == bind_dn) return -1;
} else {
/*
** check if we have a format in BindDN
*/
bind_dn = prep_bind_fmt(ptr, who);
if(NULL == bind_dn) {
/*
** use static LDAPBind DN and PW
*/
bind_dn = misc_strdup(FL, ptr);
bind_pw = config_str(NULL, "LDAPBindPW", NULL);
} else {
auth_ok = 1;
}
}
/*
** bind usind a dn & pw
*/
lderr = ldap_simple_bind_s(ld, bind_dn, bind_pw);
if(LDAP_SUCCESS != lderr) {
syslog_write(U_ERR,
"can't bind LDAP dn='%.256s' for %s: %.512s",
bind_dn, ctx->cli_ctrl->peer,
ldap_err2string(lderr));
return -1;
}
syslog_write(T_DBG,
"LDAP bind to dn='%.256s': succeed", bind_dn);
} else {
/*
** bind anonymously
*/
lderr = ldap_simple_bind_s(ld, 0, 0);
if(LDAP_SUCCESS != lderr) {
syslog_write(T_ERR,
"can't bind LDAP anonymously for %s: %.512s",
ctx->cli_ctrl->peer, ldap_err2string(lderr));
return -1;
}
}
syslog_write(U_INF, "reading data for '%s' from LDAP", who);
if(NULL != base_dn) {
syslog_write(T_DBG,
"LDAP search: base='%.256s' filter='%.256s'",
base_dn, str);
result = 0;
lderr = ldap_search_s(ld, base_dn, LDAP_SCOPE_SUBTREE,
str, NULL, 0, &result);
if(LDAP_SUCCESS != lderr) {
syslog_write(T_ERR,
"can't read LDAP data for %s: %.512s",
ctx->cli_ctrl->peer,
ldap_err2string(lderr));
return -1;
}
/*
** Check if we have a user data
** (else return 'error' or 'empty')
*/
if(NULL == (e = ldap_first_entry(ld, result))) {
GET_LDERROR(ld,lderr);
syslog_write(T_DBG,
"empty LDAP result for %s in base-dn='%s'",
ctx->cli_ctrl->peer, base_dn);
e = result = NULL;
}
} else {
e = result = NULL;
}
/*
** Preform auth on userauth if type is ldap
*/
ptr = config_str(NULL, "UserAuthType", NULL);
if( ptr && 0 == strcasecmp(ptr, "ldap")) {
LDAPMessage *res=0, *a=e;
int rc = 0;
/*
** if LDAPAuthDN set, do auth on a different base...
*/
if(NULL != auth_dn) {
syslog_write(T_DBG,
"LDAP auth: base='%.256s' filter='%.256s'",
auth_dn, str);
lderr = ldap_search_s(ld, auth_dn, LDAP_SCOPE_SUBTREE,
str, NULL, 0, &res);
if(LDAP_SUCCESS != lderr) {
syslog_write(T_ERR,
"can't read LDAP auth-data for %s: %.512s",
ctx->cli_ctrl->peer,
ldap_err2string(lderr));
if(result) ldap_msgfree(result);
return -1;
}
if(NULL == (a = ldap_first_entry(ld, res))) {
GET_LDERROR(ld,lderr);
syslog_write(T_WRN,
"empty LDAP result for %s in auth-dn='%s'",
ctx->cli_ctrl->peer, auth_dn);
if(result) ldap_msgfree(result);
return -1;
}
} else
if(NULL == base_dn || NULL == e) {
ldap_unbind(ld);
misc_die(FL, "ldap_fetch: ?LDAPBaseDN?");
}
/*
** OK, let's check the user auth now
*/
rc = ldap_auth(ld, a, who, pwd);
if(res) ldap_msgfree(res);
if(0 > rc) {
syslog_write(U_ERR,
"LDAP user auth failed for %s from %s",
who, ctx->cli_ctrl->peer);
if(result) ldap_msgfree(result);
return -1;
}
/*
** do not allow to configure UserAuthType=ldap
** and to skip all manual ldap checks without
** an sufficient ldap-bind.
*/
if(0 == rc && 0 == auth_ok) {
syslog_write(T_ERR, "LDAP auth config not sufficient");
if(result) ldap_msgfree(result);
return -1;
}
}
/*
** read proxy user profile data ...
** if we have a base_dn and result
*/
if(NULL == base_dn || NULL == e) {
return 0;
}
/*
** Evaluate the destination FTP server address.
*/
p = ldap_attrib(ld, e, "DestinationAddress", NULL);
if(NULL != p && ctx->magic_addr == INADDR_ANY) {
ctx->srv_addr = socket_str2addr(p, INADDR_ANY);
if(INADDR_ANY == ctx->srv_addr) {
syslog_write(T_ERR, "can't eval DestAddr for %s",
ctx->cli_ctrl->peer);
ldap_msgfree(result);
return -1;
}
#if defined(COMPILE_DEBUG)
debug(2, "ldap DestAddr for %s: '%s'", ctx->cli_ctrl->peer,
socket_addr2str(ctx->srv_addr));
#endif
}
/*
** Evaluate the destination FTP server port
*/
p = ldap_attrib(ld, e, "DestinationPort", NULL);
if(NULL != p && ctx->magic_port == INPORT_ANY) {
ctx->srv_port = socket_str2port(p, INPORT_ANY);
if(INPORT_ANY == ctx->srv_port) {
syslog_write(T_ERR, "can't eval DestPort for %s",
ctx->cli_ctrl->peer);
ldap_msgfree(result);
return -1;
}
#if defined(COMPILE_DEBUG)
debug(2, "ldap DestPort for %s: %u",
ctx->cli_ctrl->peer, ctx->srv_port);
#endif
}
/*
** Evaluate the destination transfer mode
*/
p = ldap_attrib(ld, e, "DestinationTransferMode", NULL);
if(NULL != p) {
if(strcasecmp(p, "active") == 0)
ctx->srv_mode = MOD_ACT_FTP;
else if (strcasecmp(p, "passive") == 0)
ctx->srv_mode = MOD_PAS_FTP;
else if (strcasecmp(p, "client") == 0)
ctx->srv_mode = MOD_CLI_FTP;
else {
syslog_write(T_ERR, "can't eval DestMode for %s",
ctx->cli_ctrl->peer);
ldap_msgfree(result);
return -1;
}
#if defined(COMPILE_DEBUG)
debug(2, "ldap DestMode for %s: %s", ctx->cli_ctrl->peer, p);
#endif
}
/*
** Evaluate the port ranges
*/
p = ldap_attrib(ld, e, "DestinationMinPort", NULL);
q = ldap_attrib(ld, e, "DestinationMaxPort", NULL);
if(NULL != p && NULL != q) {
l = socket_str2port(p, INPORT_ANY);
u = socket_str2port(q, INPORT_ANY);
if (l > 0 && u > 0 && u >= l) {
ctx->srv_lrng = l;
ctx->srv_urng = u;
}
#if defined(COMPILE_DEBUG)
debug(2, "ldap DestRange for %s: %u-%u", ctx->cli_ctrl->peer,
ctx->srv_lrng, ctx->srv_urng);
#endif
}
p = ldap_attrib(ld, e, "ActiveMinDataPort", NULL);
q = ldap_attrib(ld, e, "ActiveMaxDataPort", NULL);
if(NULL != p && NULL != q) {
l = socket_str2port(p, INPORT_ANY);
u = socket_str2port(q, INPORT_ANY);
if (l > 0 && u > 0 && u >= l) {
ctx->act_lrng = l;
ctx->act_urng = u;
}
#if defined(COMPILE_DEBUG)
debug(2, "ActiveRange for %s: %u-%u", ctx->cli_ctrl->peer,
ctx->act_lrng, ctx->act_urng);
#endif
}
p = ldap_attrib(ld, e, "PassiveMinDataPort", NULL);
q = ldap_attrib(ld, e, "PassiveMaxDataPort", NULL);
if(NULL != p && NULL != q) {
l = socket_str2port(p, INPORT_ANY);
u = socket_str2port(q, INPORT_ANY);
if (l > 0 && u > 0 && u >= l) {
ctx->pas_lrng = l;
ctx->pas_urng = u;
}
#if defined(COMPILE_DEBUG)
debug(2, "PassiveRange for %s: %u-%u", ctx->cli_ctrl->peer,
ctx->pas_lrng, ctx->pas_urng);
#endif
}
/*
** Setup other configuration options
*/
p = ldap_attrib(ld, e, "SameAddress", NULL);
if(NULL != p) {
if (strcasecmp(p, "y") == 0)
ctx->same_adr = 1;
else if (strcasecmp(p, "on") == 0)
ctx->same_adr = 1;
else if (strcasecmp(p, "yes") == 0)
ctx->same_adr = 1;
else if (strcasecmp(p, "true") == 0)
ctx->same_adr = 1;
else if (*p >= '0' && *p <= '9')
ctx->same_adr = (atoi(p) != 0);
else
ctx->same_adr = 0;
#if defined(COMPILE_DEBUG)
debug(2, "SameAddress for %s: %s", ctx->cli_ctrl->peer,
ctx->same_adr ? "yes" : "no");
#endif
}
p = ldap_attrib(ld, e, "TimeOut", "900");
if(NULL != p) {
if (*p >= '0' && *p <= '9')
ctx->timeout = atoi(p);
else
ctx->timeout = 900;
#if defined(COMPILE_DEBUG)
debug(2, "TimeOut for %s: %d", ctx->cli_ctrl->peer,
ctx->timeout);
#endif
}
/*
** Adjust the allow/deny flags for the commands
*/
p = ldap_attrib(ld, e, "ValidCommands", NULL);
if(NULL != p) {
cmds_set_allow(p);
}
/*
** All relevant attributes have been evaluated
*/
ldap_msgfree(result);
return 0;
}
/* ------------------------------------------------------------ **
**
** Function......: ldap_auth
**
** Parameters....: ld Pointer to LDAP struct
** e Pointer to result buffer
** who Pointer to user name
** pwd Pointer to user pwd
**
** Return........: 0 on success
**
** Purpose.......: Preform LDAP userauth
**
** ------------------------------------------------------------ */
static int ldap_auth(LDAP *ld, LDAPMessage *e, char *who, char *pwd)
{
char str[MAX_PATH_SIZE];
char *v, *p, *q;
size_t len;
int xrc = 0;
if (ld == NULL || e == NULL)
misc_die(FL, "ldap_checkauth: ?ld? ?e?");
/*
** check "user enabled" flag if present
*/
if( (p = config_str(NULL, "LDAPAuthOKFlag", NULL))) {
misc_strncpy(str, p, sizeof(str));
if( (v = strchr(str, '=')))
*v++ = '\0';
else v = 0;
if(v && strlen(v) && strlen(str)) {
if(0 != ldap_exists(ld, e, str, v, 0)) {
syslog_write(U_WRN,
"access denied for %s", NIL(who));
return -1;
} else {
syslog_write(T_DBG,
"LDAP auth ok-check: '%.256s'='%.256s' passed",
NIL(str), NIL(v));
xrc = 1;
}
} else {
errno = 0;
misc_die(FL, "ldap_auth: ?LDAPAuthOKFlag?");
}
} else {
syslog_write(T_DBG, "LDAP auth ok-check skipped");
}
/*
** check user pass match
*/
if( (p = config_str(NULL, "LDAPAuthPWAttr", "")) && strlen(p)) {
if(NULL == pwd)
pwd = "";
v = config_str(NULL, "LDAPAuthPWType", "plain");
q = ldap_attrib(ld, e, p, "");
p = 0;
len = 0;
if( !strncasecmp(v, "plain", sizeof("plain")-1)) {
/*
** plain passwd - no prefix
*/
len = sizeof("plain")-1;
p = pwd;
#if defined(HAVE_CRYPT)
} else
if( !strncasecmp(v, "crypt", sizeof("plain")-1)) {
/*
** crypt - no prefix
*/
len = sizeof("plain")-1;
p = crypt(pwd, q);
} else
if( !strncasecmp(v, "{crypt}", sizeof("{crypt}")-1)) {
/*
** crypt - {crypt} prefix
*/
len = sizeof("{crypt}")-1;
if(strncasecmp(q, "{crypt}", len)) {
syslog_write(T_ERR,
"ldap user auth - prefix missed");
return -1;
}
q+=len;
p = crypt(pwd, q);
#endif
} else {
errno = 0;
misc_die(FL, "ldap_auth: ?LDAPAuthPWType?");
}
/*
** check if we have different minimal length
** it is coded in latest "char", i.e. plain9
*/
if(0 < len && strlen(v) == len+1 &&
'0' <= v[len] && '9' >= v[len])
{
len = (size_t)v[len] - '0';
} else len = PASS_MIN_LEN;
syslog_write(T_DBG, "LDAP auth pw-type[%d]='%.256s'", len, v);
#if defined(COMPILE_DEBUG)
debug(3, "LDAP auth pw-check: '%.256s' ?= '%.256s'",
NIL(q), NIL(p));
#endif
/*
** check (lenght) and compare passwds; the user
** account is locked if LDAP-PWD is "*" or "!"
*/
if(p && strlen(p)>=len && strlen(q) == strlen(p) &&
!(1==strlen(q) && ('*' == q[0] || '!' == q[0])))
{
if(0 == strcmp(q, p)) {
syslog_write(T_DBG,
"LDAP auth pw-check succeed");
return xrc + 2;
}
}
syslog_write(T_DBG, "LDAP auth pw-check failed");
return -1;
} else {
syslog_write(T_DBG, "LDAP auth pw-check skipped");
}
/*
** OK, all configured manual LDAPAuth checks succeed...
*/
return xrc;
}
/* ------------------------------------------------------------ **
**
** Function......: ldap_attrib
**
** Parameters....: ld Pointer to LDAP struct
** e Pointer to result buffer
** attr Name of desired option
** dflt Default value
**
** Return........: Value for attr (or dflt if not found)
**
** Purpose.......: Search the LDAP result message for the
** desired attribute value and return it.
** NEVER return a NULL pointer except if
** the dflt was taken and is NULL itself.
**
** ------------------------------------------------------------ */
static char *ldap_attrib(LDAP *ld, LDAPMessage *e, char *attr, char *dflt)
{
static char str[MAX_PATH_SIZE];
char **vals;
if (ld == NULL || e == NULL || attr == NULL)
misc_die(FL, "ldap_attrib: ?ld? ?e? ?attr?");
/*
** See if this attribute has values available
*/
if ((vals = ldap_get_values(ld, e, attr)) == NULL) {
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: '%.256s' - '%.1024s'",
attr, NIL(dflt));
#endif
return dflt;
}
/*
** Save value (use the first one) and free memory
*/
misc_strncpy(str, vals[0], sizeof(str));
ldap_value_free(vals);
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: '%.256s' = '%.1024s'", attr, str);
#endif
return str;
}
/* ------------------------------------------------------------ **
**
** Function......: ldap_exists
**
** Parameters....: ld Pointer to LDAP struct
** e Pointer to result buffer
** attr Name of desired option
** vstr Value of desired option
** cs 1 for case sensitive check
**
** Return........: 0 if value found
**
** Purpose.......: Search the LDAP result message for the
** desired (multivalue) attribute and check
** if it contains a value string.
**
** ------------------------------------------------------------ */
static int ldap_exists(LDAP *ld, LDAPMessage *e, char *attr,
char *vstr, int cs)
{
char **vals;
int count, at;
if (ld == NULL || e == NULL || attr == NULL || vstr == NULL)
misc_die(FL, "ldap_exists: ?ld? ?e? ?attr? ?vstr?");
/*
** See if this attribute has values available
*/
if ((vals = ldap_get_values(ld, e, attr)) == NULL) {
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: no values for '%.256s'", attr);
#endif
return -1;
}
count = ldap_count_values(vals);
if(cs) {
for(at=0; at < count; at++) {
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: checking[%d:%d] '%.256s'='%.1024s'",
count-1, at, attr, vals[at]);
#endif
if(misc_strequ(vals[at], vstr)) {
ldap_value_free(vals);
return 0;
}
}
} else {
for(at=0; at < count; at++) {
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: checking[%d:%d] '%.256s'='%.1024s'",
count-1, at, attr, vals[at]);
#endif
if(misc_strcaseequ(vals[at], vstr)) {
ldap_value_free(vals);
return 0;
}
}
}
ldap_value_free(vals);
#if defined(COMPILE_DEBUG)
debug(3, "LDAP result: '%.256s'='%.1024s' not found",
attr, vstr);
#endif
return 1;
}
#endif
/* ------------------------------------------------------------
* $Log: ftp-ldap.c,v $
* Revision 1.7.2.3 2004/03/10 16:07:13 mt
* added LDAPPreBindDN/LDAPPreBindPW options usable
* instead of anonymous bind while LDAPBindDN=auto
*
* Revision 1.7.2.2 2003/05/11 20:22:17 mt
* simplyfied ldap version handling
*
* Revision 1.7.2.1 2003/05/07 11:10:00 mt
* moved user profile-config reading to ftp-client.c
* added LDAP_VERSION handling with LDAPv3 default
* improved user-auth to support auth via ldap-bind
*
* Revision 1.7 2002/05/02 13:17:12 mt
* implemented simple (ldap based) user auth
*
* Revision 1.6 2002/01/14 19:26:38 mt
* implemented bind_dn and pwd authorized ldap_simple_bind
* fixed ld_errno fetching macro to work with openldap 2.x
*
* Revision 1.5 2001/11/06 23:04:44 mt
* applied / merged with transparent proxy patches v8
* see ftp-proxy/NEWS for more detailed release news
*
* Revision 1.4 1999/09/24 06:38:52 wiegand
* added regular expressions for all commands
* removed character map and length of paths
* added flag to reset PASV on every PORT
* added "magic" user with built-in destination
* added some argument pointer fortification
*
* Revision 1.3 1999/09/21 07:14:43 wiegand
* syslog / abort cleanup and review
* default PASV port range to 0:0
*
* Revision 1.2 1999/09/17 16:32:29 wiegand
* changes from source code review
* added POSIX regular expressions
*
* Revision 1.1 1999/09/15 14:06:22 wiegand
* initial checkin
*
* ------------------------------------------------------------ */
syntax highlighted by Code2HTML, v. 0.9.1