/* * $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 * Pieter Hollants * Marius Tomaschewski * Volker Wiegand * * 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 #define _GNU_SOURCE /* needed for crypt in Linux... */ #if defined(STDC_HEADERS) # include # include # include # include # include # include #endif #if defined(HAVE_UNISTD_H) # include #endif #if defined(TIME_WITH_SYS_TIME) # include # include #else # if defined(HAVE_SYS_TIME_H) # include # else # include # endif #endif #include #include #include #include #if defined(HAVE_LIBLDAP) # if defined(HAVE_LDAP_UMICH) # include # endif # include # 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 * * ------------------------------------------------------------ */