From eb07e71216a3fc19c77158f9f9670dabe3a462a1 Mon Sep 17 00:00:00 2001 From: chantra Date: Mon, 19 Jul 2010 19:52:50 +0200 Subject: [PATCH 01/44] Adding ldap user config compile depency Do not install testplugin openvpn-ldap-search test programs --- config.h.in | 3 ++ configure.in | 23 +++++++++++-- src/Makefile.am | 1 + src/la_ldap.c | 8 +++++ src/ldap_profile.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ src/ldap_profile.h | 76 +++++++++++++++++++++++++++++++++++++++++ tests/Makefile.am | 3 +- 7 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 src/ldap_profile.c create mode 100644 src/ldap_profile.h diff --git a/config.h.in b/config.h.in index 45de24d..0e4bea9 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.in by autoheader. */ +/* Enable user ldap settings */ +#undef ENABLE_LDAPUSERCONF + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H diff --git a/configure.in b/configure.in index 2f20121..e6db2a3 100644 --- a/configure.in +++ b/configure.in @@ -18,10 +18,20 @@ dnl LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CC -CFLAGS="${CFLAGS} -g -Wall -Werror -D_FILE_OFFSET_BITS=64" - +CFLAGS="${CFLAGS} -g -Wall -Werror" AC_SUBST(CFLAGS) +AC_ARG_ENABLE(ldapuserconfig, + [ --disable-ldapuserconfig, Disable user ldap settings], + [LDAP_USER_CONF="$enableval"], + [LDAP_USER_CONF="yes"] +) + +dnl enable ldapuserconfig +if test "$LDAP_USER_CONF" = "yes"; then + AC_DEFINE(ENABLE_LDAPUSERCONF, 1, [Enable user ldap settings]) +fi + AC_CHECK_HEADER([ldap.h], [AC_CHECK_LIB(ldap, [ldap_initialize])], [AC_MSG_ERROR("ldap headers not found")]) @@ -33,3 +43,12 @@ AC_CHECK_HEADER([pthread.h], AC_PROG_INSTALL AC_OUTPUT( Makefile src/Makefile tests/Makefile ) +echo " +Configuration: + + Source code location: ${srcdir} + Lib install dir: ${prefix}/lib + Compiler: ${CXX} + + LDAP user conf: ${LDAP_USER_CONF} +" diff --git a/src/Makefile.am b/src/Makefile.am index 2198a13..5b4ec7f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,7 @@ auth_ldap_SOURCES = utils.h utils.c \ list.h list.c \ action.h action.c \ la_ldap.h la_ldap.c \ + ldap_profile.h ldap_profile.c \ debug.h debug.c #openvpn_ldap_rules_SOURCES = openvpn-ldap-rules.c \ diff --git a/src/la_ldap.c b/src/la_ldap.c index a935e71..1918d05 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -28,6 +28,10 @@ #include "debug.h" #include "la_ldap.h" +#ifdef ENABLE_LDAPUSERCONF +#include "ldap_profile.h" +#endif + void ldap_context_free( ldap_context_t *l ){ if( !l ) return; @@ -322,6 +326,10 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ /* success, let set our return value to SUCCESS */ if( DODEBUG( l->verb ) ) LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); + /* TODO check if user is allowed to connect */ +#ifdef ENABLE_LDAPUSERCONF + ldap_account_load( ldap, userdn, NULL ); +#endif /* check if user belong to right groups */ if( config->groupdn && config->group_search_filter && config->member_attribute ){ rc = ldap_group_membership( ldap, l, userdn ); diff --git a/src/ldap_profile.c b/src/ldap_profile.c new file mode 100644 index 0000000..adb1eae --- /dev/null +++ b/src/ldap_profile.c @@ -0,0 +1,84 @@ +/** + * ldap_profile.c + * vim: tabstop=2 softtabstop=2 shiftwidth=2 expandtab + * Copyright (C) 2010 Emmanuel Bretelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define DODEBUG(verb) ((verb) >= 4) + +#include +#include + +#include "debug.h" +#include "ldap_profile.h" +#include "utils.h" + +ldap_profile_t * +ldap_profile_new( ){ + ldap_profile_t *l; + l = la_malloc( sizeof( ldap_profile_t ) ); + if( !l ) return NULL; + l->start_date = l->end_date = 0; + l->pf_rules = NULL; + l->config = NULL; + l->push_reset = 0; + l->iroutes = list_new( ); + l->push_options = list_new( ); + if( l->iroutes == NULL || l->push_options == NULL ){ + ldap_profile_free( l ); + return NULL; + } + return l; +} + +void +ldap_profile_free( ldap_profile_t *l ){ + if( !l ) return; + if( l->pf_rules ) la_free( l->pf_rules ); + if( l->push_options ) list_free ( l->push_options, la_free ); + if( l->iroutes ) list_free( l->iroutes, la_free ); + if( l->config ) la_free( l->config ); + la_free( l ); +} + +ldap_account_t * +ldap_account_new( ){ + ldap_account_t *l; + l = la_malloc( sizeof( ldap_account_t ) ); + if( !l ) return NULL; + l->ifconfig_push = NULL; + l->profile = ldap_profile_new( ); + + if( l->profile == NULL ){ + ldap_account_free( l ); + return NULL; + } + return l; +} + +void +ldap_account_free( ldap_account_t *l){ + if( !l ) return; + if( l->profile ) ldap_profile_free( l->profile ); + if( l->ifconfig_push ) la_free( l->ifconfig_push ); + la_free( l ); +} +int +ldap_account_load( LDAP *ldap, char *userdn, ldap_account_t *account ){ + return 0; +} diff --git a/src/ldap_profile.h b/src/ldap_profile.h new file mode 100644 index 0000000..839c305 --- /dev/null +++ b/src/ldap_profile.h @@ -0,0 +1,76 @@ +/** + * ldap_profile.h + * vim: tabstop=2 softtabstop=2 shiftwidth=2 expandtab + * Copyright (C) 2010 Emmanuel Bretelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __LDAP_PROFILE_H__ +#define __LDAP_PROFILE_H__ + +#include "cnf.h" +#include "list.h" +#include "utils.h" +#include "action.h" + +typedef struct ldap LDAP; + +typedef struct ldap_profile +{ + time_t start_date; + time_t end_date; + char *pf_rules; + list_t *push_options; + uint8_t push_reset; + list_t *iroutes; + char *config; +} ldap_profile_t; + + +typedef struct ldap_account +{ + struct ldap_profile *profile; + char *ifconfig_push; +} ldap_account_t; + +/** + * Allocate LDAP profile resources + */ +extern ldap_profile_t *ldap_profile_new( void ); + +/** + * Free LDAP profile resources + */ +extern void ldap_profile_free( ldap_profile_t *l ); + +/** + * Allocate LDAP account resouces + */ +extern ldap_account_t *ldap_account_new( void ); + +/** + * Free LDAP account resources + */ +extern void ldap_account_free( ldap_account_t *l ); + +/** + * Load user settings from LDAP + */ + +extern int ldap_account_load( LDAP *ldap, char *userdn, ldap_account_t *account ); + +#endif /* __LDAP_PROFILE_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 488ff78..2da24e8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,7 +3,7 @@ INCLUDES = -I$(top_srcdir)/src AM_LDFLAGS = -L$(top_srcdir)/src -bin_PROGRAMS = testplugin openvpn-ldap-search +noinst_PROGRAMS = testplugin openvpn-ldap-search testplugin_SOURCES = testplugin.c openvpn_ldap_search_SOURCES = openvpn-ldap-search.c @@ -13,3 +13,4 @@ ldadd = $(top_srcdir)/src/.libs/libopenvpn-ldap-auth.a testplugin_LDADD = $(ldadd) #testplugin_LDADD = -lopenvpn-ldap-auth openvpn_ldap_search_LDADD = -lopenvpn-ldap-auth + From 69238b76d90e63d79cdc31e74b3352a545eac53f Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 20 Jul 2010 11:46:20 +0200 Subject: [PATCH 02/44] Free ldap result even when operation failed From ldap_search_ext* man page: Note that res parameter of ldap_search_ext_s() and ldap_search_s() should be freed with ldap_msgfree() regardless of return value of these functions. --- src/la_ldap.c | 18 ++++++++++++++---- src/la_ldap.h | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 1918d05..6f772dc 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -79,6 +79,16 @@ auth_context_new( void ){ return a; } +/** + * la_ldap_set_timeout: + * Set a timeout according to config + */ +void +la_ldap_set_timeout( config_t *conf, struct timeval *timeout){ + timeout->tv_sec = conf->timeout; + timeout->tv_usec = 0; +} + /** * Search for a user's DN * Given a search_filter and context, will search for @@ -102,8 +112,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) config = ldap_context->config; /* initialise timeout values */ - timeout.tv_sec = config->timeout; - timeout.tv_usec = 0; + la_ldap_set_timeout( config, &timeout ); if( username && config->search_filter ){ search_filter = str_replace(config->search_filter, "%u", username ); } @@ -129,9 +138,10 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) LOGERROR( "searched returned and entry but we could not retrieve it!!!\n" ); } } - /* free the returned result */ - ldap_msgfree( result ); } + /* free the returned result */ + ldap_msgfree( result ); + if( dn ){ userdn = strdup( dn ); /* finally, if a DN was returned, free it */ diff --git a/src/la_ldap.h b/src/la_ldap.h index f27582c..00d81ac 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -73,6 +73,10 @@ extern void ldap_context_free( ldap_context_t *l ); extern ldap_context_t * ldap_context_new( void ); +/** + * Set a timeout according to config + */ +extern void la_ldap_set_timeout( config_t *conf, struct timeval *timeout); /** * handle authentication action */ From 61a504b748542ee9a86a14a81a22885777661121 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 20 Jul 2010 12:49:32 +0200 Subject: [PATCH 03/44] Some more ldap result to free --- src/la_ldap.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 6f772dc..75b70d7 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -27,6 +27,7 @@ #include "debug.h" #include "la_ldap.h" +#include "config.h" #ifdef ENABLE_LDAPUSERCONF #include "ldap_profile.h" @@ -109,6 +110,8 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) LOGERROR("ldap_find_user missing required parameter\n"); return NULL; } + + result = NULL; config = ldap_context->config; /* initialise timeout values */ @@ -140,7 +143,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) } } /* free the returned result */ - ldap_msgfree( result ); + if( result != NULL ) ldap_msgfree( result ); if( dn ){ userdn = strdup( dn ); @@ -177,8 +180,7 @@ connect_ldap( ldap_context_t *l ){ goto connect_ldap_error; } /* Timeout */ - timeout.tv_sec = config->timeout; - timeout.tv_usec = 0; + la_ldap_set_timeout( config, &timeout); rc = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout ); if( rc != LDAP_OPT_SUCCESS ){ LOGERROR( "ldap_set_option timeout %ds returned (%d) \"%s\"\n", config->timeout, rc, ldap_err2string(rc) ); @@ -255,8 +257,7 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ config = ldap_context->config; /* initialise timeout values */ - timeout.tv_sec = config->timeout; - timeout.tv_usec = 0; + la_ldap_set_timeout( config, &timeout); if( userdn && config->group_search_filter && config->member_attribute ){ search_filter = strdupf(filter,config->member_attribute, userdn, config->group_search_filter); } @@ -274,9 +275,9 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ LOGINFO( "User %s matches %d groups with filter %s\n", userdn, nbrow, search_filter ); res = 0; } - /* free the returned result */ - ldap_msgfree( result ); } + /* free the returned result */ + if ( result != NULL ) ldap_msgfree( result ); if( search_filter ) free( search_filter ); return res; } @@ -338,7 +339,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); /* TODO check if user is allowed to connect */ #ifdef ENABLE_LDAPUSERCONF - ldap_account_load( ldap, userdn, NULL ); + LOGWARNING( "ldap_account returned: %d\n", ldap_account_load( l, ldap, userdn, NULL )); #endif /* check if user belong to right groups */ if( config->groupdn && config->group_search_filter && config->member_attribute ){ From abb0393c84fdda8874e08da41be586da6b2983f0 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 20 Jul 2010 20:05:16 +0200 Subject: [PATCH 04/44] Parsing info from ldap config to structure --- src/la_ldap.c | 17 +++- src/la_ldap.h | 7 ++ src/ldap_profile.c | 219 ++++++++++++++++++++++++++++++++++++++++++++- src/ldap_profile.h | 15 +++- 4 files changed, 255 insertions(+), 3 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 75b70d7..bd80661 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -90,6 +90,16 @@ la_ldap_set_timeout( config_t *conf, struct timeval *timeout){ timeout->tv_usec = 0; } +/** + * la_ldap_errno + */ +int +la_ldap_errno( LDAP *ldap ){ + int rc; + ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &rc); + return rc; +} + /** * Search for a user's DN * Given a search_filter and context, will search for @@ -141,6 +151,8 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) LOGERROR( "searched returned and entry but we could not retrieve it!!!\n" ); } } + }else{ + LOGERROR( "ldap_search_ext_s did not succeed (%d) %s\n", rc, ldap_err2string( rc )); } /* free the returned result */ if( result != NULL ) ldap_msgfree( result ); @@ -339,7 +351,10 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); /* TODO check if user is allowed to connect */ #ifdef ENABLE_LDAPUSERCONF - LOGWARNING( "ldap_account returned: %d\n", ldap_account_load( l, ldap, userdn, NULL )); + ldap_account_t *account = ldap_account_new(); + LOGWARNING( "ldap_account returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, account )); + ldap_account_dump( account ); + ldap_account_free( account ); #endif /* check if user belong to right groups */ if( config->groupdn && config->group_search_filter && config->member_attribute ){ diff --git a/src/la_ldap.h b/src/la_ldap.h index 00d81ac..f774de8 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -27,6 +27,9 @@ #include "utils.h" #include "action.h" +/* ldap forward declaration */ +typedef struct LDAP ldap; + typedef struct ldap_context { @@ -82,4 +85,8 @@ extern void la_ldap_set_timeout( config_t *conf, struct timeval *timeout); */ extern int la_ldap_handle_authentication( ldap_context_t *l, action_t *a); +/** + * return ldap's ld_errno value + */ +extern int la_ldap_errno( LDAP *ldap ); #endif /* __LA_LDAP_H__ */ diff --git a/src/ldap_profile.c b/src/ldap_profile.c index adb1eae..862468f 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include "debug.h" #include "ldap_profile.h" @@ -56,12 +58,38 @@ ldap_profile_free( ldap_profile_t *l ){ la_free( l ); } +void +ldap_profile_dump( ldap_profile_t *l ){ + + fprintf(stdout, "Account profile:\n\ +\tstart_date:\t\t%u\n\ +\tend_date:\t\t%u\n\ +\tpf_rules:\t\t%s\n\ +\tpush_reset:\t\t%s\n\ +\tconfig:\t\t%s\n", + (unsigned int)l->start_date, (unsigned int)l->end_date, + l->pf_rules ? l->pf_rules : "None", + l->push_reset ? "TRUE" : "FALSE", + l->config ? l->config : "None"); + fprintf( stdout, "\tpush options:\n" ); + list_item_t *i; + for(i = list_first( l->push_options ); i!=NULL; i = list_item_next( i ) ){ + fprintf( stdout, "\t\t\t%s\n", i->data ? (char *)(i->data) : "None"); + } + fprintf( stdout, "\tiroutes:\n" ); + for(i = list_first( l->iroutes ); i!=NULL; i = list_item_next( i ) ){ + fprintf( stdout, "\t\t\t%s\n", i->data ? (char *)i->data : "None"); + } + +} + ldap_account_t * ldap_account_new( ){ ldap_account_t *l; l = la_malloc( sizeof( ldap_account_t ) ); if( !l ) return NULL; l->ifconfig_push = NULL; + l->profile_dn = NULL; l->profile = ldap_profile_new( ); if( l->profile == NULL ){ @@ -76,9 +104,198 @@ ldap_account_free( ldap_account_t *l){ if( !l ) return; if( l->profile ) ldap_profile_free( l->profile ); if( l->ifconfig_push ) la_free( l->ifconfig_push ); + if( l->profile_dn ) la_free( l->profile_dn ); la_free( l ); } + + +void +ldap_account_dump( ldap_account_t *l ){ + fprintf(stdout, "LDAP account dump:\n\ +\tifconfig_push:\t\t%s\n\ +\tprofile_dn:\t\t%s\n", + l->ifconfig_push ? l->ifconfig_push : "None", + l->profile_dn ? l->profile_dn : "None"); + ldap_profile_dump( l->profile ); +} +/** + * convert a LDAP GeneralizedTime string to a time_t. + * t will be set to 0 if generalized time is + * 00000000000000 or 00000101000000 and will + * return success + * Return 0 on success + */ int -ldap_account_load( LDAP *ldap, char *userdn, ldap_account_t *account ){ +la_generalizedtime_to_time(const char *s, time_t *t) +{ + struct tm tm; + + if (s == NULL) return 0; + + if( strncasecmp( s, "00000000000000", sizeof("00000000000000") -1 ) == 0 + || + strncasecmp( s, "00000101000000", sizeof("00000101000000") -1 ) == 0 ){ + *t = 0; + return 0; + } + memset(&tm, 0, sizeof(tm)); + if (sscanf(s, "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return 1; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + *t = timegm(&tm); + return 0; +} + +/** + * ldap_account_load_from_entry + * Loads profile from an LDAP message + */ +int +ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *account ){ + BerElement *berptr; + char *attr; + struct berval **vals; + int rc = 0; + int i = 0; + time_t t; + + for( attr = ldap_first_attribute( ldap, e, &berptr ); attr != NULL; attr = ldap_next_attribute( ldap, e, berptr ) ){ + vals = ldap_get_values_len( ldap, e, attr ); + if( ldap_count_values_len( vals ) < 1 ) + goto ldap_account_load_from_entry_end_loop; + if( strcasecmp( attr, "OvpnStartDate" ) == 0 && ldap_count_values_len( vals ) > 0){ + if( la_generalizedtime_to_time( vals[0]->bv_val, &t ) ){ + LOGERROR("Generalized time is not valid for OvpnStartDate"); + rc = 1; + }else{ + account->profile->start_date = t; + } + }else if( strcasecmp( attr, "OvpnEndDate" ) == 0 ){ + if( la_generalizedtime_to_time( vals[0]->bv_val, &t ) ){ + LOGERROR("Generalized time is not valid for OvpnEndDate"); + rc = 1; + }else{ + account->profile->end_date = t; + } + }else if( strcasecmp( attr, "OvpnPFRules" ) == 0 ){ + if( account->profile->pf_rules ) la_free( account->profile->pf_rules ); + account->profile->pf_rules = strdup( vals[0]->bv_val ); + }else if( strcasecmp( attr, "OvpnCCDPushOption" ) == 0 ){ + for( i = 0; vals[i]; i++){ + list_append( account->profile->push_options, (void *)strdup( vals[i]->bv_val ) ); + } + }else if( strcasecmp( attr, "OvpnCCDPushReset" ) == 0 ){ + char *boolean = vals[0]->bv_val; + if( strcasecmp( boolean, "true" ) == 0 || strcasecmp( boolean, "on" ) ) + account->profile->push_reset = 1; + }else if( strcasecmp( attr, "OvpnCCDIRoute" ) == 0 ){ + for( i = 0; vals[i]; i++){ + list_append( account->profile->iroutes, (void *) strdup( vals[i]->bv_val ) ); + } + }else if( strcasecmp( attr, "OvpnCCDConfig" ) == 0 ){ + if( account->profile->config ) la_free( account->profile->config ); + account->profile->config = strdup( vals[0]->bv_val ); + } +ldap_account_load_from_entry_end_loop: + ldap_value_free_len( vals ); + ldap_memfree( attr ); + } + /** + * ldap_first_attribute, ldap_next_attribute return NULL + * on error or end of attribute list + * we need to check out la_ldap_errno value to know + * if we exited the loop on error or success + */ + int ec; + ec = la_ldap_errno( ldap ); + if( ec != LDAP_SUCCESS){ + rc = 1; + LOGERROR( "Error retrieving attributes (%d): %s\n", ec, ldap_err2string(ec) ); + } + if( berptr != NULL ) ber_free( berptr, 0 ); + + return rc; +} + +/** + * ldap_account_load_from_dn + * Load a user config from LDAP database + * returns 0 on success, non 0 otherwise + */ +int +ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ){ + /** + * retrieve info from user settings + * if user has a profile, get info from that profile + */ + struct timeval timeout; + char *attrs[] = { NULL }; + LDAPMessage *e, *result; + config_t *config = NULL; + uint8_t is_account = 0; + int rc; + + /* if a NULL value was given for account, no action is taken */ + if( account == NULL ) + return 0; + result = NULL; + if (!ldap || !ldap_context){ + LOGERROR("ldap_account_load missing required parameter\n"); + return 1; + } + config = ldap_context->config; + la_ldap_set_timeout( config, &timeout ); + rc = ldap_search_ext_s( ldap, dn, LDAP_SCOPE_BASE, NULL, + attrs, 0,NULL, NULL, + &timeout, 2, &result ); + if( rc != LDAP_SUCCESS ){ + LOGERROR( "ldap_search_ext_s: did not succeed for dn %s, (%d): %s\n", + dn, rc, ldap_err2string( rc ) ); + ldap_msgfree( result ); + return 1; + } + int nbrow = ldap_count_entries( ldap, result ); + if( nbrow != 1 ){ + LOGERROR( "ldap_search_ext_s: returned %d results, only 1 expected\n", nbrow ); + ldap_msgfree( result ); + return 1; + } + + /** for a user account, we first check if there is a + * profile we should read data from. + * Then, we read profile data + */ + e = ldap_first_entry( ldap, result ); + if( e == NULL ){ + int ec = la_ldap_errno( ldap ); + LOGERROR( "ldap_first_entry did not succeed (%d): %s\n", ec, ldap_err2string( ec ) ); + ldap_msgfree( result ); + return 1; + } + struct berval **vals = ldap_get_values_len( ldap, e, "objectClass" ); + int i; + for( i = 0; vals[i]; i++ ){ + if( strcasecmp( vals[i]->bv_val, "OpenVPNAccount" ) == 0 ){ + is_account = 1; + break; + } + } + ldap_value_free_len( vals ); + if( is_account ){ + vals = ldap_get_values_len( ldap, e, "ovpnprofile" ); + if ( ldap_count_values_len( vals ) > 0 ){ + /** We have a profile, read profile values from DN */ + account->profile_dn = strdup( vals[0]->bv_val ); + ldap_account_load_from_dn( ldap_context, ldap, vals[0]->bv_val, account ); + } + ldap_value_free_len( vals ); + } + ldap_account_load_from_entry( ldap, e, account ); + ldap_msgfree( result ); return 0; } diff --git a/src/ldap_profile.h b/src/ldap_profile.h index 839c305..84a70ed 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -26,6 +26,8 @@ #include "list.h" #include "utils.h" #include "action.h" +#include "la_ldap.h" + typedef struct ldap LDAP; @@ -44,6 +46,7 @@ typedef struct ldap_profile typedef struct ldap_account { struct ldap_profile *profile; + char *profile_dn; char *ifconfig_push; } ldap_account_t; @@ -57,6 +60,11 @@ extern ldap_profile_t *ldap_profile_new( void ); */ extern void ldap_profile_free( ldap_profile_t *l ); +/** + * Print LDAP profile config to stdout + */ +extern void ldap_profile_dump( ldap_profile_t *l ); + /** * Allocate LDAP account resouces */ @@ -67,10 +75,15 @@ extern ldap_account_t *ldap_account_new( void ); */ extern void ldap_account_free( ldap_account_t *l ); +/** + * Print LDAP account config to stdout + */ +extern void ldap_account_dump( ldap_account_t *l ); /** * Load user settings from LDAP + * returns 0 on success, non 0 otherwise */ -extern int ldap_account_load( LDAP *ldap, char *userdn, ldap_account_t *account ); +extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ); #endif /* __LDAP_PROFILE_H__ */ From b18ee3b4eacdf26775cdf9f9bc303c890392fd91 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 22 Jul 2010 04:16:05 +0200 Subject: [PATCH 05/44] Reads info from LDAP backend, pushes it to openvpn PF rules are written to pf_file options available through ccd files are pushes through OPENVPN_PLUGIN_CLIENT_CONNECT_V2 's return_list --- src/Makefile.am | 1 + src/action.h | 1 + src/client_context.c | 55 +++++++++++++++++++++++++ src/client_context.h | 48 ++++++++++++++++++++++ src/la_ldap.c | 46 +++++++++++++++++++-- src/la_ldap.h | 3 +- src/ldap-auth.c | 98 ++++++++++++++++++++++++++++++++++++-------- src/ldap_profile.c | 51 +++++++++++++++++++++++ src/ldap_profile.h | 7 +++- src/utils.c | 42 +++++++++++++++++-- src/utils.h | 6 +++ tests/testplugin.c | 17 ++++---- 12 files changed, 340 insertions(+), 35 deletions(-) create mode 100644 src/client_context.c create mode 100644 src/client_context.h diff --git a/src/Makefile.am b/src/Makefile.am index 5b4ec7f..8d038ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ auth_ldap_SOURCES = utils.h utils.c \ action.h action.c \ la_ldap.h la_ldap.c \ ldap_profile.h ldap_profile.c \ + client_context.h client_context.c \ debug.h debug.c #openvpn_ldap_rules_SOURCES = openvpn-ldap-rules.c \ diff --git a/src/action.h b/src/action.h index 579d2d2..a04670e 100644 --- a/src/action.h +++ b/src/action.h @@ -31,6 +31,7 @@ enum ldap_auth_action { typedef struct action{ enum ldap_auth_action type; void *context; + void *client_context; /*this should not be freed, openvpn plugin call will take care of it */ void (*context_free_func)( void *data ); } action_t; diff --git a/src/client_context.c b/src/client_context.c new file mode 100644 index 0000000..850ab93 --- /dev/null +++ b/src/client_context.c @@ -0,0 +1,55 @@ +/** + * vim: tabstop=2:shiftwidth=2:softtabstop=2:expandtab + * client_context.c + * + * Copyright (C) 2010 Emmanuel Bretelle + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "client_context.h" +#include "utils.h" + +#ifdef ENABLE_LDAPUSERCONF +#include "ldap_profile.h" +#endif + + +struct client_context * +client_context_new (void) { + struct client_context *cc; + cc = la_malloc (sizeof (struct client_context)); + if (cc) + la_memset (cc, 0, sizeof (struct client_context)); +#ifdef ENABLE_LDAPUSERCONF + if( ( cc->ldap_account = ldap_account_new( ) ) == NULL ){ + client_context_free( cc ); + cc = NULL; + } +#endif + return cc; +} +void +client_context_free (struct client_context *cc) { + if (cc == NULL) + return; + FREE_IF_NOT_NULL (cc->user_id); +#ifdef ENABLE_LDAPUSERCONF + if( cc->ldap_account != NULL ) ldap_account_free( cc->ldap_account ); +#endif + FREE_IF_NOT_NULL (cc); +} + diff --git a/src/client_context.h b/src/client_context.h new file mode 100644 index 0000000..306af78 --- /dev/null +++ b/src/client_context.h @@ -0,0 +1,48 @@ +/** + * vim: tabstop=2:shiftwidth=2:softtabstop=2:expandtab + * client_context.h + * + * Copyright (C) 2010 Emmanuel Bretelle + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _CLIENT_CONTEXT_H_ +#define _CLIENT_CONTEXT_H_ + +#include "config.h" + + +typedef struct client_context { + char *user_id; +#ifdef ENABLE_LDAPUSERCONF + struct ldap_account *ldap_account; +#endif +} client_context_t; + + +/** + * Initialize a new client context structure + */ +extern struct client_context *client_context_new (void); +/** + * Free a client context structure + */ +extern void client_context_free (struct client_context * cc); + + +#endif + diff --git a/src/la_ldap.c b/src/la_ldap.c index bd80661..2538148 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -27,12 +27,41 @@ #include "debug.h" #include "la_ldap.h" +#include "client_context.h" #include "config.h" #ifdef ENABLE_LDAPUSERCONF #include "ldap_profile.h" #endif +#include +#include +#include +#include +/* write a value to auth_control_file */ +int +write_to_pf_file( char *pf_file, char *value ) +{ + int fd, rc; + fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); + if( fd == -1 ){ + LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + return -1; + } + rc = write( fd, value, strlen(value) ); + if( rc == -1 ){ + LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); + }else if( rc !=1 ){ + LOGERROR( "Could not write value %s to file %s\n", value, pf_file ); + } + rc = close( fd ); + if( rc != 0 ){ + LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + } + return rc == 0; +} + + void ldap_context_free( ldap_context_t *l ){ if( !l ) return; @@ -67,6 +96,7 @@ auth_context_free( auth_context_t *a ){ if( a->username ) free( a->username ); if( a->password ) free( a->password ); if( a->auth_control_file ) free( a->auth_control_file ); + FREE_IF_NOT_NULL( a->pf_file ); free( a ); return; } @@ -100,6 +130,8 @@ la_ldap_errno( LDAP *ldap ){ return rc; } + + /** * Search for a user's DN * Given a search_filter and context, will search for @@ -300,6 +332,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LDAP *ldap = NULL; config_t *config = l->config; auth_context_t *auth_context = a->context; + client_context_t *client_context = a->client_context; char *userdn = NULL; int rc; int res = OPENVPN_PLUGIN_FUNC_ERROR; @@ -351,10 +384,15 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); /* TODO check if user is allowed to connect */ #ifdef ENABLE_LDAPUSERCONF - ldap_account_t *account = ldap_account_new(); - LOGWARNING( "ldap_account returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, account )); - ldap_account_dump( account ); - ldap_account_free( account ); + LOGWARNING( "ldap_account returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); + /* TODO check if user timeframe is allowed start_date, end_date */ + /* write to pf_file */ + if( client_context->ldap_account->profile->pf_rules && auth_context->pf_file ){ + write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); + }else{ + /* set up default pf_rules */ + } + /* ldap_account_dump( client_context->ldap_account ); */ #endif /* check if user belong to right groups */ if( config->groupdn && config->group_search_filter && config->member_attribute ){ diff --git a/src/la_ldap.h b/src/la_ldap.h index f774de8..43ff66b 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -28,7 +28,7 @@ #include "action.h" /* ldap forward declaration */ -typedef struct LDAP ldap; +typedef struct ldap LDAP; typedef struct ldap_context { @@ -53,6 +53,7 @@ typedef struct auth_context char *username; char *password; char *auth_control_file; + char *pf_file; } auth_context_t; /** diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 28f0047..f0d37e0 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -47,12 +47,15 @@ #include +#include "config.h" #include "cnf.h" #include "utils.h" #include "debug.h" #include "action.h" #include "list.h" #include "la_ldap.h" +#include "client_context.h" +#include "ldap_profile.h" #define DODEBUG(verb) ((verb) >= 4) @@ -78,6 +81,21 @@ action_push( list_t *list, action_t *action) } pthread_mutex_unlock( &action_mutex ); } + +action_t * +action_pop (list_t *l){ + action_t *a = NULL; + pthread_mutex_lock (&action_mutex); + if (list_length (l) == 0){ + pthread_cond_wait (&action_cond, &action_mutex); + } + /* get the action item */ + a = list_remove_item_at (l, 0); + pthread_mutex_unlock (&action_mutex); + return a; +} + + /* * Name/Value pairs for conversation function. * Special Values: @@ -185,7 +203,7 @@ daemonize (const char *envp[]) #endif OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list) { ldap_context_t *context; @@ -245,6 +263,12 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char } } +#ifdef ENABLE_LDAPUSERCONF + /* when ldap userconf is define, we need to hook onto those callbacks */ + *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) + | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) + | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); +#endif /** * Parse configuration file is -c filename is provided */ @@ -329,7 +353,12 @@ write_to_auth_control_file( char *auth_control_file, char value ) OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, + const int type, + const char *argv[], + const char *envp[], + void *per_client_context, + struct openvpn_plugin_string_list **return_list) { ldap_context_t *context = (ldap_context_t *) handle; auth_context_t *auth_context = NULL; @@ -340,12 +369,15 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch config_t *config = context->config; int rc; int res = OPENVPN_PLUGIN_FUNC_ERROR; - /* get username/password/auth_control_file from envp string array */ - const char *username = get_env ("username", envp); - const char *password = get_env ("password", envp); - const char *auth_control_file = get_env ( "auth_control_file", envp ); if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY){ + /* get username/password/auth_control_file from envp string array */ + const char *username = get_env ("username", envp); + const char *password = get_env ("password", envp); + const char *auth_control_file = get_env ( "auth_control_file", envp ); + const char *pf_file = get_env ("pf_file", envp); + + /* required parameters check */ if (!username){ @@ -360,6 +392,7 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch } if( username ) auth_context->username = strdup( username ); if( password ) auth_context->password = strdup( password ); + if( pf_file ) auth_context->pf_file = strdup( pf_file ); if( auth_control_file ) auth_context->auth_control_file = strdup( auth_control_file ); /* If some argument were missing or could not be duplicate */ if( !(auth_context->username && auth_context->password && auth_context->auth_control_file ) ){ @@ -369,12 +402,40 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch action = action_new( ); action->type = LDAP_AUTH_ACTION_AUTH; action->context = auth_context; + action->client_context = per_client_context; action->context_free_func = auth_context_free; action_push( context->action_list, action ); return OPENVPN_PLUGIN_FUNC_DEFERRED; } - +#ifdef ENABLE_LDAPUSERCONF + else if (type == OPENVPN_PLUGIN_ENABLE_PF){ + /* unfortunately, at this stage we dont know anything about the client + * yet. Let assume it is enabled, we will define default somewhere + */ + return OPENVPN_PLUGIN_FUNC_SUCCESS; + }else if( type == OPENVPN_PLUGIN_CLIENT_CONNECT_V2 ){ + /* on client connect, we return conf options through return list + */ + client_context_t *cc = per_client_context; + ldap_account_t *a = cc->ldap_account; + char *ccd_options = ldap_account_get_options_to_string( cc->ldap_account ); + if( ccd_options ){ + *return_list = la_malloc( sizeof( struct openvpn_plugin_string_list ) ); + if( *return_list != NULL){ + (*return_list)->next = NULL; + (*return_list)->name = strdup( "config" ); + (*return_list)->value = ccd_options; + } + } + return OPENVPN_PLUGIN_FUNC_SUCCESS; + }else if( type == OPENVPN_PLUGIN_CLIENT_DISCONNECT ){ + /* nothing done for now + * potentially, session could be logged + */ + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } +#endif return res; } @@ -442,16 +503,7 @@ action_thread_main_loop (void *c) int loop = 1; while( loop ){ - pthread_mutex_lock (&action_mutex); - if (list_length (context->action_list) == 0){ - pthread_cond_wait (&action_cond, &action_mutex); - if (DODEBUG (context->verb) ){ - LOGINFO( "Signal received, there is some action!\n"); - } - } - /* get the action item */ - action = list_remove_item_at (context->action_list, 0); - pthread_mutex_unlock (&action_mutex); + action = action_pop(context->action_list); /* TODO, do some action */ if (action){ switch (action->type){ @@ -487,3 +539,15 @@ action_thread_main_loop (void *c) } pthread_exit (NULL); } + +OPENVPN_EXPORT void * +openvpn_plugin_client_constructor_v1( openvpn_plugin_handle_t handle){ + client_context_t *cc = client_context_new( ); + return (void *)cc; +} + +OPENVPN_EXPORT void +openvpn_plugin_client_destructor_v1( openvpn_plugin_handle_t handle, void *per_client_context ){ + client_context_t *cc = per_client_context; + client_context_free( cc ); +} diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 862468f..980ff49 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -299,3 +299,54 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, l ldap_msgfree( result ); return 0; } + +/** + * ldap_account_get_options_to_string + * returns NULL is no option is to be pushed + */ + +char * +ldap_account_get_options_to_string( ldap_account_t *account ){ + + uint8_t tot_size = 0; + list_item_t *elem = NULL; + char *res = NULL; + if (account->profile->push_reset) + tot_size += sizeof("push-reset\n"); + if (account->ifconfig_push) + tot_size += sizeof("ifconfig \n") + strlen(account->ifconfig_push); + + if ( list_length (account->profile->iroutes) > 0 ) + for(elem = list_first( account->profile->iroutes ); elem; elem = list_item_next( elem ) ){ + tot_size += sizeof("iroute \n") + strlen( (char *)elem->data ); + } + + if ( list_length (account->profile->push_options) > 0 ) + for(elem = list_first( account->profile->push_options ); elem; elem = list_item_next( elem ) ){ + tot_size += sizeof("push \"\"\n") + strlen( (char *)elem->data ); + } + + if ( tot_size == 0 ) + return NULL; + + tot_size += 1; + res = la_malloc( tot_size ); + la_memset( res, 0, tot_size); + + if (account->profile->push_reset) + strcat( res, "push-reset\n"); + if (account->ifconfig_push) + strcatf( res, "ifconfig %s\n", account->ifconfig_push ); + + if ( list_length (account->profile->iroutes) > 0 ) + for(elem = list_first( account->profile->iroutes ); elem; elem = list_item_next( elem ) ){ + strcatf( res, "iroute %s\n", (char *)elem->data ); + } + + if ( list_length (account->profile->push_options) > 0 ) + for(elem = list_first( account->profile->push_options ); elem; elem = list_item_next( elem ) ){ + strcatf( res, "push \"%s\"\n", (char *)elem->data ); + } + + return res; +} diff --git a/src/ldap_profile.h b/src/ldap_profile.h index 84a70ed..c3fa6ee 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -29,8 +29,6 @@ #include "la_ldap.h" -typedef struct ldap LDAP; - typedef struct ldap_profile { time_t start_date; @@ -86,4 +84,9 @@ extern void ldap_account_dump( ldap_account_t *l ); extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ); +/** + * Returns a string that is suitable to pass options to openvpn + */ + +extern char *ldap_account_get_options_to_string( ldap_account_t *account ); #endif /* __LDAP_PROFILE_H__ */ diff --git a/src/utils.c b/src/utils.c index 7f845f2..06bf3cd 100644 --- a/src/utils.c +++ b/src/utils.c @@ -43,18 +43,18 @@ la_memset( void *s, int c, size_t n ){ return memset( s, c, n ); } +/** + * same as stdup but given a va_list + */ char * -strdupf (const char *fmt, ...){ - va_list vargs; +vstrdupf (const char *fmt, va_list vargs){ char buf[BUFSIZ]; char *p; if (!fmt) { return (NULL); } - va_start (vargs, fmt); vsnprintf (buf, sizeof (buf), fmt, vargs); - va_end (vargs); buf[sizeof (buf) - 1] = '\0'; /* ensure buf is NUL-terminated */ @@ -64,6 +64,40 @@ strdupf (const char *fmt, ...){ return (p); } + +char * +strdupf (const char *fmt, ...){ + va_list vargs; + char *p; + + if (!fmt) { + return (NULL); + } + va_start (vargs, fmt); + p = vstrdupf (fmt, vargs); + va_end (vargs); + + return p; +} + +char * +strcatf( char *dest, const char *fmt, ...){ + va_list vargs; + char *p; + if (!fmt) { + return dest; + } + va_start (vargs, fmt); + p = vstrdupf( fmt, vargs ); + va_end (vargs); + + if(p){ + strcat( dest, p ); + la_free( p ); + } + return dest; +} + char * str_replace( const char *string, const char *substr, const char *replacement ){ char *tok = NULL; diff --git a/src/utils.h b/src/utils.h index 566f3d7..a61bd40 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,6 +24,7 @@ #define _UTILS_H_ #include +#define FREE_IF_NOT_NULL(a) if (a != NULL) la_free (a) /* memory allocation */ extern void *la_malloc( size_t size ); @@ -37,7 +38,12 @@ extern void *la_memset( void *s, int c, size_t n ); */ extern char *strdupf (const char *fmt, ...); +/* + * Same as strcat but providing a format-string + * returns a pointer to dest as strcat + */ +extern char *strcatf( char *dest, const char *fmt, ...); /* * Create a new string with [substr] being replaced by [replacement] in [string] * Returns the new string, or NULL if out of memory. diff --git a/tests/testplugin.c b/tests/testplugin.c index 063bb49..d7b4aff 100644 --- a/tests/testplugin.c +++ b/tests/testplugin.c @@ -46,7 +46,8 @@ const char username_template[] = "username="; const char password_template[] = "password="; - +void *client_context = NULL; +struct openvpn_plugin_string_list *return_list = NULL; int main(int argc, const char *argv[]) { openvpn_plugin_handle_t handle; @@ -90,14 +91,15 @@ int main(int argc, const char *argv[]) { envp[4] = "auth_control_file=/tmp/foobar_ctrl_file.txt"; envp[5] = NULL; - handle = openvpn_plugin_open_v1(&type, argv, envp); + handle = openvpn_plugin_open_v2(&type, argv, envp, NULL); if (!handle) errx(1, "Initialization Failed!\n"); /* Authenticate */ for( ; loops; --loops ){ - err = openvpn_plugin_func_v1(handle, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, argv, envp); + client_context = openvpn_plugin_client_constructor_v1( handle ); + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, argv, envp, client_context, NULL); if (err == OPENVPN_PLUGIN_FUNC_ERROR) { printf("Authorization Failed!\n"); } else if( err == OPENVPN_PLUGIN_FUNC_SUCCESS ) { @@ -108,9 +110,9 @@ int main(int argc, const char *argv[]) { } printf( "Sleeping %d seconds to let the threads do some job...\n", SLEEP_TIME ); sleep( SLEEP_TIME ); - goto free_exit; + //goto free_exit; /* Client Connect */ - err = openvpn_plugin_func_v1(handle, OPENVPN_PLUGIN_CLIENT_CONNECT, argv, envp); + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, argv, envp, client_context, &return_list); if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { printf("client-connect failed!\n"); } else { @@ -118,13 +120,14 @@ int main(int argc, const char *argv[]) { } /* Client Disconnect */ - err = openvpn_plugin_func_v1(handle, OPENVPN_PLUGIN_CLIENT_DISCONNECT, argv, envp); + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_DISCONNECT, argv, envp, client_context, NULL); if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { printf("client-disconnect failed!\n"); } else { printf("client-disconnect succeed!\n"); } -free_exit: +//free_exit: + openvpn_plugin_client_destructor_v1( handle, client_context ); sprintf(command, "lsof -n -p %d", pid); //system(command); openvpn_plugin_close_v1(handle); From 6bbbabbbe9a9d06dffba34ad947e1c92a883bc33 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 22 Jul 2010 07:34:55 +0200 Subject: [PATCH 06/44] Removed trailing spaces --- configure.in | 2 +- src/la_ldap.c | 4 ++-- src/la_ldap.h | 2 +- src/ldap-auth.c | 2 +- src/ldap_profile.c | 24 ++++++++++++------------ src/ldap_profile.h | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/configure.in b/configure.in index e6db2a3..e603e99 100644 --- a/configure.in +++ b/configure.in @@ -29,7 +29,7 @@ AC_ARG_ENABLE(ldapuserconfig, dnl enable ldapuserconfig if test "$LDAP_USER_CONF" = "yes"; then - AC_DEFINE(ENABLE_LDAPUSERCONF, 1, [Enable user ldap settings]) + AC_DEFINE(ENABLE_LDAPUSERCONF, 1, [Enable user ldap settings]) fi AC_CHECK_HEADER([ldap.h], diff --git a/src/la_ldap.c b/src/la_ldap.c index 2538148..dfb4b5b 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -96,7 +96,7 @@ auth_context_free( auth_context_t *a ){ if( a->username ) free( a->username ); if( a->password ) free( a->password ); if( a->auth_control_file ) free( a->auth_control_file ); - FREE_IF_NOT_NULL( a->pf_file ); + FREE_IF_NOT_NULL( a->pf_file ); free( a ); return; } @@ -388,7 +388,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ /* TODO check if user timeframe is allowed start_date, end_date */ /* write to pf_file */ if( client_context->ldap_account->profile->pf_rules && auth_context->pf_file ){ - write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); + write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); }else{ /* set up default pf_rules */ } diff --git a/src/la_ldap.h b/src/la_ldap.h index 43ff66b..0dcb0ad 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -89,5 +89,5 @@ extern int la_ldap_handle_authentication( ldap_context_t *l, action_t *a); /** * return ldap's ld_errno value */ -extern int la_ldap_errno( LDAP *ldap ); +extern int la_ldap_errno( LDAP *ldap ); #endif /* __LA_LDAP_H__ */ diff --git a/src/ldap-auth.c b/src/ldap-auth.c index f0d37e0..b312bf6 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -543,7 +543,7 @@ action_thread_main_loop (void *c) OPENVPN_EXPORT void * openvpn_plugin_client_constructor_v1( openvpn_plugin_handle_t handle){ client_context_t *cc = client_context_new( ); - return (void *)cc; + return (void *)cc; } OPENVPN_EXPORT void diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 980ff49..5bbf146 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -66,7 +66,7 @@ ldap_profile_dump( ldap_profile_t *l ){ \tend_date:\t\t%u\n\ \tpf_rules:\t\t%s\n\ \tpush_reset:\t\t%s\n\ -\tconfig:\t\t%s\n", +\tconfig:\t\t%s\n", (unsigned int)l->start_date, (unsigned int)l->end_date, l->pf_rules ? l->pf_rules : "None", l->push_reset ? "TRUE" : "FALSE", @@ -129,7 +129,7 @@ int la_generalizedtime_to_time(const char *s, time_t *t) { struct tm tm; - + if (s == NULL) return 0; if( strncasecmp( s, "00000000000000", sizeof("00000000000000") -1 ) == 0 @@ -139,14 +139,14 @@ la_generalizedtime_to_time(const char *s, time_t *t) return 0; } memset(&tm, 0, sizeof(tm)); - if (sscanf(s, "%04u%02u%02u%02u%02u%02u", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + if (sscanf(s, "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { return 1; } tm.tm_year -= 1900; tm.tm_mon -= 1; - + *t = timegm(&tm); return 0; } @@ -210,7 +210,7 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun * on error or end of attribute list * we need to check out la_ldap_errno value to know * if we exited the loop on error or success - */ + */ int ec; ec = la_ldap_errno( ldap ); if( ec != LDAP_SUCCESS){ @@ -254,19 +254,19 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, l attrs, 0,NULL, NULL, &timeout, 2, &result ); if( rc != LDAP_SUCCESS ){ - LOGERROR( "ldap_search_ext_s: did not succeed for dn %s, (%d): %s\n", - dn, rc, ldap_err2string( rc ) ); + LOGERROR( "ldap_search_ext_s: did not succeed for dn %s, (%d): %s\n", + dn, rc, ldap_err2string( rc ) ); ldap_msgfree( result ); return 1; } - int nbrow = ldap_count_entries( ldap, result ); + int nbrow = ldap_count_entries( ldap, result ); if( nbrow != 1 ){ LOGERROR( "ldap_search_ext_s: returned %d results, only 1 expected\n", nbrow ); ldap_msgfree( result ); return 1; } - /** for a user account, we first check if there is a + /** for a user account, we first check if there is a * profile we should read data from. * Then, we read profile data */ @@ -332,12 +332,12 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ tot_size += 1; res = la_malloc( tot_size ); la_memset( res, 0, tot_size); - + if (account->profile->push_reset) strcat( res, "push-reset\n"); if (account->ifconfig_push) strcatf( res, "ifconfig %s\n", account->ifconfig_push ); - + if ( list_length (account->profile->iroutes) > 0 ) for(elem = list_first( account->profile->iroutes ); elem; elem = list_item_next( elem ) ){ strcatf( res, "iroute %s\n", (char *)elem->data ); diff --git a/src/ldap_profile.h b/src/ldap_profile.h index c3fa6ee..7f9b6d2 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -48,7 +48,7 @@ typedef struct ldap_account char *ifconfig_push; } ldap_account_t; -/** +/** * Allocate LDAP profile resources */ extern ldap_profile_t *ldap_profile_new( void ); @@ -83,7 +83,7 @@ extern void ldap_account_dump( ldap_account_t *l ); */ extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ); - + /** * Returns a string that is suitable to pass options to openvpn */ From f7ead775ccb0cecb68660339fe3884122d6f7e0c Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 27 Jul 2010 20:39:08 +0200 Subject: [PATCH 07/44] Adding multiple profile in config Can now authenticate different profiles from different sources. If no pf_rules are found, it will accept everything --- src/client_context.c | 1 + src/client_context.h | 3 + src/cnf.c | 305 +++++++++++++++++++++++++++--------- src/cnf.h | 45 +++++- src/debug.h | 2 + src/la_ldap.c | 122 ++++++++++----- src/ldap-auth.c | 14 +- src/ldap_profile.c | 28 +++- src/utils.h | 15 ++ tests/openvpn-ldap-search.c | 38 ++--- 10 files changed, 417 insertions(+), 156 deletions(-) diff --git a/src/client_context.c b/src/client_context.c index 850ab93..c88e7c2 100644 --- a/src/client_context.c +++ b/src/client_context.c @@ -47,6 +47,7 @@ client_context_free (struct client_context *cc) { if (cc == NULL) return; FREE_IF_NOT_NULL (cc->user_id); + FREE_IF_NOT_NULL (cc->user_dn); #ifdef ENABLE_LDAPUSERCONF if( cc->ldap_account != NULL ) ldap_account_free( cc->ldap_account ); #endif diff --git a/src/client_context.h b/src/client_context.h index 306af78..3bda100 100644 --- a/src/client_context.h +++ b/src/client_context.h @@ -24,10 +24,13 @@ #define _CLIENT_CONTEXT_H_ #include "config.h" +#include "cnf.h" typedef struct client_context { char *user_id; + char *user_dn; + profile_config_t *profile; #ifdef ENABLE_LDAPUSERCONF struct ldap_account *ldap_account; #endif diff --git a/src/cnf.c b/src/cnf.c index cc18c88..13ab4a2 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -20,9 +20,12 @@ */ #include "cnf.h" +#include "utils.h" #include "defines.h" +#include "debug.h" #include #include +#include #include #include #include @@ -34,84 +37,100 @@ //#define STRDUP_IFNOTSET_NOTNULL(a, b) if( b ) STRDUP_IFNOTSET(a,b) void check_and_free( void *d ){ - if( d ) free( d ); + if( d ) la_free( d ); } void config_set_default( config_t *c){ #ifdef OURI - if(OURI) STRDUP_IFNOTSET(c->uri, OURI ); + if(OURI) STRDUP_IFNOTSET(c->ldap->uri, OURI ); #endif #ifdef OBASEDN - STRDUP_IFNOTSET(c->basedn, OBASEDN ); + STRDUP_IFNOTSET(c->profile->basedn, OBASEDN ); #endif #ifdef OBINDDN - STRDUP_IFNOTSET(c->binddn, OBINDDN ); + STRDUP_IFNOTSET(c->ldap->binddn, OBINDDN ); #endif #ifdef OBINDPW - STRDUP_IFNOTSET(c->bindpw, OBINDPW); + STRDUP_IFNOTSET(c->ldap->bindpw, OBINDPW); #endif - if(!c->ldap_version) c->ldap_version = OLDAP_VERSION; + if(!c->ldap->ldap_version) c->ldap->ldap_version = OLDAP_VERSION; #ifdef OSEARCH_FILTER - STRDUP_IFNOTSET(c->search_filter, OSEARCH_FILTER ); + STRDUP_IFNOTSET(c->profile->search_filter, OSEARCH_FILTER ); #endif #ifdef OSSL - STRDUP_IFNOTSET(c->ssl, OSSL ); + STRDUP_IFNOTSET(c->ldap->ssl, OSSL ); #endif #ifdef OTLS_CACERTFILE - STRDUP_IFNOTSET(c->tls_cacertfile, OTLS_CACERTFILE ); + STRDUP_IFNOTSET(c->ldap->tls_cacertfile, OTLS_CACERTFILE ); #endif #ifdef OTLS_CACERTDIR - STRDUP_IFNOTSET(c->tls_cacertdir, OTLS_CACERTDIR ); + STRDUP_IFNOTSET(c->ldap->tls_cacertdir, OTLS_CACERTDIR ); #endif #ifdef OTLS_CERTFILE - STRDUP_IFNOTSET(c->tls_certfile, OTLS_CERTFILE ); + STRDUP_IFNOTSET(c->ldap->tls_certfile, OTLS_CERTFILE ); #endif #ifdef OTLS_CERTKEY - STRDUP_IFNOTSET(c->tls_certkey, OTLS_CERTKEY ); + STRDUP_IFNOTSET(c->ldap->tls_certkey, OTLS_CERTKEY ); #endif #ifdef OTLS_CIPHERSUITE - STRDUP_IFNOTSET(c->tls_ciphersuite, OTLS_CIPHERSUITE ); + STRDUP_IFNOTSET(c->ldap->tls_ciphersuite, OTLS_CIPHERSUITE ); #endif #ifdef OTLS_REQCERT - STRDUP_IFNOTSET(c->tls_reqcert, OTLS_REQCERT ); + STRDUP_IFNOTSET(c->ldap->tls_reqcert, OTLS_REQCERT ); #endif #ifdef OTIMEOUT - if( !c->timeout ) c->timeout = OTIMEOUT; + if( !c->ldap->timeout ) c->ldap->timeout = OTIMEOUT; #endif #ifdef OGROUPDN - STRDUP_IFNOTSET(c->groupdn, OGROUPDN ); + STRDUP_IFNOTSET(c->profile->groupdn, OGROUPDN ); #endif #ifdef OGROUP_SEARCH_FILTER - STRDUP_IFNOTSET(c->group_search_filter, OGROUP_SEARCH_FILTER ); + STRDUP_IFNOTSET(c->profile->group_search_filter, OGROUP_SEARCH_FILTER ); #endif #ifdef OMEMBER_ATRIBUTE - STRDUP_IFNOTSET(c->member_attribute, OMEMBER_ATRIBUTE ); + STRDUP_IFNOTSET(c->profile->member_attribute, OMEMBER_ATRIBUTE ); #endif } -config_t * -config_new( void ){ - config_t *c = malloc( sizeof( config_t ) ); - if( !c ) return NULL; - memset( c, 0, sizeof( config_t ) ); - return c; +/** + * ldap config + */ +void +ldap_config_free( ldap_config_t *c ){ + check_and_free( c->uri ); + check_and_free( c->binddn ); + check_and_free( c->bindpw ); + /* TLS */ + check_and_free( c->ssl ); + check_and_free( c->tls_cacertfile ); + check_and_free( c->tls_cacertdir ); + check_and_free( c->tls_certfile ); + check_and_free( c->tls_certkey ); + check_and_free( c->tls_ciphersuite ); + check_and_free( c->tls_reqcert ); + la_free( c ); } -config_t * -config_dup( config_t *c ){ - config_t *nc = NULL; +ldap_config_t * +ldap_config_new( void ){ + ldap_config_t *c = la_malloc( sizeof( ldap_config_t ) ); if( !c ) return NULL; - nc = config_new( ); - if( !nc ) return NULL; + la_memset (c, 0, sizeof( ldap_config_t ) ); + return c; +} + +ldap_config_t * +ldap_config_dup( const ldap_config_t *c ){ + ldap_config_t *nc = ldap_config_new( ); + if( !nc) + return NULL; if( c->uri ) nc->uri = strdup( c->uri ); if( c->binddn ) nc->binddn = strdup( c->binddn ); if( c->bindpw ) nc->bindpw = strdup( c->bindpw ); - if( c->basedn ) nc->basedn = strdup( c->basedn ); nc->ldap_version = c->ldap_version; - if( c->search_filter ) nc->search_filter = strdup( c->search_filter ); if( c->ssl ) nc->ssl = strdup( c->ssl ); if( c->tls_cacertfile ) nc->tls_cacertfile = strdup( c->tls_cacertfile ); if( c->tls_cacertdir ) nc->tls_cacertdir = strdup( c->tls_cacertdir ); @@ -121,35 +140,109 @@ config_dup( config_t *c ){ if( c->tls_reqcert ) nc->tls_reqcert = strdup( c->tls_reqcert ); nc->timeout = c->timeout; - - if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); - if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); - if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); - return nc; + return nc; } +/** + * profile + */ void -config_free( config_t *c ){ - if( !c ) return; - check_and_free( c->uri ); - check_and_free( c->binddn ); - check_and_free( c->bindpw ); +profile_config_free ( profile_config_t *c ){ + if( !c ) + return; + check_and_free( c->basedn ); check_and_free( c->search_filter ); - /* TLS */ - check_and_free( c->ssl ); - check_and_free( c->tls_cacertfile ); - check_and_free( c->tls_cacertdir ); - check_and_free( c->tls_certfile ); - check_and_free( c->tls_certkey ); - check_and_free( c->tls_ciphersuite ); - check_and_free( c->tls_reqcert ); /* Group */ check_and_free( c->groupdn ); check_and_free( c->group_search_filter ); check_and_free( c->member_attribute ); - free( c ); + la_free( c ); +} + +void +profile_config_list_free_cb( void *data ){ + profile_config_t *c = data; + profile_config_free( c ); +} +profile_config_t * +profile_config_new ( void ){ + profile_config_t *c = la_malloc( sizeof( profile_config_t ) ); + if( !c ) return NULL; + la_memset (c, 0, sizeof( profile_config_t ) ); + return c; +} + +profile_config_t * +profile_config_dup( const profile_config_t *c ){ + profile_config_t *nc = NULL; + + nc = profile_config_new( ); + if( nc == NULL ) + return NULL; + + if( c->basedn ) nc->basedn = strdup( c->basedn ); + if( c->search_filter ) nc->search_filter = strdup( c->search_filter ); + nc->search_scope = c->search_scope; + if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); + if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); + if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); + + return nc; +} + +/** + * config + */ +config_t * +config_new( void ){ + config_t *c = malloc( sizeof( config_t ) ); + if( !c ) return NULL; + memset( c, 0, sizeof( config_t ) ); + + c->ldap = ldap_config_new( ); + c->profile = profile_config_new( ); + c->profiles = list_new( ); + + if( !(c->profiles && c->profile && c->ldap) ){ + config_free( c ); + return NULL; + } + return c; +} + +config_t * +config_dup( config_t *c ){ + config_t *nc = NULL; + profile_config_t *pgc = NULL; + list_item_t *item = NULL; + + if( !c ) return NULL; + nc = config_new( ); + if( !nc ) return NULL; + + pgc = profile_config_dup( c->profile ); + + profile_config_free( nc->profile ); + nc->profile = pgc; + + for( item = list_first(c->profiles); item; item = item->next ){ + pgc = profile_config_dup( item->data ); + list_append( nc->profiles, pgc ); + } + + return nc; +} + + +void +config_free( config_t *c ){ + if( !c ) return; + profile_config_free( c->profile ); + ldap_config_free( c->ldap ); + list_free( c->profiles, profile_config_list_free_cb ); + la_free( c ); } char * @@ -180,49 +273,88 @@ config_parse_file( const char *filename, config_t *c ){ int fd; char *line; char *arg,*val; + int in_profile = 0; + int rc = 0; + profile_config_t *p = NULL; fd = open( filename, O_RDONLY ); if( fd == -1 ){ + LOGERROR( "Could not open file %s: (%d) %s\n", filename, errno, strerror( errno ) ); return 1; } val = NULL; while ( ( line = f_readline( fd ) ) ){ + if( line[0] == '#' || line[0] == ';' ){ + free(line); + continue; + } + if( !strncmp( line, "", strlen( "" ) ) ){ + in_profile = 1; + p = profile_config_new( ); + free(line); + if( p == NULL ){ + LOGERROR( "Could not allocate memory for new profile\n" ); + rc = 1; + break; + } + list_append( c->profiles, p ); + continue; + } + if( !strncmp( line, "", strlen( "" ) ) ){ + in_profile = 0; + p = NULL; + free(line); + continue; + } + profile_config_t *current_profile = in_profile ? p : c->profile; arg = strtok( line, "=" ); if(arg && *arg != '\n'){ val = strtok( NULL, "\n"); + /* global conf -> ldap */ if( !strcmp( arg, "uri" ) ){ - STRDUP_IFNOTSET(c->uri, val ); + STRDUP_IFNOTSET(c->ldap->uri, val ); } else if ( !strcmp( arg, "binddn" ) ) { - STRDUP_IFNOTSET(c->binddn, val ); + STRDUP_IFNOTSET(c->ldap->binddn, val ); }else if ( !strcmp( arg, "bindpw" ) ) { - STRDUP_IFNOTSET(c->bindpw, val ); - }else if ( !strcmp( arg, "basedn" ) ){ - STRDUP_IFNOTSET(c->basedn, val ); + STRDUP_IFNOTSET(c->ldap->bindpw, val ); }else if ( !strcmp( arg, "ldap_version" ) ){ - if(!c->ldap_version) c->ldap_version = atoi(val); - }else if ( !strcmp( arg, "search_filter" ) ){ - STRDUP_IFNOTSET(c->search_filter, val ); + if(!c->ldap->ldap_version) c->ldap->ldap_version = atoi(val); }else if ( !strcmp( arg, "ssl" ) ){ - STRDUP_IFNOTSET(c->ssl, val ); + STRDUP_IFNOTSET(c->ldap->ssl, val ); }else if ( !strcmp( arg, "tls_cacertfile" ) ){ - STRDUP_IFNOTSET(c->tls_cacertfile, val ); + STRDUP_IFNOTSET(c->ldap->tls_cacertfile, val ); }else if ( !strcmp( arg, "tls_cacertdir" ) ){ - STRDUP_IFNOTSET(c->tls_cacertdir, val ); + STRDUP_IFNOTSET(c->ldap->tls_cacertdir, val ); }else if ( !strcmp( arg, "tls_certfile" ) ){ - STRDUP_IFNOTSET(c->tls_certfile, val ); + STRDUP_IFNOTSET(c->ldap->tls_certfile, val ); }else if ( !strcmp( arg, "tls_certkey" ) ){ - STRDUP_IFNOTSET(c->tls_certkey, val ); + STRDUP_IFNOTSET(c->ldap->tls_certkey, val ); }else if ( !strcmp( arg, "tls_ciphersuite" ) ){ - STRDUP_IFNOTSET(c->tls_ciphersuite, val ); + STRDUP_IFNOTSET(c->ldap->tls_ciphersuite, val ); }else if ( !strcmp( arg, "tls_reqcert" ) ){ - STRDUP_IFNOTSET(c->tls_reqcert, val ); + STRDUP_IFNOTSET(c->ldap->tls_reqcert, val ); }else if( !strcmp( arg, "timeout" ) ){ - if( !c->timeout ) c->timeout = atoi(val); + if( !c->ldap->timeout ) c->ldap->timeout = atoi(val); + /* global conf */ + }else if ( !strcmp( arg, "basedn" ) ){ + STRDUP_IFNOTSET(current_profile->basedn, val ); + }else if ( !strcmp( arg, "search_filter" ) ){ + STRDUP_IFNOTSET(current_profile->search_filter, val ); + }else if ( !strcmp( arg, "search_scope" ) ){ + if( !strcasecmp( val, "LDAP_SCOPE_BASE" ) ){ + current_profile->search_scope = LA_SCOPE_BASE; + }else if( !strcasecmp( val, "LDAP_SCOPE_ONELEVEL" ) ){ + current_profile->search_scope = LA_SCOPE_ONELEVEL; + }else if( !strcasecmp( val, "LDAP_SCOPE_SUBTREE" ) ){ + current_profile->search_scope = LA_SCOPE_SUBTREE; + } }else if( !strcmp( arg, "groupdn" ) ){ - STRDUP_IFNOTSET(c->groupdn, val ); + STRDUP_IFNOTSET(current_profile->groupdn, val ); }else if( !strcmp( arg, "group_search_filter" ) ){ - STRDUP_IFNOTSET(c->group_search_filter, val ); + STRDUP_IFNOTSET(c->profile->group_search_filter, val ); }else if( !strcmp( arg, "member_attribute" ) ){ - STRDUP_IFNOTSET(c->member_attribute, val ); + STRDUP_IFNOTSET(c->profile->member_attribute, val ); + }else{ + LOGWARNING("Unrecognized option *%s=%s*\n", arg, val); } } @@ -234,12 +366,33 @@ config_parse_file( const char *filename, config_t *c ){ void config_dump( config_t *c){ - STRPRINT_IFSET(c->uri,"URI"); - STRPRINT_IFSET(c->basedn, "BaseDN"); - STRPRINT_IFSET(c->binddn,"BindDN"); - STRPRINT_IFSET(c->groupdn,"GroupDN"); - STRPRINT_IFSET(c->group_search_filter, "Group Search Filter"); - STRPRINT_IFSET(c->member_attribute,"Member Attribute"); - /* STRPRINT_IFSET(c->bindpw,"BindPW"); */ + fprintf( stderr, "Config Dump:\n*LDAP:*\n"); + STRPRINT_IFSET(c->ldap->uri,"\tURI"); + STRPRINT_IFSET(c->ldap->binddn,"\tBindDN"); + fprintf( stderr, "\tSSL:\t%s\n", c->ldap->ssl ); + fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->ldap_version ); + fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); + fprintf( stderr, "*Default Profile:*\n" ); + STRPRINT_IFSET(c->profile->basedn, "\tBaseDN"); + fprintf( stderr, "\tSearch Scope:\t%d\n", c->profile->search_scope ); + fprintf( stderr, "\tSearch filter:\t%s\n", c->profile->search_filter ); + STRPRINT_IFSET(c->profile->groupdn,"\tGroupDN"); + STRPRINT_IFSET(c->profile->group_search_filter, "\tGroup Search Filter"); + STRPRINT_IFSET(c->profile->member_attribute,"\tMember Attribute"); + STRPRINT_IFSET(c->profile->profiledn,"\tProfile DN"); /* TODO finish dumping info */ + list_item_t *item; + profile_config_t *p; + for( item = list_first( c->profiles ); item; item = item->next){ + p = item->data; + fprintf( stderr, "*Custom Profile:*\n" ); + STRPRINT_IFSET(p->basedn, "\tBaseDN"); + fprintf( stderr, "\tSearch Scope:\t%d\n", p->search_scope ); + fprintf( stderr, "\tSearch filter:\t%s\n", p->search_filter ); + STRPRINT_IFSET(p->groupdn,"\tGroupDN"); + STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); + STRPRINT_IFSET(p->member_attribute,"\tMember Attribute"); + STRPRINT_IFSET(p->profiledn,"\tProfile DN"); + + } } diff --git a/src/cnf.h b/src/cnf.h index 700013b..6c3bca7 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -22,17 +22,29 @@ #ifndef _CNF_H_ #define _CNF_H_ -typedef struct config{ +#include "list.h" + + +typedef enum ldap_search_scope{ + LA_SCOPE_BASE = 0, + LA_SCOPE_ONELEVEL, + LA_SCOPE_SUBTREE +} ldap_search_scope_t; +/** + * ldap_config + * defines how to connect to an ldap server + */ + +typedef struct ldap_config{ char *uri; char *binddn; char *bindpw; - char *basedn; int ldap_version; + int timeout; - char *search_filter; - + /* TLS/SSL */ char *ssl; char *tls_cacertfile; char *tls_cacertdir; @@ -41,11 +53,28 @@ typedef struct config{ char *tls_ciphersuite; char *tls_reqcert; - int timeout; + +} ldap_config_t; + +typedef struct profile_config{ + char *basedn; + char *search_filter; + ldap_search_scope_t search_scope; /* group membership */ - char *groupdn; - char *group_search_filter; - char *member_attribute; + char *groupdn; + char *group_search_filter; + char *member_attribute; + char *profiledn; +} profile_config_t; + +/** + * config hold a reference to global_config + * and the different profiles to use + */ +typedef struct config{ + ldap_config_t *ldap; + profile_config_t *profile; + list_t *profiles; } config_t; extern int config_parse_file( const char *filename, config_t *c ); diff --git a/src/debug.h b/src/debug.h index 36ad83b..f83d649 100644 --- a/src/debug.h +++ b/src/debug.h @@ -48,5 +48,7 @@ void _log( const char *level, const char *fmt, ... ); #define LOGINFO( fmt, args... ) _log( "INFO", fmt, ##args ) +#define LOGDEBUG( fmt, args... ) _log( "DEBUG", fmt, ##args ) + #endif /* _DEBUG_H_ */ diff --git a/src/la_ldap.c b/src/la_ldap.c index dfb4b5b..2d15d29 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -38,11 +38,16 @@ #include #include #include -/* write a value to auth_control_file */ +/* write a value to pf_file */ int write_to_pf_file( char *pf_file, char *value ) { int fd, rc; + if( pf_file == NULL ){ + LOGERROR( "pf_file is null\n"); + return -1; + } + fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); if( fd == -1 ){ LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); @@ -51,8 +56,8 @@ write_to_pf_file( char *pf_file, char *value ) rc = write( fd, value, strlen(value) ); if( rc == -1 ){ LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); - }else if( rc !=1 ){ - LOGERROR( "Could not write value %s to file %s\n", value, pf_file ); + }else if( rc !=strlen(value) ){ + LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); } rc = close( fd ); if( rc != 0 ){ @@ -116,7 +121,7 @@ auth_context_new( void ){ */ void la_ldap_set_timeout( config_t *conf, struct timeval *timeout){ - timeout->tv_sec = conf->timeout; + timeout->tv_sec = conf->ldap->timeout; timeout->tv_usec = 0; } @@ -131,40 +136,37 @@ la_ldap_errno( LDAP *ldap ){ } - -/** - * Search for a user's DN - * Given a search_filter and context, will search for - */ char * -ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ){ +ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char *username, profile_config_t *p){ + char *userdn = NULL; struct timeval timeout; char *attrs[] = { NULL }; char *dn = NULL; LDAPMessage *e, *result; config_t *config = NULL; - char *search_filter = NULL; int rc; - char *userdn = NULL; + char *search_filter = NULL; + int ldap_scope = 0; - /* arguments sanity check */ - if( !ldap_context || !username || !ldap){ - LOGERROR("ldap_find_user missing required parameter\n"); - return NULL; - } result = NULL; config = ldap_context->config; - + /* initialise timeout values */ la_ldap_set_timeout( config, &timeout ); - if( username && config->search_filter ){ - search_filter = str_replace(config->search_filter, "%u", username ); + + if( username && config->profile->search_filter ){ + search_filter = str_replace(config->profile->search_filter, "%u", username ); } if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, config->basedn ); - - rc = ldap_search_ext_s( ldap, config->basedn, LDAP_SCOPE_ONELEVEL, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); + LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, p->basedn ); + if( p->search_scope == LA_SCOPE_BASE ) + ldap_scope = LDAP_SCOPE_BASE; + else if( p->search_scope == LA_SCOPE_ONELEVEL ) + ldap_scope = LDAP_SCOPE_ONELEVEL; + else if( p->search_scope == LA_SCOPE_SUBTREE ) + ldap_scope = LDAP_SCOPE_SUBTREE; + rc = ldap_search_ext_s( ldap, p->basedn, ldap_scope, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ int nbrow = ldap_count_entries( ldap, result ); @@ -196,6 +198,49 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username ) } if( search_filter ) free( search_filter ); return userdn; + +} +/** + * Search for a user's DN + * Given a search_filter and context, will search for + */ +char * +ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, client_context_t *cc ){ + config_t *config = NULL; + char *userdn = NULL; + profile_config_t *p = NULL; + list_item_t *item = NULL; + + cc->profile = NULL; + + /* arguments sanity check */ + if( !ldap_context || !username || !ldap){ + LOGERROR("ldap_find_user missing required parameter\n"); + return NULL; + } + + config = ldap_context->config; + + if( list_length( config->profiles ) == 0 ){ + p = config->profile; + userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); + if( userdn ){ + cc->user_dn = strdup( userdn ); + cc->profile = p; + } + }else{ + for( item = list_first( config->profiles ); item; item = item->next ){ + p = item->data; + userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); + if( userdn ){ + cc->user_dn = strdup( userdn ); + cc->profile = p; + break; + } + } + } + + return userdn; } @@ -212,26 +257,26 @@ connect_ldap( ldap_context_t *l ){ struct timeval timeout; /* init connection to ldap */ - rc = ldap_initialize(&ldap, config->uri); + rc = ldap_initialize(&ldap, config->ldap->uri); if( rc!= LDAP_SUCCESS ){ LOGERROR( "ldap_initialize returned (%d) \"%s\" : %s\n", rc, ldap_err2string(rc), strerror(errno) ); goto connect_ldap_error; } /* Version */ - rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap_version)); + rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->ldap_version)); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"\n", config->ldap_version, rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"\n", config->ldap->ldap_version, rc, ldap_err2string(rc) ); goto connect_ldap_error; } /* Timeout */ la_ldap_set_timeout( config, &timeout); rc = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout ); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option timeout %ds returned (%d) \"%s\"\n", config->timeout, rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option timeout %ds returned (%d) \"%s\"\n", config->ldap->timeout, rc, ldap_err2string(rc) ); goto connect_ldap_error; } /* SSL/TLS */ - if( strcmp( config->ssl, "start_tls" ) == 0){ + if( strcmp( config->ldap->ssl, "start_tls" ) == 0){ /*TODO handle certif properly */ ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); @@ -302,13 +347,13 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ /* initialise timeout values */ la_ldap_set_timeout( config, &timeout); - if( userdn && config->group_search_filter && config->member_attribute ){ - search_filter = strdupf(filter,config->member_attribute, userdn, config->group_search_filter); + if( userdn && config->profile->group_search_filter && config->profile->member_attribute ){ + search_filter = strdupf(filter,config->profile->member_attribute, userdn, config->profile->group_search_filter); } if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, config->groupdn ); + LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, config->profile->groupdn ); - rc = ldap_search_ext_s( ldap, config->groupdn, LDAP_SCOPE_ONELEVEL, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); + rc = ldap_search_ext_s( ldap, config->profile->groupdn, LDAP_SCOPE_ONELEVEL, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ int nbrow = ldap_count_entries( ldap, result ); @@ -340,15 +385,15 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ /* Connection to LDAP backend */ ldap = connect_ldap( l ); if( ldap == NULL ){ - LOGERROR( "Could not connect to URI %s\n", config->uri ); + LOGERROR( "Could not connect to URI %s\n", config->ldap->uri ); goto la_ldap_handle_authentication_exit; } /* bind to LDAP server anonymous or authenticated */ - rc = ldap_binddn( ldap, config->binddn, config->bindpw ); + rc = ldap_binddn( ldap, config->ldap->binddn, config->ldap->bindpw ); switch( rc ){ case LDAP_SUCCESS: if( DODEBUG( l->verb ) ) - LOGINFO( "ldap_sasl_bind_s %s success\n", config->binddn ? config->binddn : "Anonymous" ); + LOGINFO( "ldap_sasl_bind_s %s success\n", config->ldap->binddn ? config->ldap->binddn : "Anonymous" ); break; case LDAP_INVALID_CREDENTIALS: LOGERROR( "ldap_binddn: Invalid Credentials\n" ); @@ -358,13 +403,12 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ goto la_ldap_handle_authentication_free; } - userdn = ldap_find_user( ldap, l, auth_context->username ); + userdn = ldap_find_user( ldap, l, auth_context->username, client_context ); if( !userdn ){ LOGWARNING( "LDAP user *%s* was not found \n", auth_context->username ); goto la_ldap_handle_authentication_free; } - /* OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY */ if (auth_context && l->config ){ if (auth_context->username && strlen (auth_context->username) > 0 && auth_context->password){ /** TODO authenticate user */ @@ -382,7 +426,6 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ /* success, let set our return value to SUCCESS */ if( DODEBUG( l->verb ) ) LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); - /* TODO check if user is allowed to connect */ #ifdef ENABLE_LDAPUSERCONF LOGWARNING( "ldap_account returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); /* TODO check if user timeframe is allowed start_date, end_date */ @@ -391,11 +434,12 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); }else{ /* set up default pf_rules */ + write_to_pf_file( auth_context->pf_file, "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n"); } /* ldap_account_dump( client_context->ldap_account ); */ #endif /* check if user belong to right groups */ - if( config->groupdn && config->group_search_filter && config->member_attribute ){ + if( config->profile->groupdn && config->profile->group_search_filter && config->profile->member_attribute ){ rc = ldap_group_membership( ldap, l, userdn ); if( rc == 0 ){ res = OPENVPN_PLUGIN_FUNC_SUCCESS; diff --git a/src/ldap-auth.c b/src/ldap-auth.c index b312bf6..464198a 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -227,29 +227,29 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:b:f:t:WZ" ) ) != - 1 ){ switch( rc ) { case 'H': - context->config->uri = strdup(optarg); + context->config->ldap->uri = strdup(optarg); break; case 'b': - context->config->basedn = strdup(optarg); + context->config->profile->basedn = strdup(optarg); break; case 'f': - context->config->search_filter = strdup(optarg); + context->config->profile->search_filter = strdup(optarg); break; case 'Z': - context->config->ssl = strdup("start_tls"); + context->config->ldap->ssl = strdup("start_tls"); break; case 'D': - context->config->binddn = strdup(optarg); + context->config->ldap->binddn = strdup(optarg); break; case 'W': - context->config->bindpw = get_passwd("BindPW Password: "); + context->config->ldap->bindpw = get_passwd("BindPW Password: "); //printdebug( "Password is %s: length: %d\n", config->bindpw, strlen(config->bindpw) ); break; case 'c': configfile = optarg; break; case 't': - context->config->timeout = atoi( optarg ); + context->config->ldap->timeout = atoi( optarg ); break; case '?': fprintf( stderr, "LDAP-AUTH: Unknown Option -%c !!\n", optopt ); diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 5bbf146..7edb36f 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -163,11 +163,14 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun int rc = 0; int i = 0; time_t t; + int ec; for( attr = ldap_first_attribute( ldap, e, &berptr ); attr != NULL; attr = ldap_next_attribute( ldap, e, berptr ) ){ vals = ldap_get_values_len( ldap, e, attr ); + printf("attribute: %s: %d\n", attr, ldap_count_values_len( vals )); if( ldap_count_values_len( vals ) < 1 ) goto ldap_account_load_from_entry_end_loop; + if( strcasecmp( attr, "OvpnStartDate" ) == 0 && ldap_count_values_len( vals ) > 0){ if( la_generalizedtime_to_time( vals[0]->bv_val, &t ) ){ LOGERROR("Generalized time is not valid for OvpnStartDate"); @@ -211,7 +214,6 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun * we need to check out la_ldap_errno value to know * if we exited the loop on error or success */ - int ec; ec = la_ldap_errno( ldap ); if( ec != LDAP_SUCCESS){ rc = 1; @@ -287,13 +289,25 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, l } ldap_value_free_len( vals ); if( is_account ){ - vals = ldap_get_values_len( ldap, e, "ovpnprofile" ); - if ( ldap_count_values_len( vals ) > 0 ){ - /** We have a profile, read profile values from DN */ - account->profile_dn = strdup( vals[0]->bv_val ); - ldap_account_load_from_dn( ldap_context, ldap, vals[0]->bv_val, account ); + if( account->profile_dn ){ + la_free( account->profile_dn ); + account->profile_dn = NULL; + } + if( ( vals = ldap_get_values_len( ldap, e, "ovpnprofile" ) ) ){ + if ( ldap_count_values_len( vals ) > 0 ){ + /** We have a profile, read profile values from DN */ + account->profile_dn = strdup( vals[0]->bv_val ); + } + ldap_value_free_len( vals ); + + if( account->profile_dn ){ + ldap_account_load_from_dn( ldap_context, ldap, account->profile_dn, account ); + } + }else{ + /* reset ld_errno */ + int ec = LDAP_SUCCESS; + ldap_set_option( ldap, LDAP_OPT_ERROR_NUMBER, &ec ); } - ldap_value_free_len( vals ); } ldap_account_load_from_entry( ldap, e, account ); ldap_msgfree( result ); diff --git a/src/utils.h b/src/utils.h index a61bd40..10feefe 100644 --- a/src/utils.h +++ b/src/utils.h @@ -26,6 +26,21 @@ #include #define FREE_IF_NOT_NULL(a) if (a != NULL) la_free (a) +/* bool definitions */ +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#define BOOL_CAST(x) ((x) ? (true) : (false)) + /* memory allocation */ extern void *la_malloc( size_t size ); extern void la_free( void *ptr ); diff --git a/tests/openvpn-ldap-search.c b/tests/openvpn-ldap-search.c index 609cba8..3438de0 100644 --- a/tests/openvpn-ldap-search.c +++ b/tests/openvpn-ldap-search.c @@ -74,23 +74,23 @@ main( int argc, char **argv){ usage( argv[0] ); return 0; case 'H': - config->uri = strdup(optarg); + config->ldap->uri = strdup(optarg); break; case 'b': - config->basedn = strdup(optarg); + config->profile->basedn = strdup(optarg); break; case 'f': - config->search_filter = strdup(optarg); + config->profile->search_filter = strdup(optarg); break; case 'Z': - config->ssl = strdup("start_tls"); + config->ldap->ssl = strdup("start_tls"); break; case 'D': - config->binddn = strdup(optarg); + config->ldap->binddn = strdup(optarg); break; case 'W': - config->bindpw = get_passwd("Password: "); - printdebug( "Password is %s: length: %d\n", config->bindpw, strlen(config->bindpw) ); + config->ldap->bindpw = get_passwd("Password: "); + printdebug( "Password is %s: length: %d\n", config->ldap->bindpw, strlen(config->ldap->bindpw) ); break; case 'd': debug = 1; @@ -115,19 +115,19 @@ main( int argc, char **argv){ if( configfile ) config_parse_file( configfile, config ); config_set_default( config ); config_dump( config ); - rc = ldap_initialize(&ldap, config->uri); + rc = ldap_initialize(&ldap, config->ldap->uri); if( rc!= LDAP_SUCCESS ){ ERROR( "ERROR: ldap_initialize returned (%d) \"%s\" : %s\n", rc, ldap_err2string(rc), strerror(errno) ); return 1; } - rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap_version)); + rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->ldap_version)); if( rc != LDAP_OPT_SUCCESS ){ ERROR( "ERROR: ldap_set_option returned (%d) \"%s\"\n", rc, ldap_err2string(rc) ); return 1; } - if( strcmp( config->ssl, "start_tls" ) == 0){ + if( strcmp( config->ldap->ssl, "start_tls" ) == 0){ ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); if( rc != LDAP_OPT_SUCCESS ){ @@ -140,16 +140,16 @@ main( int argc, char **argv){ return 2; } } - if( config->bindpw && strlen(config->bindpw) ){ - bv.bv_len = strlen(config->bindpw); - bv.bv_val = config->bindpw; + if( config->ldap->bindpw && strlen(config->ldap->bindpw) ){ + bv.bv_len = strlen(config->ldap->bindpw); + bv.bv_val = config->ldap->bindpw; }else{ bv.bv_len = 0; bv.bv_val = NULL; } - printdebug("Connecting with user %s\n", config->binddn); + printdebug("Connecting with user %s\n", config->ldap->binddn); - rc = ldap_sasl_bind_s( ldap, config->binddn, LDAP_SASL_SIMPLE, &bv, NULL, NULL, &bv2); + rc = ldap_sasl_bind_s( ldap, config->ldap->binddn, LDAP_SASL_SIMPLE, &bv, NULL, NULL, &bv2); switch( rc ){ case LDAP_SUCCESS: break; @@ -180,11 +180,11 @@ main( int argc, char **argv){ BerElement *ber; struct berval **vals; char *dn; - if( username && config->search_filter ){ - filter = str_replace(config->search_filter, "%u", username ); + if( username && config->profile->search_filter ){ + filter = str_replace(config->profile->search_filter, "%u", username ); } - printdebug("search Filter %s\nFinal filter: %s\n",config->search_filter, filter); - rc = ldap_search_ext_s( ldap, config->basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); + printdebug("search Filter %s\nFinal filter: %s\n",config->profile->search_filter, filter); + rc = ldap_search_ext_s( ldap, config->profile->basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ fprintf(stdout, "Search returned success\n"); e = ldap_first_entry( ldap, result ); From affe49f9c0ecaa49a1ad8c83b440480064748d7d Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 28 Jul 2010 18:49:14 +0200 Subject: [PATCH 08/44] Enable PF at config level. Use start/end date PF must be enabled at config level with: enable_pf=true When ldap account profile start_date and/or end_date are different than 0, check if user is allowed to connect at current date. --- src/cnf.c | 4 ++++ src/cnf.h | 1 + src/la_ldap.c | 26 ++++++++++++++++++++------ src/ldap-auth.c | 14 ++++++++------ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index 13ab4a2..b9b3f19 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -204,6 +204,7 @@ config_new( void ){ c->ldap = ldap_config_new( ); c->profile = profile_config_new( ); c->profiles = list_new( ); + c->enable_pf = 0; if( !(c->profiles && c->profile && c->ldap) ){ config_free( c ); @@ -226,6 +227,7 @@ config_dup( config_t *c ){ profile_config_free( nc->profile ); nc->profile = pgc; + nc->enable_pf = c->enable_pf; for( item = list_first(c->profiles); item; item = item->next ){ pgc = profile_config_dup( item->data ); @@ -335,6 +337,8 @@ config_parse_file( const char *filename, config_t *c ){ }else if( !strcmp( arg, "timeout" ) ){ if( !c->ldap->timeout ) c->ldap->timeout = atoi(val); /* global conf */ + }else if( !strcmp( arg, "enable_pf" ) ){ + c->enable_pf = !(strcasecmp( val, "true") && strcasecmp( val, "on" ) && strcasecmp( val, "1")) ? 1 : 0; }else if ( !strcmp( arg, "basedn" ) ){ STRDUP_IFNOTSET(current_profile->basedn, val ); }else if ( !strcmp( arg, "search_filter" ) ){ diff --git a/src/cnf.h b/src/cnf.h index 6c3bca7..887a893 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -75,6 +75,7 @@ typedef struct config{ ldap_config_t *ldap; profile_config_t *profile; list_t *profiles; + int enable_pf; } config_t; extern int config_parse_file( const char *filename, config_t *c ); diff --git a/src/la_ldap.c b/src/la_ldap.c index 2d15d29..e7fdbd9 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -32,6 +32,7 @@ #ifdef ENABLE_LDAPUSERCONF #include "ldap_profile.h" +#include "time.h" #endif #include @@ -427,14 +428,27 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ if( DODEBUG( l->verb ) ) LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); #ifdef ENABLE_LDAPUSERCONF - LOGWARNING( "ldap_account returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); + time_t now = time(NULL); + LOGWARNING( "ldap_account_load_from_dn returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); /* TODO check if user timeframe is allowed start_date, end_date */ - /* write to pf_file */ - if( client_context->ldap_account->profile->pf_rules && auth_context->pf_file ){ - write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); + if( ( client_context->ldap_account->profile->start_date == 0 || client_context->ldap_account->profile->start_date < now ) + && + ( client_context->ldap_account->profile->end_date == 0 || client_context->ldap_account->profile->end_date > now ) ){ + LOGINFO("user time period: %d/%d is allowed to connect at %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date, now); }else{ - /* set up default pf_rules */ - write_to_pf_file( auth_context->pf_file, "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n"); + LOGINFO("user time period: %d/%d is not allowed to connect at %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date, now); + res = OPENVPN_PLUGIN_FUNC_ERROR; + goto la_ldap_handle_authentication_free; + } + LOGDEBUG("start date; %d. end date: %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date); + /* write to pf_file */ + if( config->enable_pf ){ + if( client_context->ldap_account->profile->pf_rules && auth_context->pf_file ){ + write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); + }else{ + /* set up default pf_rules */ + write_to_pf_file( auth_context->pf_file, "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n"); + } } /* ldap_account_dump( client_context->ldap_account ); */ #endif diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 464198a..f8b23ef 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -263,12 +263,6 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char } } -#ifdef ENABLE_LDAPUSERCONF - /* when ldap userconf is define, we need to hook onto those callbacks */ - *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) - | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) - | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); -#endif /** * Parse configuration file is -c filename is provided */ @@ -282,6 +276,14 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char * Get verbosity level from environment */ +#ifdef ENABLE_LDAPUSERCONF + /* when ldap userconf is define, we need to hook onto those callbacks */ + *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) + | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT); + if( context->config->enable_pf ) + *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); +#endif + const char *verb_string = get_env ("verb", envp); if (verb_string) context->verb = atoi (verb_string); From abd5370a1a8fb7e8210961c0ac7508723147ac7f Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 28 Jul 2010 19:09:02 +0200 Subject: [PATCH 09/44] Renaming testplugin to openvpn-ldap-auth-test Install openvpn-ldap-auth-test on make install --- .gitignore | 1 + tests/Makefile.am | 7 ++++--- tests/{testplugin.c => openvpn-ldap-auth-test.c} | 0 3 files changed, 5 insertions(+), 3 deletions(-) rename tests/{testplugin.c => openvpn-ldap-auth-test.c} (100%) diff --git a/.gitignore b/.gitignore index a9240b5..5acee29 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .*.swp *~ openvpn-ldap-search +openvpn-ldap-auth-test m4 depcomp install-sh diff --git a/tests/Makefile.am b/tests/Makefile.am index 2da24e8..8627a25 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,14 +3,15 @@ INCLUDES = -I$(top_srcdir)/src AM_LDFLAGS = -L$(top_srcdir)/src -noinst_PROGRAMS = testplugin openvpn-ldap-search +noinst_PROGRAMS = openvpn-ldap-search +bin_PROGRAMS = openvpn-ldap-auth-test -testplugin_SOURCES = testplugin.c +openvpn_ldap_auth_test_SOURCES = openvpn-ldap-auth-test.c openvpn_ldap_search_SOURCES = openvpn-ldap-search.c ldadd = $(top_srcdir)/src/.libs/libopenvpn-ldap-auth.a -testplugin_LDADD = $(ldadd) +openvpn_ldap_auth_test_LDADD = $(ldadd) #testplugin_LDADD = -lopenvpn-ldap-auth openvpn_ldap_search_LDADD = -lopenvpn-ldap-auth diff --git a/tests/testplugin.c b/tests/openvpn-ldap-auth-test.c similarity index 100% rename from tests/testplugin.c rename to tests/openvpn-ldap-auth-test.c From 50ecf25459c4fc740fbac2c91c5fdb8f0d76fae4 Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 28 Jul 2010 20:37:04 +0200 Subject: [PATCH 10/44] make enable_pf a ternary value Allow to define undef/false/true to be able to handle PF at profile level add src/types.h add helpers in cnf.h * int config_is_pf_enabled( config_t *c ) * config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ) --- src/cnf.c | 30 +++++++++++++++++++++++++++--- src/cnf.h | 10 +++++++--- src/la_ldap.c | 49 ++++++++++++++++++++++++++++++++++++++----------- src/ldap-auth.c | 5 +++-- src/types.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 17 +---------------- 6 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 src/types.h diff --git a/src/cnf.c b/src/cnf.c index b9b3f19..24b7b15 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -188,6 +188,7 @@ profile_config_dup( const profile_config_t *c ){ if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); + nc->enable_pf = c->enable_pf; return nc; } @@ -204,7 +205,6 @@ config_new( void ){ c->ldap = ldap_config_new( ); c->profile = profile_config_new( ); c->profiles = list_new( ); - c->enable_pf = 0; if( !(c->profiles && c->profile && c->ldap) ){ config_free( c ); @@ -227,7 +227,6 @@ config_dup( config_t *c ){ profile_config_free( nc->profile ); nc->profile = pgc; - nc->enable_pf = c->enable_pf; for( item = list_first(c->profiles); item; item = item->next ){ pgc = profile_config_dup( item->data ); @@ -338,7 +337,7 @@ config_parse_file( const char *filename, config_t *c ){ if( !c->ldap->timeout ) c->ldap->timeout = atoi(val); /* global conf */ }else if( !strcmp( arg, "enable_pf" ) ){ - c->enable_pf = !(strcasecmp( val, "true") && strcasecmp( val, "on" ) && strcasecmp( val, "1")) ? 1 : 0; + current_profile->enable_pf = !(strcasecmp( val, "true") && strcasecmp( val, "on" ) && strcasecmp( val, "1")) ? TERN_TRUE : TERN_FALSE; }else if ( !strcmp( arg, "basedn" ) ){ STRDUP_IFNOTSET(current_profile->basedn, val ); }else if ( !strcmp( arg, "search_filter" ) ){ @@ -378,6 +377,7 @@ config_dump( config_t *c){ fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); fprintf( stderr, "*Default Profile:*\n" ); STRPRINT_IFSET(c->profile->basedn, "\tBaseDN"); + fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(c->profile->enable_pf)); fprintf( stderr, "\tSearch Scope:\t%d\n", c->profile->search_scope ); fprintf( stderr, "\tSearch filter:\t%s\n", c->profile->search_filter ); STRPRINT_IFSET(c->profile->groupdn,"\tGroupDN"); @@ -391,6 +391,7 @@ config_dump( config_t *c){ p = item->data; fprintf( stderr, "*Custom Profile:*\n" ); STRPRINT_IFSET(p->basedn, "\tBaseDN"); + fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); fprintf( stderr, "\tSearch Scope:\t%d\n", p->search_scope ); fprintf( stderr, "\tSearch filter:\t%s\n", p->search_filter ); STRPRINT_IFSET(p->groupdn,"\tGroupDN"); @@ -400,3 +401,26 @@ config_dump( config_t *c){ } } + +int +config_is_pf_enabled( config_t *c ){ + int enabled = 0; + list_item_t *item; + if( c->profile->enable_pf == TERN_TRUE ) + return 1; + + for( item = list_first( c->profiles ); item; item = item->next ){ + profile_config_t *pc = item->data; + if( pc->enable_pf == TERN_TRUE ){ + enabled = 1; + break; + } + } + return enabled; +} +int +config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ){ + return (c->profile->enable_pf != TERN_TRUE && p->enable_pf == TERN_TRUE) + || + ( c->profile->enable_pf == TERN_TRUE && p->enable_pf != TERN_FALSE); +} diff --git a/src/cnf.h b/src/cnf.h index 887a893..ab5a842 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -23,6 +23,7 @@ #define _CNF_H_ #include "list.h" +#include "types.h" typedef enum ldap_search_scope{ @@ -65,6 +66,7 @@ typedef struct profile_config{ char *group_search_filter; char *member_attribute; char *profiledn; + ternary_t enable_pf; } profile_config_t; /** @@ -75,7 +77,6 @@ typedef struct config{ ldap_config_t *ldap; profile_config_t *profile; list_t *profiles; - int enable_pf; } config_t; extern int config_parse_file( const char *filename, config_t *c ); @@ -83,6 +84,9 @@ extern int config_parse_file( const char *filename, config_t *c ); extern config_t *config_new( void ); extern config_t *config_dup( config_t *c ); extern void config_free( config_t *c ); -extern void config_dump( config_t *c); -extern void config_set_default( config_t *c); +extern void config_dump( config_t *c ); +extern void config_set_default( config_t *c ); + +extern int config_is_pf_enabled( config_t *c ); +extern int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ); #endif /* _CNF_H_ */ diff --git a/src/la_ldap.c b/src/la_ldap.c index e7fdbd9..f82f797 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -39,6 +39,9 @@ #include #include #include + +#define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" + /* write a value to pf_file */ int write_to_pf_file( char *pf_file, char *value ) @@ -372,6 +375,39 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ return res; } +/** + * la_ldap_handle_pf_file + * Given the plugin config and the client_context + * will write to pf_file the right + */ +int la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ + profile_config_t *p = cc->profile; + ldap_profile_t *lp = cc->ldap_account->profile; + + /* check if pf is enabled */ + LOGDEBUG("Global:%s\tProfile:%s\tPF enable for this profile: %s\n", + ternary_to_string(c->profile->enable_pf), + ternary_to_string(p->enable_pf), + config_is_pf_enabled_for_profile( c, p) ? "TRUE" : "FALSE" ); + /* write to pf_file */ + if( pf_file == NULL && config_is_pf_enabled(c) ){ + LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); + }else if( pf_file ){ + if( config_is_pf_enabled_for_profile( c, p) ){ + if( lp->pf_rules ){ + write_to_pf_file( pf_file, lp->pf_rules ); + }else{ + /* set up default pf_rules */ + /* TODO, set default pf rules per profiles */ + write_to_pf_file( pf_file, PF_ALLOW_ALL); + } + }else{ + /* profile has PF disabled */ + write_to_pf_file( pf_file, PF_ALLOW_ALL ); + } + } + return 0; +} int la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ @@ -430,7 +466,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ #ifdef ENABLE_LDAPUSERCONF time_t now = time(NULL); LOGWARNING( "ldap_account_load_from_dn returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); - /* TODO check if user timeframe is allowed start_date, end_date */ + /* check if user timeframe is allowed start_date, end_date */ if( ( client_context->ldap_account->profile->start_date == 0 || client_context->ldap_account->profile->start_date < now ) && ( client_context->ldap_account->profile->end_date == 0 || client_context->ldap_account->profile->end_date > now ) ){ @@ -440,16 +476,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ res = OPENVPN_PLUGIN_FUNC_ERROR; goto la_ldap_handle_authentication_free; } - LOGDEBUG("start date; %d. end date: %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date); - /* write to pf_file */ - if( config->enable_pf ){ - if( client_context->ldap_account->profile->pf_rules && auth_context->pf_file ){ - write_to_pf_file( auth_context->pf_file, client_context->ldap_account->profile->pf_rules ); - }else{ - /* set up default pf_rules */ - write_to_pf_file( auth_context->pf_file, "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n"); - } - } + la_ldap_handle_pf_file( config, client_context, auth_context->pf_file ); /* ldap_account_dump( client_context->ldap_account ); */ #endif /* check if user belong to right groups */ diff --git a/src/ldap-auth.c b/src/ldap-auth.c index f8b23ef..3e4c818 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -278,10 +278,11 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char #ifdef ENABLE_LDAPUSERCONF /* when ldap userconf is define, we need to hook onto those callbacks */ + if( config_is_pf_enabled( context->config )){ + *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); + } *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT); - if( context->config->enable_pf ) - *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); #endif const char *verb_string = get_env ("verb", envp); diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..0b5a1c6 --- /dev/null +++ b/src/types.h @@ -0,0 +1,48 @@ +/** + * vim: tabstop=2:shiftwidth=2:softtabstop=2:expandtab + * types.h + * + * Copyright (C) 2010 Emmanuel Bretelle + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +typedef enum ternary { + TERN_FALSE = -1, + TERN_UNDEF = 0, + TERN_TRUE = 1 +} ternary_t; + +#define ternary_to_string(x) x == TERN_FALSE ? "False" : x == TERN_UNDEF ? "Undef" : "True" +/* bool definitions */ +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#define BOOL_CAST(x) ((x) ? (true) : (false)) + +#endif diff --git a/src/utils.h b/src/utils.h index 10feefe..1add865 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,23 +24,8 @@ #define _UTILS_H_ #include +#include "types.h" #define FREE_IF_NOT_NULL(a) if (a != NULL) la_free (a) - -/* bool definitions */ -#ifndef bool -#define bool int -#endif - -#ifndef true -#define true 1 -#endif - -#ifndef false -#define false 0 -#endif - -#define BOOL_CAST(x) ((x) ? (true) : (false)) - /* memory allocation */ extern void *la_malloc( size_t size ); extern void la_free( void *ptr ); From 43c9c11c324a44bb0b66d68c2d4428318aecccd6 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 00:37:26 +0200 Subject: [PATCH 11/44] Add OPENVPN_PLUGIN_ENABLE_PF call if needed changed sleep period to 1 --- tests/openvpn-ldap-auth-test.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/openvpn-ldap-auth-test.c b/tests/openvpn-ldap-auth-test.c index d7b4aff..9ecfec8 100644 --- a/tests/openvpn-ldap-auth-test.c +++ b/tests/openvpn-ldap-auth-test.c @@ -1,7 +1,7 @@ /** * vim: tabstop=2:shiftwidth=2:softtabstop=2:expandtab * - * testplugin.c + * openvpn-ldap-auth-test.c * OpenVPN LDAP Authentication Plugin Test Driver * * Copyright (c) 2005 Landon Fuller @@ -42,7 +42,7 @@ #include #include -#define SLEEP_TIME 5 +#define SLEEP_TIME 1 const char username_template[] = "username="; const char password_template[] = "password="; @@ -52,7 +52,7 @@ struct openvpn_plugin_string_list *return_list = NULL; int main(int argc, const char *argv[]) { openvpn_plugin_handle_t handle; unsigned int type; - const char *envp[6]; /* username, password, verb, ifconfig_pool_remote_ip, NULL */ + const char *envp[7]; /* username, password, verb, ifconfig_pool_remote_ip, auth_confrol_file, [pf_file], NULL */ char username[30]; char *password; int loops; @@ -89,16 +89,28 @@ int main(int argc, const char *argv[]) { envp[2] = "ifconfig_pool_remote_ip=10.0.50.1"; envp[3] = "verb=4"; envp[4] = "auth_control_file=/tmp/foobar_ctrl_file.txt"; - envp[5] = NULL; handle = openvpn_plugin_open_v2(&type, argv, envp, NULL); if (!handle) errx(1, "Initialization Failed!\n"); + if( type & OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF) ){ + envp[5] = "pf_file=/tmp/foobar_pf_file.txt"; + envp[6] = NULL; + }else{ + envp[5] = NULL; + } + /* Authenticate */ for( ; loops; --loops ){ client_context = openvpn_plugin_client_constructor_v1( handle ); + if( type & OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF) ){ + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_ENABLE_PF, argv, envp, client_context, NULL); + printf("Enable PF: %s\n", err == OPENVPN_PLUGIN_FUNC_SUCCESS ? "True" : "False" ); + }else{ + printf("Enable PF: Not enabled\n"); + } err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, argv, envp, client_context, NULL); if (err == OPENVPN_PLUGIN_FUNC_ERROR) { printf("Authorization Failed!\n"); From 8e3f096710333b99fcf42f6b56cddf6e82bb6d27 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 00:44:03 +0200 Subject: [PATCH 12/44] Code organization * move ldapconfprofile functions to ldap_profile.c * add ldap_profile_handle_allowed_timeframe will check if user is allowed to connect now --- src/la_ldap.c | 83 ++------------------------------------- src/ldap_profile.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-- src/ldap_profile.h | 20 ++++++++++ 3 files changed, 116 insertions(+), 83 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index f82f797..407778d 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -32,45 +32,8 @@ #ifdef ENABLE_LDAPUSERCONF #include "ldap_profile.h" -#include "time.h" #endif -#include -#include -#include -#include - -#define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" - -/* write a value to pf_file */ -int -write_to_pf_file( char *pf_file, char *value ) -{ - int fd, rc; - if( pf_file == NULL ){ - LOGERROR( "pf_file is null\n"); - return -1; - } - - fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); - if( fd == -1 ){ - LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); - return -1; - } - rc = write( fd, value, strlen(value) ); - if( rc == -1 ){ - LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); - }else if( rc !=strlen(value) ){ - LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); - } - rc = close( fd ); - if( rc != 0 ){ - LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); - } - return rc == 0; -} - - void ldap_context_free( ldap_context_t *l ){ if( !l ) return; @@ -375,40 +338,6 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ return res; } -/** - * la_ldap_handle_pf_file - * Given the plugin config and the client_context - * will write to pf_file the right - */ -int la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ - profile_config_t *p = cc->profile; - ldap_profile_t *lp = cc->ldap_account->profile; - - /* check if pf is enabled */ - LOGDEBUG("Global:%s\tProfile:%s\tPF enable for this profile: %s\n", - ternary_to_string(c->profile->enable_pf), - ternary_to_string(p->enable_pf), - config_is_pf_enabled_for_profile( c, p) ? "TRUE" : "FALSE" ); - /* write to pf_file */ - if( pf_file == NULL && config_is_pf_enabled(c) ){ - LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); - }else if( pf_file ){ - if( config_is_pf_enabled_for_profile( c, p) ){ - if( lp->pf_rules ){ - write_to_pf_file( pf_file, lp->pf_rules ); - }else{ - /* set up default pf_rules */ - /* TODO, set default pf rules per profiles */ - write_to_pf_file( pf_file, PF_ALLOW_ALL); - } - }else{ - /* profile has PF disabled */ - write_to_pf_file( pf_file, PF_ALLOW_ALL ); - } - } - return 0; -} - int la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LDAP *ldap = NULL; @@ -464,19 +393,13 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ if( DODEBUG( l->verb ) ) LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); #ifdef ENABLE_LDAPUSERCONF - time_t now = time(NULL); - LOGWARNING( "ldap_account_load_from_dn returned: %d\n", ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account )); + ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account ); /* check if user timeframe is allowed start_date, end_date */ - if( ( client_context->ldap_account->profile->start_date == 0 || client_context->ldap_account->profile->start_date < now ) - && - ( client_context->ldap_account->profile->end_date == 0 || client_context->ldap_account->profile->end_date > now ) ){ - LOGINFO("user time period: %d/%d is allowed to connect at %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date, now); - }else{ - LOGINFO("user time period: %d/%d is not allowed to connect at %d\n", client_context->ldap_account->profile->start_date, client_context->ldap_account->profile->end_date, now); + if( ldap_profile_handle_allowed_timeframe( client_context->ldap_account->profile ) != 0 ){ res = OPENVPN_PLUGIN_FUNC_ERROR; goto la_ldap_handle_authentication_free; } - la_ldap_handle_pf_file( config, client_context, auth_context->pf_file ); + ldap_profile_handle_pf_file( config, client_context->profile, client_context->ldap_account->profile, auth_context->pf_file ); /* ldap_account_dump( client_context->ldap_account ); */ #endif /* check if user belong to right groups */ diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 7edb36f..25a9c69 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -21,14 +21,21 @@ #define DODEBUG(verb) ((verb) >= 4) +#include "debug.h" +#include "ldap_profile.h" +#include "utils.h" + #include #include #include #include -#include "debug.h" -#include "ldap_profile.h" -#include "utils.h" +#include +#include +#include +#include + + ldap_profile_t * ldap_profile_new( ){ @@ -364,3 +371,86 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ return res; } + + +int +ldap_profile_write_to_pf_file( char *pf_file, char *value ) +{ + int fd, rc; + if( pf_file == NULL ){ + LOGERROR( "pf_file is null\n"); + return -1; + } + + fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); + if( fd == -1 ){ + LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + return -1; + } + rc = write( fd, value, strlen(value) ); + if( rc == -1 ){ + LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); + }else if( rc !=strlen(value) ){ + LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); + } + rc = close( fd ); + if( rc != 0 ){ + LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + } + return rc == 0; +} + + +/** + * la_ldap_handle_pf_file + * Given the plugin config and the client_context + * will write to pf_file the right + */ +int +ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file){ + + /* check if pf is enabled */ + LOGDEBUG("Global:%s\tProfile:%s\tPF enable for this profile: %s\n", + ternary_to_string(c->profile->enable_pf), + ternary_to_string(p->enable_pf), + config_is_pf_enabled_for_profile( c, p) ? "TRUE" : "FALSE" ); + /* write to pf_file */ + if( pf_file == NULL && config_is_pf_enabled(c) ){ + LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); + }else if( pf_file ){ + if( config_is_pf_enabled_for_profile( c, p) ){ + if( lp->pf_rules ){ + ldap_profile_write_to_pf_file( pf_file, lp->pf_rules ); + }else{ + /* set up default pf_rules */ + /* TODO, set default pf rules per profiles */ + ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL); + } + }else{ + /* profile has PF disabled */ + ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL ); + } + } + return 0; +} + +/** + * la_ldap_handle_allowed_timeframe + * check if a user LDAP profile can log in + * return 0 on success + */ +int +ldap_profile_handle_allowed_timeframe( ldap_profile_t *p ){ + time_t now = time(NULL); + if( !( p->start_date == 0 || p->start_date < now ) + || + !( p->end_date == 0 || p->end_date > now ) ){ + LOGINFO("user time period: %d/%d is not allowed to connect at %d\n", p->start_date, p->end_date, now); + return 1; + } + LOGINFO("user time period: %d/%d is allowed to connect at %d\n", p->start_date, p->end_date, now); + return 0; +} + + + diff --git a/src/ldap_profile.h b/src/ldap_profile.h index 7f9b6d2..806ee15 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -29,6 +29,8 @@ #include "la_ldap.h" +#define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" + typedef struct ldap_profile { time_t start_date; @@ -89,4 +91,22 @@ extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, */ extern char *ldap_account_get_options_to_string( ldap_account_t *account ); + +/* write a value to pf_file */ +extern int ldap_profile_write_to_pf_file( char *pf_file, char *value ); + +/** + * la_ldap_handle_pf_file + * Given the plugin config, used profile_config and ldap_profile + * will write to pf_file the right + */ +extern int ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file); + +/** + * la_ldap_handle_allowed_timeframe + * check if a user LDAP profile can log in + * return 0 on success + */ +extern int ldap_profile_handle_allowed_timeframe( ldap_profile_t *p ); + #endif /* __LDAP_PROFILE_H__ */ From 0ceb3afa181825c7cd5dc014f41332bef1ebab31 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 00:52:42 +0200 Subject: [PATCH 13/44] group_search_filter must be in parentheses Will match search_filter syntax --- Changelog | 4 ++++ src/la_ldap.c | 2 +- tests/config.conf | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 9b24c92..b3d0b93 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +version 0.0.5 + * group_search_filter needs to be enclosed in parentheses + * support for multiple account profiles + version 0.0.4 2010-07-19 * Only one thread is handling authentication diff --git a/src/la_ldap.c b/src/la_ldap.c index 407778d..8bf2e12 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -303,7 +303,7 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ char *search_filter = NULL; int rc; int res = 1; - char filter[]="(&(%s=%s)(%s))"; + char filter[]="(&(%s=%s)%s)"; /* arguments sanity check */ if( !ldap_context || !userdn || !ldap){ diff --git a/tests/config.conf b/tests/config.conf index fec66fd..d899f4a 100644 --- a/tests/config.conf +++ b/tests/config.conf @@ -6,5 +6,5 @@ version=3 #ssl=start_tls ssl=off groupdn=ou=roles,dc=example,dc=com -group_search_filter=|(cn=vpn)(cn=sysadmins) +group_search_filter=(|(cn=vpn)(cn=sysadmins)) member_attribute=member From 3d0efda8fc2a453e97016c234410fc08c01e74aa Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 05:56:46 +0200 Subject: [PATCH 14/44] Group filtering is done at profile level --- src/cnf.c | 21 +++++++++-- src/la_ldap.c | 57 ++++++++++++++++++++-------- src/ldap_profile.c | 5 ++- tests/openvpn-ldap-auth-test.c | 68 +++++++++++++++++++++------------- 4 files changed, 105 insertions(+), 46 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index 24b7b15..28c4de4 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -353,9 +353,9 @@ config_parse_file( const char *filename, config_t *c ){ }else if( !strcmp( arg, "groupdn" ) ){ STRDUP_IFNOTSET(current_profile->groupdn, val ); }else if( !strcmp( arg, "group_search_filter" ) ){ - STRDUP_IFNOTSET(c->profile->group_search_filter, val ); + STRDUP_IFNOTSET(current_profile->group_search_filter, val ); }else if( !strcmp( arg, "member_attribute" ) ){ - STRDUP_IFNOTSET(c->profile->member_attribute, val ); + STRDUP_IFNOTSET(current_profile->member_attribute, val ); }else{ LOGWARNING("Unrecognized option *%s=%s*\n", arg, val); } @@ -367,6 +367,19 @@ config_parse_file( const char *filename, config_t *c ){ return 0; } +const char * +config_search_scope_to_string( ldap_search_scope_t scope){ + + switch( scope ){ + case LA_SCOPE_BASE: + return "BASE"; + case LA_SCOPE_ONELEVEL: + return "ONELEVEL"; + case LA_SCOPE_SUBTREE: + return "SUBTREE"; + } + return NULL; +} void config_dump( config_t *c){ fprintf( stderr, "Config Dump:\n*LDAP:*\n"); @@ -378,7 +391,7 @@ config_dump( config_t *c){ fprintf( stderr, "*Default Profile:*\n" ); STRPRINT_IFSET(c->profile->basedn, "\tBaseDN"); fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(c->profile->enable_pf)); - fprintf( stderr, "\tSearch Scope:\t%d\n", c->profile->search_scope ); + fprintf( stderr, "\tSearch Scope:\t%s\n", config_search_scope_to_string( c->profile->search_scope ) ); fprintf( stderr, "\tSearch filter:\t%s\n", c->profile->search_filter ); STRPRINT_IFSET(c->profile->groupdn,"\tGroupDN"); STRPRINT_IFSET(c->profile->group_search_filter, "\tGroup Search Filter"); @@ -392,7 +405,7 @@ config_dump( config_t *c){ fprintf( stderr, "*Custom Profile:*\n" ); STRPRINT_IFSET(p->basedn, "\tBaseDN"); fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); - fprintf( stderr, "\tSearch Scope:\t%d\n", p->search_scope ); + fprintf( stderr, "\tSearch Scope:\t%s\n", config_search_scope_to_string( p->search_scope ) ); fprintf( stderr, "\tSearch filter:\t%s\n", p->search_filter ); STRPRINT_IFSET(p->groupdn,"\tGroupDN"); STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); diff --git a/src/la_ldap.c b/src/la_ldap.c index 8bf2e12..5d75160 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -102,7 +102,31 @@ la_ldap_errno( LDAP *ldap ){ return rc; } +static int +la_ldap_config_search_scope_to_ldap( ldap_search_scope_t scope ){ + int ldap_scope = 0; + if( scope == LA_SCOPE_BASE ) + ldap_scope = LDAP_SCOPE_BASE; + else if( scope == LA_SCOPE_ONELEVEL ) + ldap_scope = LDAP_SCOPE_ONELEVEL; + else if( scope == LA_SCOPE_SUBTREE ) + ldap_scope = LDAP_SCOPE_SUBTREE; + return ldap_scope; +} + +static const char * +la_ldap_ldap_scope_to_string( int scope ){ + switch( scope ){ + case LDAP_SCOPE_BASE: + return "BASE"; + case LDAP_SCOPE_ONELEVEL: + return "ONELEVEL"; + case LDAP_SCOPE_SUBTREE: + return "SUBTREE"; + } + return NULL; +} char * ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char *username, profile_config_t *p){ char *userdn = NULL; @@ -126,13 +150,8 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char search_filter = str_replace(config->profile->search_filter, "%u", username ); } if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, p->basedn ); - if( p->search_scope == LA_SCOPE_BASE ) - ldap_scope = LDAP_SCOPE_BASE; - else if( p->search_scope == LA_SCOPE_ONELEVEL ) - ldap_scope = LDAP_SCOPE_ONELEVEL; - else if( p->search_scope == LA_SCOPE_SUBTREE ) - ldap_scope = LDAP_SCOPE_SUBTREE; + LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); + ldap_scope = la_ldap_config_search_scope_to_ldap( p->search_scope ); rc = ldap_search_ext_s( ldap, p->basedn, ldap_scope, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ @@ -161,7 +180,7 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char if( dn ){ userdn = strdup( dn ); /* finally, if a DN was returned, free it */ - if( dn ) ldap_memfree( dn ); + ldap_memfree( dn ); } if( search_filter ) free( search_filter ); return userdn; @@ -192,6 +211,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, p = config->profile; userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); if( userdn ){ + if( cc->user_dn ) la_free( cc->user_dn ); cc->user_dn = strdup( userdn ); cc->profile = p; } @@ -200,6 +220,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, p = item->data; userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); if( userdn ){ + if( cc->user_dn ) la_free( cc->user_dn ); cc->user_dn = strdup( userdn ); cc->profile = p; break; @@ -295,7 +316,7 @@ ldap_binddn( LDAP *ldap, const char *username, const char *password ){ * Check if userdn belongs to group */ int -ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ +ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, client_context_t *cc ){ struct timeval timeout; char *attrs[] = { NULL }; LDAPMessage *result; @@ -304,6 +325,9 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ int rc; int res = 1; char filter[]="(&(%s=%s)%s)"; + int ldap_scope = 0; + char *userdn = cc->user_dn; + profile_config_t *p = cc->profile; /* arguments sanity check */ if( !ldap_context || !userdn || !ldap){ @@ -314,13 +338,15 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, char *userdn ){ /* initialise timeout values */ la_ldap_set_timeout( config, &timeout); - if( userdn && config->profile->group_search_filter && config->profile->member_attribute ){ - search_filter = strdupf(filter,config->profile->member_attribute, userdn, config->profile->group_search_filter); + if( userdn && p->group_search_filter && p->member_attribute ){ + search_filter = strdupf(filter,p->member_attribute, userdn, p->group_search_filter); } + + ldap_scope = la_ldap_config_search_scope_to_ldap( p->search_scope ); if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s\n", search_filter, config->profile->groupdn ); + LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->groupdn, la_ldap_ldap_scope_to_string( p->search_scope ) ); - rc = ldap_search_ext_s( ldap, config->profile->groupdn, LDAP_SCOPE_ONELEVEL, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); + rc = ldap_search_ext_s( ldap, p->groupdn, ldap_scope, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ int nbrow = ldap_count_entries( ldap, result ); @@ -402,9 +428,10 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ ldap_profile_handle_pf_file( config, client_context->profile, client_context->ldap_account->profile, auth_context->pf_file ); /* ldap_account_dump( client_context->ldap_account ); */ #endif + /* check if user belong to right groups */ - if( config->profile->groupdn && config->profile->group_search_filter && config->profile->member_attribute ){ - rc = ldap_group_membership( ldap, l, userdn ); + if( client_context->profile->groupdn && client_context->profile->group_search_filter && client_context->profile->member_attribute ){ + rc = ldap_group_membership( ldap, l, client_context ); if( rc == 0 ){ res = OPENVPN_PLUGIN_FUNC_SUCCESS; } diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 25a9c69..3e1c9cd 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -111,7 +111,9 @@ ldap_account_free( ldap_account_t *l){ if( !l ) return; if( l->profile ) ldap_profile_free( l->profile ); if( l->ifconfig_push ) la_free( l->ifconfig_push ); - if( l->profile_dn ) la_free( l->profile_dn ); + if( l->profile_dn ){ + la_free( l->profile_dn ); + } la_free( l ); } @@ -174,7 +176,6 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun for( attr = ldap_first_attribute( ldap, e, &berptr ); attr != NULL; attr = ldap_next_attribute( ldap, e, berptr ) ){ vals = ldap_get_values_len( ldap, e, attr ); - printf("attribute: %s: %d\n", attr, ldap_count_values_len( vals )); if( ldap_count_values_len( vals ) < 1 ) goto ldap_account_load_from_entry_end_loop; diff --git a/tests/openvpn-ldap-auth-test.c b/tests/openvpn-ldap-auth-test.c index 9ecfec8..2dc032c 100644 --- a/tests/openvpn-ldap-auth-test.c +++ b/tests/openvpn-ldap-auth-test.c @@ -46,7 +46,7 @@ const char username_template[] = "username="; const char password_template[] = "password="; -void *client_context = NULL; +void **client_contexts = NULL; struct openvpn_plugin_string_list *return_list = NULL; int main(int argc, const char *argv[]) { @@ -102,16 +102,23 @@ int main(int argc, const char *argv[]) { envp[5] = NULL; } + client_contexts = malloc( sizeof( void * ) * loops ); + if( client_contexts == NULL ){ + fprintf(stderr, "Could not allocate client contexts\n"); + return 1; + } + + int i; /* Authenticate */ - for( ; loops; --loops ){ - client_context = openvpn_plugin_client_constructor_v1( handle ); + for( i = 0; i < loops; i++ ){ + client_contexts[i] = openvpn_plugin_client_constructor_v1( handle ); if( type & OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF) ){ - err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_ENABLE_PF, argv, envp, client_context, NULL); + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_ENABLE_PF, argv, envp, client_contexts[i], NULL); printf("Enable PF: %s\n", err == OPENVPN_PLUGIN_FUNC_SUCCESS ? "True" : "False" ); }else{ printf("Enable PF: Not enabled\n"); } - err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, argv, envp, client_context, NULL); + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, argv, envp, client_contexts[i], NULL); if (err == OPENVPN_PLUGIN_FUNC_ERROR) { printf("Authorization Failed!\n"); } else if( err == OPENVPN_PLUGIN_FUNC_SUCCESS ) { @@ -119,27 +126,38 @@ int main(int argc, const char *argv[]) { }else if ( err == OPENVPN_PLUGIN_FUNC_DEFERRED ){ printf("Authorization Deferred!\n"); } + printf( "Sleeping %d seconds to let the threads do some job...\n", SLEEP_TIME ); + sleep( SLEEP_TIME + 2 ); + //goto free_exit; + /* Client Connect */ + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, argv, envp, client_contexts[i], &return_list); + if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { + printf("client-connect failed!\n"); + } else { + printf("client-connect succeed!\n"); + } + + struct openvpn_plugin_string_list *rl, *next; + next = return_list; + while( next ){ + free( next->name); + free( next->value); + rl = next; + next = next->next; + free( rl ); + } + /* Client Disconnect */ + err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_DISCONNECT, argv, envp, client_contexts[i], NULL); + if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { + printf("client-disconnect failed!\n"); + } else { + printf("client-disconnect succeed!\n"); + } + //free_exit: + openvpn_plugin_client_destructor_v1( handle, client_contexts[i] ); } - printf( "Sleeping %d seconds to let the threads do some job...\n", SLEEP_TIME ); - sleep( SLEEP_TIME ); - //goto free_exit; - /* Client Connect */ - err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, argv, envp, client_context, &return_list); - if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { - printf("client-connect failed!\n"); - } else { - printf("client-connect succeed!\n"); - } - - /* Client Disconnect */ - err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_DISCONNECT, argv, envp, client_context, NULL); - if (err != OPENVPN_PLUGIN_FUNC_SUCCESS) { - printf("client-disconnect failed!\n"); - } else { - printf("client-disconnect succeed!\n"); - } -//free_exit: - openvpn_plugin_client_destructor_v1( handle, client_context ); + + free( client_contexts ); sprintf(command, "lsof -n -p %d", pid); //system(command); openvpn_plugin_close_v1(handle); From 3d788beed261b576ed635e430b5c15114a3991ec Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 17:11:33 +0200 Subject: [PATCH 15/44] Adding LDAP schema --- tests/ovpn.schema | 193 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 tests/ovpn.schema diff --git a/tests/ovpn.schema b/tests/ovpn.schema new file mode 100644 index 0000000..f9c262c --- /dev/null +++ b/tests/ovpn.schema @@ -0,0 +1,193 @@ +# 1.3.6.1.4.1.4203.666.1194 +# 1.3.6.1.4.1.4203.666.1194.5 LDAP elements +# 1.3.6.1.4.1.4203.666.1194.5.4 Attribute Types +# 1.3.6.1.4.1.4203.666.1194.5.5 Object Classes + +objectIdentifier OpenVPNRoot 1.3.6.1.4.1.4203.666.1194 +objectIdentifier OpenVPNLDAP OpenVPNRoot:5 + +############################################################################# +# Attribute group OIDs. e.g.: objectIdentifier Ovpn OpenVPNLDAP:4 +############################################################################# +objectIdentifier OvpnAttrType OpenVPNLDAP:4 + +############################################################################# +# Attribute OIDs e.g.: objectIdentifier OvpnStartDate OvpnAttrType:1 +############################################################################# + +objectIdentifier OvpnStartDate OvpnAttrType:1 +objectIdentifier OvpnEndDate OvpnAttrType:2 +objectIdentifier OvpnPFRulesClientDefaultAccept OvpnAttrType:3 +objectIdentifier OvpnPFRulesSubnetDefaultAccept OvpnAttrType:4 +objectIdentifier OvpnPFRulesClient OvpnAttrType:5 +objectIdentifier OvpnPFRulesSubnet OvpnAttrType:6 +objectIdentifier OvpnCCDPushOption OvpnAttrType:7 +objectIdentifier OvpnCCDPushReset OvpnAttrType:8 +objectIdentifier OvpnCCDIRoute OvpnAttrType:9 +objectIdentifier OvpnCCDIfconfigPush OvpnAttrType:10 +objectIdentifier OvpnCCDConfig OvpnAttrType:11 +objectIdentifier OvpnProfile OvpnAttrType:12 + +############################################################################# +# Object Class OIDs +############################################################################# +objectIdentifier OvpnObjectClass OpenVPNLDAP:2 +objectIdentifier OpenVPNProfile OvpnObjectClass:1 +objectIdentifier OpenVPNAccount OvpnObjectClass:2 + + + +############################################################################# +# attribute definitions +# +# OID (the first arg) comes from the objectIdentifier defined above +# +# NAME should be the same as objectIdentifier +# +# DESC should be the description of the attribute +# +# EQUALITY is the rule to use when doing a search/compare for an +# attribute value. +# +# SUBSTR is the rule to use when doing a substring search (*foo*) +# +# SYNTAX is the syntax (i.e., type) of the attribute. We should +# probably stick to syntaxes: +# +# 1.3.6.1.4.1.1466.115.121.1.15 -> directoryString (UTF-8 string) +# 1.3.6.1.4.1.1466.115.121.1.26 -> IA5String (ASCII String) +# 1.3.6.1.4.1.1466.115.121.1.27 -> integer (Integer value) +# +# SINGLE-VALUE should be present if only one instance of this +# attribute is allowed within an entry. +# +# {32} is the allowed length +# +# e.g.: +# +# attributetype ( AstExample +# NAME ( 'AstExample' ) +# DESC 'Asterisk Example Attribute' +# EQUALITY caseIgnoreMatch +# SUBSTR caseIgnoreSubstringsMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32} +# SINGLE-VALUE ) +# +############################################################################# + +attributetype ( OvpnStartDate + NAME 'OvpnStartDate' + DESC 'Time at which account can start loggin in' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE ) + +attributetype ( OvpnEndDate + NAME 'OvpnEndDate' + DESC 'Time at which account cannot loggin in anymore' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE ) + +attributetype ( OvpnPFRulesClientDefaultAccept + NAME 'OvpnPFRulesClientDefaultAccept' + DESC 'Default packet filtering rule for client to client access' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnPFRulesSubnetDefaultAccept + NAME 'OvpnPFRulesSubnetDefaultAccept' + DESC 'Default packet filtering rule to access subnet' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnPFRulesClient + NAME 'OvpnPFRulesClient' + DESC 'Packet filtering rules for client to client access' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnPFRulesSubnet + NAME 'OvpnPFRulesSubnet' + DESC 'Packet filtering rules to access subnets' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnCCDPushOption + NAME 'OvpnCCDPushOption' + DESC 'Options to push to client' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) + +attributetype ( OvpnCCDPushReset + NAME 'OvpnCCDPushReset' + DESC 'Dont inherit the global push list' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + SINGLE-VALUE ) + +attributetype ( OvpnCCDIRoute + NAME 'OvpnCCDIRoute' + DESC 'IRoute of the client' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) + +attributetype ( OvpnCCDIfconfigPush + NAME 'OvpnCCDIfconfigPush' + DESC 'ifconfig to push to client' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnCCDConfig + NAME 'OvpnCCDConfig' + DESC 'location of a config file???' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + +attributetype ( OvpnProfile + NAME 'OvpnProfile' + DESC 'dn of a OpenVPNProfile' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} + SINGLE-VALUE ) + + +############################################################################# +# Object Class definitions +# +# This is where to define the object classes. Object classes are used +# to define which attribute MAY (optional) or MUST (required) belong +# to an entry. +# +# Classes can be AUXILIARY or STRUCTURAL. An entry in the directory +# must have one and only one structural class, but can have many +# AUXILIARY classes. +# +############################################################################# + +objectClass ( OpenVPNProfile + NAME 'OpenVPNProfile' + DESC 'An OpenVPN profile definition' + SUP top + AUXILIARY + MAY ( OvpnStartDate $ OvpnEndDate $ OvpnPFRulesClientDefaultAccept $ + OvpnPFRulesSubnetDefaultAccept $ OvpnPFRulesClient $ OvpnPFRulesSubnet $ + OvpnCCDPushOption $ OvpnCCDPushReset $ + OvpnCCDIRoute $ OvpnCCDConfig ) ) + +objectClass ( OpenVPNAccount + NAME 'OpenVPNAccount' + DESC 'An OpenVPN account definition' + SUP OpenVPNProfile + AUXILIARY + MAY ( OvpnProfile $ OvpnCCDIfconfigPush ) ) + + From 17ee8b6afb54e5ea46309977eaf9358951e46405 Mon Sep 17 00:00:00 2001 From: chantra Date: Thu, 29 Jul 2010 17:37:18 +0200 Subject: [PATCH 16/44] Handle PF rules if provided in ldap profile if either default rules for client/subnet is missing, default to allow all (default openvpn behaviour) --- .gitignore | 1 + src/cnf.c | 2 +- src/la_ldap.c | 28 +++++++-- src/la_ldap.h | 5 ++ src/ldap-auth.c | 2 +- src/ldap_profile.c | 138 ++++++++++++++++++++++++++++++++++++--------- src/ldap_profile.h | 7 ++- 7 files changed, 146 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 5acee29..809df86 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ Makefile configure config.h testplugin +tools/ diff --git a/src/cnf.c b/src/cnf.c index 28c4de4..d6fa435 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -397,7 +397,7 @@ config_dump( config_t *c){ STRPRINT_IFSET(c->profile->group_search_filter, "\tGroup Search Filter"); STRPRINT_IFSET(c->profile->member_attribute,"\tMember Attribute"); STRPRINT_IFSET(c->profile->profiledn,"\tProfile DN"); - /* TODO finish dumping info */ + /* Dump each profiles */ list_item_t *item; profile_config_t *p; for( item = list_first( c->profiles ); item; item = item->next){ diff --git a/src/la_ldap.c b/src/la_ldap.c index 5d75160..d91c366 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -94,6 +94,7 @@ la_ldap_set_timeout( config_t *conf, struct timeval *timeout){ /** * la_ldap_errno + * return the last set error */ int la_ldap_errno( LDAP *ldap ){ @@ -102,6 +103,9 @@ la_ldap_errno( LDAP *ldap ){ return rc; } +/** + * Translate config scope values to ldap scope values + */ static int la_ldap_config_search_scope_to_ldap( ldap_search_scope_t scope ){ int ldap_scope = 0; @@ -127,6 +131,13 @@ la_ldap_ldap_scope_to_string( int scope ){ } return NULL; } +/** + * Search for a user's DN given a config profile + * On success, return userdn (much be freed by caller) + * On error, return NULL + */ + + char * ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char *username, profile_config_t *p){ char *userdn = NULL; @@ -186,9 +197,16 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char return userdn; } + /** * Search for a user's DN - * Given a search_filter and context, will search for + * Given a search_filter and context, will search for a user + * Each profiles will be tried one after another one until a + * match is found or no more profile are available + * On success + * * return userdn (much be freed by caller) + * * set set userdn and used profile in client_context + * On error, return NULL */ char * ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, client_context_t *cc ){ @@ -395,6 +413,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ goto la_ldap_handle_authentication_free; } + /* find user and return userdn */ userdn = ldap_find_user( ldap, l, auth_context->username, client_context ); if( !userdn ){ LOGWARNING( "LDAP user *%s* was not found \n", auth_context->username ); @@ -403,13 +422,8 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ if (auth_context && l->config ){ if (auth_context->username && strlen (auth_context->username) > 0 && auth_context->password){ - /** TODO authenticate user */ if (DODEBUG (l->verb)) { - #if 0 - LOGINFO ("LDAP-AUTH: Authenticating Username:%s Password:%s\n", auth_context->username, auth_context->password); - #else LOGINFO ("LDAP-AUTH: Authenticating Username:%s\n", auth_context->username ); - #endif } rc = ldap_binddn( ldap, userdn, auth_context->password ); if( rc != LDAP_SUCCESS ){ @@ -419,12 +433,14 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ if( DODEBUG( l->verb ) ) LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); #ifdef ENABLE_LDAPUSERCONF + /* load user settings from LDAP profile */ ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account ); /* check if user timeframe is allowed start_date, end_date */ if( ldap_profile_handle_allowed_timeframe( client_context->ldap_account->profile ) != 0 ){ res = OPENVPN_PLUGIN_FUNC_ERROR; goto la_ldap_handle_authentication_free; } + /* handle pf_rules if any, default value otherwise */ ldap_profile_handle_pf_file( config, client_context->profile, client_context->ldap_account->profile, auth_context->pf_file ); /* ldap_account_dump( client_context->ldap_account ); */ #endif diff --git a/src/la_ldap.h b/src/la_ldap.h index 0dcb0ad..7e5e63e 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -83,6 +83,11 @@ extern ldap_context_t * ldap_context_new( void ); extern void la_ldap_set_timeout( config_t *conf, struct timeval *timeout); /** * handle authentication action + * takes care of: + * - checking if user exists + * - user/pass is correct + * - load LDAP profile data if any + * - write PF rules if needed */ extern int la_ldap_handle_authentication( ldap_context_t *l, action_t *a); diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 3e4c818..cc4ba14 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -507,7 +507,7 @@ action_thread_main_loop (void *c) int loop = 1; while( loop ){ action = action_pop(context->action_list); - /* TODO, do some action */ + /* handle action */ if (action){ switch (action->type){ case LDAP_AUTH_ACTION_AUTH: diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 3e1c9cd..7cf9011 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -43,9 +43,13 @@ ldap_profile_new( ){ l = la_malloc( sizeof( ldap_profile_t ) ); if( !l ) return NULL; l->start_date = l->end_date = 0; - l->pf_rules = NULL; + /* PF */ + l->pf_client_default_accept = TERN_UNDEF; + l->pf_subnet_default_accept = TERN_UNDEF; + l->pf_client_rules = NULL; + l->pf_subnet_rules = NULL; l->config = NULL; - l->push_reset = 0; + l->push_reset = TERN_UNDEF; l->iroutes = list_new( ); l->push_options = list_new( ); if( l->iroutes == NULL || l->push_options == NULL ){ @@ -58,7 +62,8 @@ ldap_profile_new( ){ void ldap_profile_free( ldap_profile_t *l ){ if( !l ) return; - if( l->pf_rules ) la_free( l->pf_rules ); + if( l->pf_client_rules ) la_free( l->pf_client_rules ); + if( l->pf_subnet_rules ) la_free( l->pf_subnet_rules ); if( l->push_options ) list_free ( l->push_options, la_free ); if( l->iroutes ) list_free( l->iroutes, la_free ); if( l->config ) la_free( l->config ); @@ -71,12 +76,18 @@ ldap_profile_dump( ldap_profile_t *l ){ fprintf(stdout, "Account profile:\n\ \tstart_date:\t\t%u\n\ \tend_date:\t\t%u\n\ -\tpf_rules:\t\t%s\n\ +\tpf_client_default_accept:\t\t%s\n\ +\tpf_subnet_default_accept:\t\t%s\n\ +\tpf_client_rules:\t\t%s\n\ +\tpf_subnet_rules:\t\t%s\n\ \tpush_reset:\t\t%s\n\ \tconfig:\t\t%s\n", (unsigned int)l->start_date, (unsigned int)l->end_date, - l->pf_rules ? l->pf_rules : "None", - l->push_reset ? "TRUE" : "FALSE", + l->pf_client_default_accept == TERN_TRUE ? "ACCEPT" : l->pf_client_default_accept == TERN_FALSE ? "DROP": "Undef", + l->pf_subnet_default_accept == TERN_TRUE ? "ACCEPT" : l->pf_subnet_default_accept == TERN_FALSE ? "DROP" : "Undef", + l->pf_client_rules ? l->pf_client_rules : "None", + l->pf_subnet_rules ? l->pf_subnet_rules : "None", + l->push_reset == TERN_TRUE ? "TRUE" : l->push_reset == TERN_FALSE ? "FALSE" : "Undef", l->config ? l->config : "None"); fprintf( stdout, "\tpush options:\n" ); list_item_t *i; @@ -127,6 +138,24 @@ ldap_account_dump( ldap_account_t *l ){ l->profile_dn ? l->profile_dn : "None"); ldap_profile_dump( l->profile ); } + +/** + * Converts a LDAP boolean value to a ternary + * If value is neither true/on/false/off + * TERN_UNDEF is returned + */ +ternary_t +la_ldap_bool_to_ternary( char *value ){ + if( value == NULL ) + return TERN_UNDEF; + + if( strcasecmp( value, "true" ) == 0 || strcasecmp( value, "on" )) + return TERN_TRUE; + if( strcasecmp( value, "false" ) == 0 || strcasecmp( value, "off" )) + return TERN_FALSE; + return TERN_UNDEF; +} + /** * convert a LDAP GeneralizedTime string to a time_t. * t will be set to 0 if generalized time is @@ -193,17 +222,22 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun }else{ account->profile->end_date = t; } - }else if( strcasecmp( attr, "OvpnPFRules" ) == 0 ){ - if( account->profile->pf_rules ) la_free( account->profile->pf_rules ); - account->profile->pf_rules = strdup( vals[0]->bv_val ); + }else if( strcasecmp( attr, "OvpnPFRulesClientDefaultAccept" ) == 0 ){ + account->profile->pf_client_default_accept = la_ldap_bool_to_ternary( vals[0]->bv_val ); + }else if( strcasecmp( attr, "OvpnPFRulesSubnetDefaultAccept" ) == 0 ){ + account->profile->pf_subnet_default_accept = la_ldap_bool_to_ternary( vals[0]->bv_val ); + }else if( strcasecmp( attr, "OvpnPFRulesClient" ) == 0 ){ + if( account->profile->pf_client_rules ) la_free( account->profile->pf_client_rules ); + account->profile->pf_client_rules = strdup( vals[0]->bv_val ); + }else if( strcasecmp( attr, "OvpnPFRulesSubnet" ) == 0 ){ + if( account->profile->pf_subnet_rules ) la_free( account->profile->pf_subnet_rules ); + account->profile->pf_subnet_rules = strdup( vals[0]->bv_val ); }else if( strcasecmp( attr, "OvpnCCDPushOption" ) == 0 ){ for( i = 0; vals[i]; i++){ list_append( account->profile->push_options, (void *)strdup( vals[i]->bv_val ) ); } }else if( strcasecmp( attr, "OvpnCCDPushReset" ) == 0 ){ - char *boolean = vals[0]->bv_val; - if( strcasecmp( boolean, "true" ) == 0 || strcasecmp( boolean, "on" ) ) - account->profile->push_reset = 1; + account->profile->push_reset = la_ldap_bool_to_ternary( vals[0]->bv_val ); }else if( strcasecmp( attr, "OvpnCCDIRoute" ) == 0 ){ for( i = 0; vals[i]; i++){ list_append( account->profile->iroutes, (void *) strdup( vals[i]->bv_val ) ); @@ -333,7 +367,7 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ uint8_t tot_size = 0; list_item_t *elem = NULL; char *res = NULL; - if (account->profile->push_reset) + if (account->profile->push_reset == TERN_TRUE) tot_size += sizeof("push-reset\n"); if (account->ifconfig_push) tot_size += sizeof("ifconfig \n") + strlen(account->ifconfig_push); @@ -355,7 +389,7 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ res = la_malloc( tot_size ); la_memset( res, 0, tot_size); - if (account->profile->push_reset) + if (account->profile->push_reset == TERN_TRUE) strcat( res, "push-reset\n"); if (account->ifconfig_push) strcatf( res, "ifconfig %s\n", account->ifconfig_push ); @@ -374,31 +408,64 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ } +/** + * return a static string interpreting + * LDAP pf_[client|subnet]_default_accept + * suitable for pf_file insertion + */ +char * +la_ldap_default_rule_to_string( ternary_t rule ){ + if( rule == TERN_TRUE ) + return "ACCEPT"; + if( rule == TERN_FALSE ) + return "DROP"; + return ""; +} + +char * +ldap_profile_generate_pf_rules( ldap_profile_t *lp ){ + char *res = NULL; + res = strdupf("[CLIENTS %s]\n\ +%s\n\ +[SUBNETS %s]\n\ +%s\n\ +[END]\n", + la_ldap_default_rule_to_string( lp->pf_client_default_accept ), + lp->pf_client_rules ? lp->pf_client_rules : "", + la_ldap_default_rule_to_string( lp->pf_subnet_default_accept ), + lp->pf_subnet_rules ? lp->pf_subnet_rules : "" ); + LOGDEBUG("pf_rules = %s\n", res); + return res; +} + int ldap_profile_write_to_pf_file( char *pf_file, char *value ) { - int fd, rc; + int fd, rc = 0; if( pf_file == NULL ){ LOGERROR( "pf_file is null\n"); - return -1; + return 1; } fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); if( fd == -1 ){ LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); - return -1; + return 1; } rc = write( fd, value, strlen(value) ); if( rc == -1 ){ LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); + rc = 1; }else if( rc !=strlen(value) ){ LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); + rc = 1; + }else{ + rc = 0; } - rc = close( fd ); - if( rc != 0 ){ + if( close( fd ) != 0 ){ LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); } - return rc == 0; + return rc; } @@ -409,7 +476,7 @@ ldap_profile_write_to_pf_file( char *pf_file, char *value ) */ int ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file){ - + int rc = 0; /* check if pf is enabled */ LOGDEBUG("Global:%s\tProfile:%s\tPF enable for this profile: %s\n", ternary_to_string(c->profile->enable_pf), @@ -418,21 +485,38 @@ ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp /* write to pf_file */ if( pf_file == NULL && config_is_pf_enabled(c) ){ LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); + return 1; }else if( pf_file ){ if( config_is_pf_enabled_for_profile( c, p) ){ - if( lp->pf_rules ){ - ldap_profile_write_to_pf_file( pf_file, lp->pf_rules ); + /* We only write PF rules from LDAP if + * pf_client_default_accept and pf_subnet_default_accept + * are defined + */ + if( lp->pf_client_default_accept != TERN_UNDEF && lp->pf_subnet_default_accept != TERN_UNDEF ){ + char *pf_rules = NULL; + pf_rules = ldap_profile_generate_pf_rules( lp ); + if( pf_rules ){ + rc = ldap_profile_write_to_pf_file( pf_file, pf_rules ); + la_free( pf_rules ); + }else{ + LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules\n"); + return 1; + } }else{ /* set up default pf_rules */ - /* TODO, set default pf rules per profiles */ - ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL); + /* + * If pf_client_default_accept or pf_subnet_default_accept + * is not defined, we default to openvpn standard behaviour: + * allow everything + */ + return ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL); } }else{ /* profile has PF disabled */ - ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL ); + return ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL ); } } - return 0; + return rc; } /** diff --git a/src/ldap_profile.h b/src/ldap_profile.h index 806ee15..f82eeab 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -35,9 +35,12 @@ typedef struct ldap_profile { time_t start_date; time_t end_date; - char *pf_rules; + ternary_t pf_client_default_accept; + ternary_t pf_subnet_default_accept; + char *pf_client_rules; + char *pf_subnet_rules; list_t *push_options; - uint8_t push_reset; + ternary_t push_reset; list_t *iroutes; char *config; } ldap_profile_t; From 8589d9a111858aee2afc8e73c33501949e14932a Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 04:24:34 +0200 Subject: [PATCH 17/44] Removing default profiles Accounts profile need to be defined within tags --- src/cnf.c | 89 ++++++++++++++++++++++++------------- src/cnf.h | 9 +++- src/defines.h | 1 - src/la_ldap.c | 16 +++---- src/ldap-auth.c | 8 +--- src/ldap_profile.c | 8 ++-- src/types.h | 1 + tests/openvpn-ldap-search.c | 85 +++++++++++++++++------------------ 8 files changed, 115 insertions(+), 102 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index d6fa435..f7f685e 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -34,6 +34,12 @@ #define STRPRINT_IFSET(a,prefix) if(a) fprintf(stderr, "%s:\t%s\n", prefix, a); #define STRDUP_IFNOTSET(a,b) if(!a && b) a=strdup(b); +#define CHECK_IF_IN_PROFILE(a,b) if(!b){ \ +LOGWARNING("%s is not defined within . It will be ignored\n", a);\ +free( line );\ +continue;\ +} + //#define STRDUP_IFNOTSET_NOTNULL(a, b) if( b ) STRDUP_IFNOTSET(a,b) void check_and_free( void *d ){ @@ -45,9 +51,6 @@ config_set_default( config_t *c){ #ifdef OURI if(OURI) STRDUP_IFNOTSET(c->ldap->uri, OURI ); #endif -#ifdef OBASEDN - STRDUP_IFNOTSET(c->profile->basedn, OBASEDN ); -#endif #ifdef OBINDDN STRDUP_IFNOTSET(c->ldap->binddn, OBINDDN ); #endif @@ -55,9 +58,6 @@ config_set_default( config_t *c){ STRDUP_IFNOTSET(c->ldap->bindpw, OBINDPW); #endif if(!c->ldap->ldap_version) c->ldap->ldap_version = OLDAP_VERSION; -#ifdef OSEARCH_FILTER - STRDUP_IFNOTSET(c->profile->search_filter, OSEARCH_FILTER ); -#endif #ifdef OSSL STRDUP_IFNOTSET(c->ldap->ssl, OSSL ); #endif @@ -158,6 +158,10 @@ profile_config_free ( profile_config_t *c ){ check_and_free( c->groupdn ); check_and_free( c->group_search_filter ); check_and_free( c->member_attribute ); +#ifdef ENABLE_LDAPUSERCONF + check_and_free( c->default_pf_rules ); + check_and_free( c->default_profiledn ); +#endif la_free( c ); } @@ -166,6 +170,7 @@ profile_config_list_free_cb( void *data ){ profile_config_t *c = data; profile_config_free( c ); } + profile_config_t * profile_config_new ( void ){ profile_config_t *c = la_malloc( sizeof( profile_config_t ) ); @@ -188,7 +193,11 @@ profile_config_dup( const profile_config_t *c ){ if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); +#ifdef ENABLE_LDAPUSERCONF + if( c->default_profiledn ) nc->default_profiledn = strdup( c->default_profiledn ); + if( c->default_pf_rules ) nc->default_pf_rules = strdup( c->default_pf_rules ); nc->enable_pf = c->enable_pf; +#endif return nc; } @@ -203,10 +212,9 @@ config_new( void ){ memset( c, 0, sizeof( config_t ) ); c->ldap = ldap_config_new( ); - c->profile = profile_config_new( ); c->profiles = list_new( ); - if( !(c->profiles && c->profile && c->ldap) ){ + if( !(c->profiles && c->ldap) ){ config_free( c ); return NULL; } @@ -218,16 +226,17 @@ config_dup( config_t *c ){ config_t *nc = NULL; profile_config_t *pgc = NULL; list_item_t *item = NULL; + ldap_config_t *l = NULL; if( !c ) return NULL; nc = config_new( ); if( !nc ) return NULL; + /* ldap */ + l = ldap_config_dup( c->ldap ); + ldap_config_free( nc->ldap ); + nc->ldap = l; - pgc = profile_config_dup( c->profile ); - - profile_config_free( nc->profile ); - nc->profile = pgc; - + /* profiles */ for( item = list_first(c->profiles); item; item = item->next ){ pgc = profile_config_dup( item->data ); list_append( nc->profiles, pgc ); @@ -240,7 +249,6 @@ config_dup( config_t *c ){ void config_free( config_t *c ){ if( !c ) return; - profile_config_free( c->profile ); ldap_config_free( c->ldap ); list_free( c->profiles, profile_config_list_free_cb ); la_free( c ); @@ -302,11 +310,11 @@ config_parse_file( const char *filename, config_t *c ){ } if( !strncmp( line, "", strlen( "" ) ) ){ in_profile = 0; + STRDUP_IFNOTSET(p->search_filter, OSEARCH_FILTER); p = NULL; free(line); continue; } - profile_config_t *current_profile = in_profile ? p : c->profile; arg = strtok( line, "=" ); if(arg && *arg != '\n'){ val = strtok( NULL, "\n"); @@ -335,27 +343,42 @@ config_parse_file( const char *filename, config_t *c ){ STRDUP_IFNOTSET(c->ldap->tls_reqcert, val ); }else if( !strcmp( arg, "timeout" ) ){ if( !c->ldap->timeout ) c->ldap->timeout = atoi(val); - /* global conf */ - }else if( !strcmp( arg, "enable_pf" ) ){ - current_profile->enable_pf = !(strcasecmp( val, "true") && strcasecmp( val, "on" ) && strcasecmp( val, "1")) ? TERN_TRUE : TERN_FALSE; + /* profile conf */ }else if ( !strcmp( arg, "basedn" ) ){ - STRDUP_IFNOTSET(current_profile->basedn, val ); + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->basedn, val ); }else if ( !strcmp( arg, "search_filter" ) ){ - STRDUP_IFNOTSET(current_profile->search_filter, val ); + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->search_filter, val ); }else if ( !strcmp( arg, "search_scope" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); if( !strcasecmp( val, "LDAP_SCOPE_BASE" ) ){ - current_profile->search_scope = LA_SCOPE_BASE; + p->search_scope = LA_SCOPE_BASE; }else if( !strcasecmp( val, "LDAP_SCOPE_ONELEVEL" ) ){ - current_profile->search_scope = LA_SCOPE_ONELEVEL; + p->search_scope = LA_SCOPE_ONELEVEL; }else if( !strcasecmp( val, "LDAP_SCOPE_SUBTREE" ) ){ - current_profile->search_scope = LA_SCOPE_SUBTREE; + p->search_scope = LA_SCOPE_SUBTREE; } }else if( !strcmp( arg, "groupdn" ) ){ - STRDUP_IFNOTSET(current_profile->groupdn, val ); + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->groupdn, val ); }else if( !strcmp( arg, "group_search_filter" ) ){ - STRDUP_IFNOTSET(current_profile->group_search_filter, val ); + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->group_search_filter, val ); }else if( !strcmp( arg, "member_attribute" ) ){ - STRDUP_IFNOTSET(current_profile->member_attribute, val ); + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->member_attribute, val ); +#ifdef ENABLE_LDAPUSERCONF + }else if( !strcmp( arg, "enable_pf" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); + p->enable_pf = string_to_ternary( val ); + }else if( !strcmp( arg, "default_pf_rules" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->default_pf_rules, val ); + }else if( !strcmp( arg, "default_profiledn" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->default_profiledn, val ); +#endif }else{ LOGWARNING("Unrecognized option *%s=%s*\n", arg, val); } @@ -388,6 +411,7 @@ config_dump( config_t *c){ fprintf( stderr, "\tSSL:\t%s\n", c->ldap->ssl ); fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->ldap_version ); fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); +#if 0 fprintf( stderr, "*Default Profile:*\n" ); STRPRINT_IFSET(c->profile->basedn, "\tBaseDN"); fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(c->profile->enable_pf)); @@ -397,6 +421,7 @@ config_dump( config_t *c){ STRPRINT_IFSET(c->profile->group_search_filter, "\tGroup Search Filter"); STRPRINT_IFSET(c->profile->member_attribute,"\tMember Attribute"); STRPRINT_IFSET(c->profile->profiledn,"\tProfile DN"); +#endif /* Dump each profiles */ list_item_t *item; profile_config_t *p; @@ -404,13 +429,17 @@ config_dump( config_t *c){ p = item->data; fprintf( stderr, "*Custom Profile:*\n" ); STRPRINT_IFSET(p->basedn, "\tBaseDN"); - fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); fprintf( stderr, "\tSearch Scope:\t%s\n", config_search_scope_to_string( p->search_scope ) ); fprintf( stderr, "\tSearch filter:\t%s\n", p->search_filter ); STRPRINT_IFSET(p->groupdn,"\tGroupDN"); STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); STRPRINT_IFSET(p->member_attribute,"\tMember Attribute"); STRPRINT_IFSET(p->profiledn,"\tProfile DN"); +#ifdef ENABLE_LDAPUSERCONF + fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); + fprintf( stderr, "\tDefault PF rules:\t%s\n", p->default_pf_rules ? p->default_pf_rules : "Undefined" ); + fprintf( stderr, "\tDefault Profile DN:\t%s\n", p->default_profiledn ? p->default_profiledn : "Undefined" ); +#endif } } @@ -419,8 +448,6 @@ int config_is_pf_enabled( config_t *c ){ int enabled = 0; list_item_t *item; - if( c->profile->enable_pf == TERN_TRUE ) - return 1; for( item = list_first( c->profiles ); item; item = item->next ){ profile_config_t *pc = item->data; @@ -433,7 +460,5 @@ config_is_pf_enabled( config_t *c ){ } int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ){ - return (c->profile->enable_pf != TERN_TRUE && p->enable_pf == TERN_TRUE) - || - ( c->profile->enable_pf == TERN_TRUE && p->enable_pf != TERN_FALSE); + return p->enable_pf == TERN_TRUE; } diff --git a/src/cnf.h b/src/cnf.h index ab5a842..dcfe1b0 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -24,6 +24,7 @@ #include "list.h" #include "types.h" +#include "config.h" typedef enum ldap_search_scope{ @@ -66,7 +67,12 @@ typedef struct profile_config{ char *group_search_filter; char *member_attribute; char *profiledn; - ternary_t enable_pf; +#ifdef ENABLE_LDAPUSERCONF + /* packet filtering */ + ternary_t enable_pf; + char *default_pf_rules; + char *default_profiledn; +#endif } profile_config_t; /** @@ -75,7 +81,6 @@ typedef struct profile_config{ */ typedef struct config{ ldap_config_t *ldap; - profile_config_t *profile; list_t *profiles; } config_t; diff --git a/src/defines.h b/src/defines.h index 9e34aae..e37c953 100644 --- a/src/defines.h +++ b/src/defines.h @@ -23,7 +23,6 @@ #define OURI "ldap://localhost" #define OLDAP_VERSION 3 -#define OBASEDN "ou=users,dc=example,dc=com" //#define OBINDDN NULL //#define OBINDPW NULL #define OSEARCH_FILTER "(uid=%u)" diff --git a/src/la_ldap.c b/src/la_ldap.c index d91c366..0719f38 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -157,8 +157,8 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char /* initialise timeout values */ la_ldap_set_timeout( config, &timeout ); - if( username && config->profile->search_filter ){ - search_filter = str_replace(config->profile->search_filter, "%u", username ); + if( username && p->search_filter ){ + search_filter = str_replace(p->search_filter, "%u", username ); } if( DODEBUG( ldap_context->verb ) ) LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); @@ -225,15 +225,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, config = ldap_context->config; - if( list_length( config->profiles ) == 0 ){ - p = config->profile; - userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); - if( userdn ){ - if( cc->user_dn ) la_free( cc->user_dn ); - cc->user_dn = strdup( userdn ); - cc->profile = p; - } - }else{ + if( list_length( config->profiles ) != 0 ){ for( item = list_first( config->profiles ); item; item = item->next ){ p = item->data; userdn = ldap_find_user_for_profile( ldap, ldap_context, username, p ); @@ -244,6 +236,8 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, break; } } + }else{ + LOGERROR("No profiles defined. Please make sure you have a section in your config.\n"); } return userdn; diff --git a/src/ldap-auth.c b/src/ldap-auth.c index cc4ba14..f9da6f4 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -224,17 +224,11 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char */ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); - while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:b:f:t:WZ" ) ) != - 1 ){ + while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:t:WZ" ) ) != - 1 ){ switch( rc ) { case 'H': context->config->ldap->uri = strdup(optarg); break; - case 'b': - context->config->profile->basedn = strdup(optarg); - break; - case 'f': - context->config->profile->search_filter = strdup(optarg); - break; case 'Z': context->config->ldap->ssl = strdup("start_tls"); break; diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 7cf9011..0e7e8ec 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -478,16 +478,14 @@ int ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file){ int rc = 0; /* check if pf is enabled */ - LOGDEBUG("Global:%s\tProfile:%s\tPF enable for this profile: %s\n", - ternary_to_string(c->profile->enable_pf), - ternary_to_string(p->enable_pf), - config_is_pf_enabled_for_profile( c, p) ? "TRUE" : "FALSE" ); + LOGDEBUG("PF enable for this profile: %s\n", + p->enable_pf == TERN_TRUE ? "TRUE" : "FALSE" ); /* write to pf_file */ if( pf_file == NULL && config_is_pf_enabled(c) ){ LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); return 1; }else if( pf_file ){ - if( config_is_pf_enabled_for_profile( c, p) ){ + if( p->enable_pf == TERN_TRUE ){ /* We only write PF rules from LDAP if * pf_client_default_accept and pf_subnet_default_accept * are defined diff --git a/src/types.h b/src/types.h index 0b5a1c6..3e48cdb 100644 --- a/src/types.h +++ b/src/types.h @@ -30,6 +30,7 @@ typedef enum ternary { } ternary_t; #define ternary_to_string(x) x == TERN_FALSE ? "False" : x == TERN_UNDEF ? "Undef" : "True" +#define string_to_ternary(x) strcasecmp(x,"true") || strcasecmp(x,"on") || strcasecmp(x,"1") ? TERN_TRUE : TERN_FALSE /* bool definitions */ #ifndef bool #define bool int diff --git a/tests/openvpn-ldap-search.c b/tests/openvpn-ldap-search.c index 3438de0..fa70e49 100644 --- a/tests/openvpn-ldap-search.c +++ b/tests/openvpn-ldap-search.c @@ -41,7 +41,7 @@ int debug = 0; void usage( char *prog ){ char *prg = strdup( prog ); char *name = basename( prog ); - fprintf( stderr, "USAGE: %s [-h] [-d] [-c configfile] [-D binddn] [-H ldap_uri] [-Z] [-f search_filter]\n\ + fprintf( stderr, "USAGE: %s [-h] [-d] [-c configfile] [-D binddn] [-H ldap_uri] [-Z]\n\ \t-h:\tprint this help\n\ \t-c:\tconfig file\n\ \t-f:\tsearch filter\n\ @@ -68,7 +68,7 @@ main( int argc, char **argv){ config = config_new( ); - while ( ( rc = getopt ( argc, argv, ":H:D:c:b:f:WZhdv" ) ) != - 1 ){ + while ( ( rc = getopt ( argc, argv, ":H:D:c:WZhdv" ) ) != - 1 ){ switch( rc ) { case 'h': usage( argv[0] ); @@ -76,12 +76,6 @@ main( int argc, char **argv){ case 'H': config->ldap->uri = strdup(optarg); break; - case 'b': - config->profile->basedn = strdup(optarg); - break; - case 'f': - config->profile->search_filter = strdup(optarg); - break; case 'Z': config->ldap->ssl = strdup("start_tls"); break; @@ -180,42 +174,45 @@ main( int argc, char **argv){ BerElement *ber; struct berval **vals; char *dn; - if( username && config->profile->search_filter ){ - filter = str_replace(config->profile->search_filter, "%u", username ); - } - printdebug("search Filter %s\nFinal filter: %s\n",config->profile->search_filter, filter); - rc = ldap_search_ext_s( ldap, config->profile->basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); - if( rc == LDAP_SUCCESS ){ - fprintf(stdout, "Search returned success\n"); - e = ldap_first_entry( ldap, result ); - if ( e != NULL ) { - do{ - dn = ldap_get_dn( ldap, e ); - fprintf( stdout, "DN: %s\n", dn ); - for ( a = ldap_first_attribute( ldap, e, &ber ); - a != NULL; a = ldap_next_attribute( ldap, e, ber ) ) { - if ((vals = ldap_get_values_len( ldap, e, a)) != NULL ) { - for ( i = 0; vals[i] != NULL; i++ ) { - printf( "%s: %s\n", a, vals[i]->bv_val ); + list_item_t *item; + for( item = list_first( config->profiles ); item; item = item->next ){ + profile_config_t *p = item->data; + if( username && p->search_filter ){ + filter = str_replace(p->search_filter, "%u", username ); + } + printdebug("search Filter %s\nFinal filter: %s\n",p->search_filter, filter); + rc = ldap_search_ext_s( ldap, p->basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); + if( rc == LDAP_SUCCESS ){ + fprintf(stdout, "Search returned success\n"); + e = ldap_first_entry( ldap, result ); + if ( e != NULL ) { + do{ + dn = ldap_get_dn( ldap, e ); + fprintf( stdout, "DN: %s\n", dn ); + for ( a = ldap_first_attribute( ldap, e, &ber ); + a != NULL; a = ldap_next_attribute( ldap, e, ber ) ) { + if ((vals = ldap_get_values_len( ldap, e, a)) != NULL ) { + for ( i = 0; vals[i] != NULL; i++ ) { + printf( "%s: %s\n", a, vals[i]->bv_val ); + } + ldap_value_free_len( vals ); } - ldap_value_free_len( vals ); + ldap_memfree( a ); + } + if ( dn != NULL ){ + ldap_memfree( dn ); + } + if ( ber != NULL ) { + ber_free( ber, 0 ); } - ldap_memfree( a ); - } - if ( dn != NULL ){ - ldap_memfree( dn ); - } - if ( ber != NULL ) { - ber_free( ber, 0 ); - } - }while( ( e = ldap_next_entry( ldap, e ) ) ); + }while( ( e = ldap_next_entry( ldap, e ) ) ); + } + ldap_msgfree( result ); + if( filter ) free( filter ); + }else{ + WARN( "Search returned error: %s", ldap_err2string( rc ) ); } - ldap_msgfree( result ); - - }else{ - WARN( "Search returned error: %s", ldap_err2string( rc ) ); - goto exit; - } + } #if 0 rc = ldap_compare_ext_s( ldap, bind_user, "givenname", &bv, NULL, NULL ); if( rc == LDAP_COMPARE_TRUE){ @@ -223,10 +220,10 @@ main( int argc, char **argv){ } #endif exit: - if( filter ) free( filter ); config_free( config ); - rc = ldap_unbind_ext_s( ldap, NULL, NULL ); - fprintf(stdout, "Unbind returned: %d\n", rc ); + rc = ldap_unbind_ext_s( ldap, NULL, NULL ); + fprintf(stdout, "Unbind returned: %d\n", rc ); + return 0; } From 4b908da6785e6562242a50c7729c4dfe591e424a Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 04:52:39 +0200 Subject: [PATCH 18/44] Fix crash if user not found in group search. Initialise result to NULL and only free if not NULL after search --- src/la_ldap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 0719f38..392192f 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -144,14 +144,13 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char struct timeval timeout; char *attrs[] = { NULL }; char *dn = NULL; - LDAPMessage *e, *result; + LDAPMessage *e, *result = NULL; config_t *config = NULL; int rc; char *search_filter = NULL; int ldap_scope = 0; - result = NULL; config = ldap_context->config; /* initialise timeout values */ @@ -331,7 +330,7 @@ int ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, client_context_t *cc ){ struct timeval timeout; char *attrs[] = { NULL }; - LDAPMessage *result; + LDAPMessage *result = NULL; config_t *config = NULL; char *search_filter = NULL; int rc; From 921190689bb7ec2125c4cb2d52c3d21c6f6e0320 Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 06:40:43 +0200 Subject: [PATCH 19/44] Handle default_pf_rules profile option If enable_pf is defined and either pf_client_default_accept or pf_subnet_default_accept is UNDEF, write the rule profided in conf If one of pf_*_default_accept is UNDEF and no default_pf_rules is defined, allow all traffic --- TODO | 6 ++++++ src/ldap_profile.c | 5 +++++ src/utils.c | 27 ++++++++++++++++++++++++++- src/utils.h | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 1a1021f..bf4705d 100644 --- a/TODO +++ b/TODO @@ -5,3 +5,9 @@ TLS: Handle the different TLS_REQCERT parameters ( never, allow, demand, try ) +User auth: +---------- +handle default_pf_rules and default_profiledn when not pf_rules/profiledn are found +default_profiledn: if user does not have a ovpnprofile dn, use this one as default +default_pf_rules: if not pf_rules are found for user, use this one instead of default to accept all + diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 0e7e8ec..84e9236 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -500,6 +500,11 @@ ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules\n"); return 1; } + }else if( p->default_pf_rules ){ + char *rules = str_replace_all( p->default_pf_rules, "\\n", "\n" ); + int res = ldap_profile_write_to_pf_file( pf_file, rules ); + if( rules ) la_free( rules ); + return res; }else{ /* set up default pf_rules */ /* diff --git a/src/utils.c b/src/utils.c index 06bf3cd..43a0a4a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -114,7 +114,32 @@ str_replace( const char *string, const char *substr, const char *replacement ){ return newstr; } - +char * +str_replace_all ( const char *string, const char *substr, const char *replacement ){ + char *tok = NULL; + char *newstr = NULL; + char *oldstr = NULL; + + /* if either substr or replacement is NULL, duplicate string a let caller + * handle it */ + if ( substr == NULL || replacement == NULL ) return strdup (string); + newstr = strdup (string); + while ( (tok = strstr ( newstr, substr ))){ + oldstr = newstr; + newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 ); + /*failed to alloc mem, free old string and return NULL */ + if ( newstr == NULL ){ + free (oldstr); + return NULL; + } + memcpy ( newstr, oldstr, tok - oldstr ); + memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) ); + memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) ); + memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 ); + free (oldstr); + } + return newstr; +} char *get_passwd( const char *prompt ){ struct termios old, new; diff --git a/src/utils.h b/src/utils.h index 1add865..576e002 100644 --- a/src/utils.h +++ b/src/utils.h @@ -50,6 +50,7 @@ extern char *strcatf( char *dest, const char *fmt, ...); * The caller is responsible for freeing this new string. */ extern char *str_replace( const char *string, const char *substr, const char *replacement ); +extern char *str_replace_all( const char *string, const char *substr, const char *replacement ); /* * Reads a password from stdin, the password is not echoed * to stdout From db455d33b2a55d826a235c06babd03dd93648c73 Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 17:38:53 +0200 Subject: [PATCH 20/44] Handle default_profiledn When an OpenVPNAccount has no OvpnProfile and default_profiledn is defined in config, fetch that info and use it. --- src/la_ldap.c | 2 +- src/ldap_profile.c | 12 ++++++++---- src/ldap_profile.h | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 392192f..daab4d3 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -427,7 +427,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); #ifdef ENABLE_LDAPUSERCONF /* load user settings from LDAP profile */ - ldap_account_load_from_dn( l, ldap, userdn, client_context->ldap_account ); + ldap_account_load_from_dn( l, ldap, userdn, client_context ); /* check if user timeframe is allowed start_date, end_date */ if( ldap_profile_handle_allowed_timeframe( client_context->ldap_account->profile ) != 0 ){ res = OPENVPN_PLUGIN_FUNC_ERROR; diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 84e9236..b26f6e1 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -149,9 +149,9 @@ la_ldap_bool_to_ternary( char *value ){ if( value == NULL ) return TERN_UNDEF; - if( strcasecmp( value, "true" ) == 0 || strcasecmp( value, "on" )) + if( strcasecmp( value, "true" ) == 0 || strcasecmp( value, "on" ) == 0) return TERN_TRUE; - if( strcasecmp( value, "false" ) == 0 || strcasecmp( value, "off" )) + if( strcasecmp( value, "false" ) == 0 || strcasecmp( value, "off" ) == 0) return TERN_FALSE; return TERN_UNDEF; } @@ -272,12 +272,13 @@ ldap_account_load_from_entry( LDAP *ldap, LDAPMessage *e, ldap_account_t *accoun * returns 0 on success, non 0 otherwise */ int -ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ){ +ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, client_context_t *cc ){ /** * retrieve info from user settings * if user has a profile, get info from that profile */ struct timeval timeout; + ldap_account_t *account = cc->ldap_account; char *attrs[] = { NULL }; LDAPMessage *e, *result; config_t *config = NULL; @@ -343,12 +344,15 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, l ldap_value_free_len( vals ); if( account->profile_dn ){ - ldap_account_load_from_dn( ldap_context, ldap, account->profile_dn, account ); + ldap_account_load_from_dn( ldap_context, ldap, account->profile_dn, cc ); } }else{ /* reset ld_errno */ int ec = LDAP_SUCCESS; ldap_set_option( ldap, LDAP_OPT_ERROR_NUMBER, &ec ); + if( cc->profile->default_profiledn ){ + ldap_account_load_from_dn( ldap_context, ldap, cc->profile->default_profiledn, cc ); + } } } ldap_account_load_from_entry( ldap, e, account ); diff --git a/src/ldap_profile.h b/src/ldap_profile.h index f82eeab..767c489 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -27,6 +27,7 @@ #include "utils.h" #include "action.h" #include "la_ldap.h" +#include "client_context.h" #define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" @@ -87,7 +88,7 @@ extern void ldap_account_dump( ldap_account_t *l ); * returns 0 on success, non 0 otherwise */ -extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, ldap_account_t *account ); +extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, client_context_t *cc ); /** * Returns a string that is suitable to pass options to openvpn From 53bc553e5124b933c87459a35d5e81fe91338eb0 Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 18:28:38 +0200 Subject: [PATCH 21/44] Compile with --disable-ldapuserconf --- src/cnf.c | 3 ++- src/cnf.h | 3 ++- src/ldap_profile.c | 8 ++++++-- src/ldap_profile.h | 5 +++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index f7f685e..457a29f 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -443,7 +443,7 @@ config_dump( config_t *c){ } } - +#ifdef ENABLE_LDAPUSERCONF int config_is_pf_enabled( config_t *c ){ int enabled = 0; @@ -462,3 +462,4 @@ int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ){ return p->enable_pf == TERN_TRUE; } +#endif diff --git a/src/cnf.h b/src/cnf.h index dcfe1b0..bf3d066 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -91,7 +91,8 @@ extern config_t *config_dup( config_t *c ); extern void config_free( config_t *c ); extern void config_dump( config_t *c ); extern void config_set_default( config_t *c ); - +#ifdef ENABLE_LDAPUSERCONF extern int config_is_pf_enabled( config_t *c ); extern int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ); +#endif #endif /* _CNF_H_ */ diff --git a/src/ldap_profile.c b/src/ldap_profile.c index b26f6e1..ccbe348 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -19,10 +19,13 @@ * */ -#define DODEBUG(verb) ((verb) >= 4) -#include "debug.h" #include "ldap_profile.h" + +#ifdef ENABLE_LDAPUSERCONF + +#define DODEBUG(verb) ((verb) >= 4) +#include "debug.h" #include "utils.h" #include @@ -546,3 +549,4 @@ ldap_profile_handle_allowed_timeframe( ldap_profile_t *p ){ +#endif diff --git a/src/ldap_profile.h b/src/ldap_profile.h index 767c489..ab2613f 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -22,6 +22,10 @@ #ifndef __LDAP_PROFILE_H__ #define __LDAP_PROFILE_H__ +#include "config.h" + +#ifdef ENABLE_LDAPUSERCONF + #include "cnf.h" #include "list.h" #include "utils.h" @@ -113,4 +117,5 @@ extern int ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_pr */ extern int ldap_profile_handle_allowed_timeframe( ldap_profile_t *p ); +#endif /* ENABLE_LDAPUSERCONF */ #endif /* __LDAP_PROFILE_H__ */ From 6980d1a5a5bb805f5ad4fac8537149fc75610980 Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 30 Jul 2010 22:30:17 +0200 Subject: [PATCH 22/44] Allow PF withouht ldap userconfig backend Per profile PF rules can be set using: * enable_pf * default_pf_rules If no rules found, accept all config items can have whitespaces in front of them --- src/cnf.c | 29 +++++---- src/cnf.h | 5 +- src/la_ldap.c | 143 ++++++++++++++++++++++++++++++++++++++++++++- src/ldap-auth.c | 7 ++- src/ldap_profile.c | 123 -------------------------------------- src/ldap_profile.h | 11 ---- 6 files changed, 165 insertions(+), 153 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index 457a29f..288e6e7 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -31,6 +31,7 @@ #include #include #include +#include /* isspace */ #define STRPRINT_IFSET(a,prefix) if(a) fprintf(stderr, "%s:\t%s\n", prefix, a); #define STRDUP_IFNOTSET(a,b) if(!a && b) a=strdup(b); @@ -158,8 +159,8 @@ profile_config_free ( profile_config_t *c ){ check_and_free( c->groupdn ); check_and_free( c->group_search_filter ); check_and_free( c->member_attribute ); -#ifdef ENABLE_LDAPUSERCONF check_and_free( c->default_pf_rules ); +#ifdef ENABLE_LDAPUSERCONF check_and_free( c->default_profiledn ); #endif la_free( c ); @@ -193,10 +194,10 @@ profile_config_dup( const profile_config_t *c ){ if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); -#ifdef ENABLE_LDAPUSERCONF - if( c->default_profiledn ) nc->default_profiledn = strdup( c->default_profiledn ); if( c->default_pf_rules ) nc->default_pf_rules = strdup( c->default_pf_rules ); nc->enable_pf = c->enable_pf; +#ifdef ENABLE_LDAPUSERCONF + if( c->default_profiledn ) nc->default_profiledn = strdup( c->default_profiledn ); #endif return nc; @@ -276,6 +277,12 @@ f_readline( int fd ){ } +char * +skip_whitespaces( char *l ){ + while(isspace(l[0])) + l++; + return l; +} int config_parse_file( const char *filename, config_t *c ){ @@ -292,11 +299,12 @@ config_parse_file( const char *filename, config_t *c ){ } val = NULL; while ( ( line = f_readline( fd ) ) ){ - if( line[0] == '#' || line[0] == ';' ){ + arg = skip_whitespaces( line ); + if( arg[0] == '#' || arg[0] == ';' ){ free(line); continue; } - if( !strncmp( line, "", strlen( "" ) ) ){ + if( !strncmp( arg, "", strlen( "" ) ) ){ in_profile = 1; p = profile_config_new( ); free(line); @@ -308,14 +316,14 @@ config_parse_file( const char *filename, config_t *c ){ list_append( c->profiles, p ); continue; } - if( !strncmp( line, "", strlen( "" ) ) ){ + if( !strncmp( arg, "", strlen( "" ) ) ){ in_profile = 0; STRDUP_IFNOTSET(p->search_filter, OSEARCH_FILTER); p = NULL; free(line); continue; } - arg = strtok( line, "=" ); + arg = strtok( arg, "=" ); if(arg && *arg != '\n'){ val = strtok( NULL, "\n"); /* global conf -> ldap */ @@ -368,13 +376,13 @@ config_parse_file( const char *filename, config_t *c ){ }else if( !strcmp( arg, "member_attribute" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); STRDUP_IFNOTSET(p->member_attribute, val ); -#ifdef ENABLE_LDAPUSERCONF }else if( !strcmp( arg, "enable_pf" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); p->enable_pf = string_to_ternary( val ); }else if( !strcmp( arg, "default_pf_rules" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); STRDUP_IFNOTSET(p->default_pf_rules, val ); +#ifdef ENABLE_LDAPUSERCONF }else if( !strcmp( arg, "default_profiledn" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); STRDUP_IFNOTSET(p->default_profiledn, val ); @@ -435,15 +443,15 @@ config_dump( config_t *c){ STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); STRPRINT_IFSET(p->member_attribute,"\tMember Attribute"); STRPRINT_IFSET(p->profiledn,"\tProfile DN"); -#ifdef ENABLE_LDAPUSERCONF fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); fprintf( stderr, "\tDefault PF rules:\t%s\n", p->default_pf_rules ? p->default_pf_rules : "Undefined" ); +#ifdef ENABLE_LDAPUSERCONF fprintf( stderr, "\tDefault Profile DN:\t%s\n", p->default_profiledn ? p->default_profiledn : "Undefined" ); #endif } } -#ifdef ENABLE_LDAPUSERCONF + int config_is_pf_enabled( config_t *c ){ int enabled = 0; @@ -462,4 +470,3 @@ int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ){ return p->enable_pf == TERN_TRUE; } -#endif diff --git a/src/cnf.h b/src/cnf.h index bf3d066..44e7fec 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -67,10 +67,11 @@ typedef struct profile_config{ char *group_search_filter; char *member_attribute; char *profiledn; -#ifdef ENABLE_LDAPUSERCONF /* packet filtering */ ternary_t enable_pf; char *default_pf_rules; +#ifdef ENABLE_LDAPUSERCONF + /* default profiledn for ldap user conf */ char *default_profiledn; #endif } profile_config_t; @@ -91,8 +92,6 @@ extern config_t *config_dup( config_t *c ); extern void config_free( config_t *c ); extern void config_dump( config_t *c ); extern void config_set_default( config_t *c ); -#ifdef ENABLE_LDAPUSERCONF extern int config_is_pf_enabled( config_t *c ); extern int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ); -#endif #endif /* _CNF_H_ */ diff --git a/src/la_ldap.c b/src/la_ldap.c index daab4d3..15674bd 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -34,6 +34,13 @@ #include "ldap_profile.h" #endif +#include +#include +#include +#include + +#define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" + void ldap_context_free( ldap_context_t *l ){ if( !l ) return; @@ -131,6 +138,138 @@ la_ldap_ldap_scope_to_string( int scope ){ } return NULL; } + +/** + * PF handling + */ + +/** + * return a static string interpreting + * LDAP pf_[client|subnet]_default_accept + * suitable for pf_file insertion + */ +char * +la_ldap_default_rule_to_string( ternary_t rule ){ + if( rule == TERN_TRUE ) + return "ACCEPT"; + if( rule == TERN_FALSE ) + return "DROP"; + return ""; +} + +#ifdef ENABLE_LDAPUSERCONF +char * +la_ldap_generate_pf_rules( ldap_profile_t *lp ){ + char *res = NULL; + res = strdupf("[CLIENTS %s]\n\ +%s\n\ +[SUBNETS %s]\n\ +%s\n\ +[END]\n", + la_ldap_default_rule_to_string( lp->pf_client_default_accept ), + lp->pf_client_rules ? lp->pf_client_rules : "", + la_ldap_default_rule_to_string( lp->pf_subnet_default_accept ), + lp->pf_subnet_rules ? lp->pf_subnet_rules : "" ); + LOGDEBUG("pf_rules = %s\n", res); + return res; +} +#endif + +int +la_ldap_write_to_pf_file( char *pf_file, char *value ) +{ + int fd, rc = 0; + if( pf_file == NULL ){ + LOGERROR( "pf_file is null\n"); + return 1; + } + + fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); + if( fd == -1 ){ + LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + return 1; + } + rc = write( fd, value, strlen(value) ); + if( rc == -1 ){ + LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); + rc = 1; + }else if( rc !=strlen(value) ){ + LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); + rc = 1; + }else{ + rc = 0; + } + if( close( fd ) != 0 ){ + LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + } + return rc; +} + + +/** + * la_ldap_handle_pf_file + * Given the plugin config and the client_context + * will write to pf_file the right + */ +int +la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ + profile_config_t *p = cc->profile; + int rc = 0; + + /* check if pf is enabled */ + LOGDEBUG("PF enable for this profile: %s\n", + p->enable_pf == TERN_TRUE ? "TRUE" : "FALSE" ); + /* write to pf_file */ + if( pf_file == NULL && config_is_pf_enabled(c) ){ + LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); + return 1; + }else if( pf_file ){ + if( p->enable_pf == TERN_TRUE ){ +#ifdef ENABLE_LDAPUSERCONF + ldap_profile_t *lp = cc->ldap_account->profile; + /* We only write PF rules from LDAP if + * pf_client_default_accept and pf_subnet_default_accept + * are defined + */ + if( lp->pf_client_default_accept != TERN_UNDEF && lp->pf_subnet_default_accept != TERN_UNDEF ){ + char *pf_rules = NULL; + pf_rules = la_ldap_generate_pf_rules( lp ); + if( pf_rules ){ + LOGDEBUG("Using PF rules from ldap backend\n"); + rc = la_ldap_write_to_pf_file( pf_file, pf_rules ); + la_free( pf_rules ); + }else{ + LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules\n"); + return 1; + } + }else +#endif + if( p->default_pf_rules ){ + LOGDEBUG("Using default PF rules from config\n"); + char *rules = str_replace_all( p->default_pf_rules, "\\n", "\n" ); + int res = la_ldap_write_to_pf_file( pf_file, rules ); + if( rules ) la_free( rules ); + return res; + }else{ + /* set up default pf_rules */ + /* + * If pf_client_default_accept or pf_subnet_default_accept + * is not defined, we default to openvpn standard behaviour: + * allow everything + */ + LOGDEBUG("No PF rules found, default to accept all\n"); + return la_ldap_write_to_pf_file( pf_file, PF_ALLOW_ALL); + } + }else{ + /* profile has PF disabled */ + LOGDEBUG("PF rules disabled for this profile, default to accept all\n"); + return la_ldap_write_to_pf_file( pf_file, PF_ALLOW_ALL ); + } + } + return rc; +} + + /** * Search for a user's DN given a config profile * On success, return userdn (much be freed by caller) @@ -433,10 +572,10 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ res = OPENVPN_PLUGIN_FUNC_ERROR; goto la_ldap_handle_authentication_free; } - /* handle pf_rules if any, default value otherwise */ - ldap_profile_handle_pf_file( config, client_context->profile, client_context->ldap_account->profile, auth_context->pf_file ); /* ldap_account_dump( client_context->ldap_account ); */ #endif + /* handle pf_rules if any, default value otherwise */ + la_ldap_handle_pf_file( config, client_context, auth_context->pf_file ); /* check if user belong to right groups */ if( client_context->profile->groupdn && client_context->profile->group_search_filter && client_context->profile->member_attribute ){ diff --git a/src/ldap-auth.c b/src/ldap-auth.c index f9da6f4..1d3f00d 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -270,11 +270,11 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char * Get verbosity level from environment */ -#ifdef ENABLE_LDAPUSERCONF /* when ldap userconf is define, we need to hook onto those callbacks */ if( config_is_pf_enabled( context->config )){ *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); } +#ifdef ENABLE_LDAPUSERCONF *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT); #endif @@ -405,13 +405,14 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, return OPENVPN_PLUGIN_FUNC_DEFERRED; } -#ifdef ENABLE_LDAPUSERCONF else if (type == OPENVPN_PLUGIN_ENABLE_PF){ /* unfortunately, at this stage we dont know anything about the client * yet. Let assume it is enabled, we will define default somewhere */ return OPENVPN_PLUGIN_FUNC_SUCCESS; - }else if( type == OPENVPN_PLUGIN_CLIENT_CONNECT_V2 ){ + } +#ifdef ENABLE_LDAPUSERCONF + else if( type == OPENVPN_PLUGIN_CLIENT_CONNECT_V2 ){ /* on client connect, we return conf options through return list */ client_context_t *cc = per_client_context; diff --git a/src/ldap_profile.c b/src/ldap_profile.c index ccbe348..947b249 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -33,12 +33,6 @@ #include #include -#include -#include -#include -#include - - ldap_profile_t * ldap_profile_new( ){ @@ -414,121 +408,6 @@ ldap_account_get_options_to_string( ldap_account_t *account ){ return res; } - -/** - * return a static string interpreting - * LDAP pf_[client|subnet]_default_accept - * suitable for pf_file insertion - */ -char * -la_ldap_default_rule_to_string( ternary_t rule ){ - if( rule == TERN_TRUE ) - return "ACCEPT"; - if( rule == TERN_FALSE ) - return "DROP"; - return ""; -} - -char * -ldap_profile_generate_pf_rules( ldap_profile_t *lp ){ - char *res = NULL; - res = strdupf("[CLIENTS %s]\n\ -%s\n\ -[SUBNETS %s]\n\ -%s\n\ -[END]\n", - la_ldap_default_rule_to_string( lp->pf_client_default_accept ), - lp->pf_client_rules ? lp->pf_client_rules : "", - la_ldap_default_rule_to_string( lp->pf_subnet_default_accept ), - lp->pf_subnet_rules ? lp->pf_subnet_rules : "" ); - LOGDEBUG("pf_rules = %s\n", res); - return res; -} - -int -ldap_profile_write_to_pf_file( char *pf_file, char *value ) -{ - int fd, rc = 0; - if( pf_file == NULL ){ - LOGERROR( "pf_file is null\n"); - return 1; - } - - fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); - if( fd == -1 ){ - LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); - return 1; - } - rc = write( fd, value, strlen(value) ); - if( rc == -1 ){ - LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); - rc = 1; - }else if( rc !=strlen(value) ){ - LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); - rc = 1; - }else{ - rc = 0; - } - if( close( fd ) != 0 ){ - LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); - } - return rc; -} - - -/** - * la_ldap_handle_pf_file - * Given the plugin config and the client_context - * will write to pf_file the right - */ -int -ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file){ - int rc = 0; - /* check if pf is enabled */ - LOGDEBUG("PF enable for this profile: %s\n", - p->enable_pf == TERN_TRUE ? "TRUE" : "FALSE" ); - /* write to pf_file */ - if( pf_file == NULL && config_is_pf_enabled(c) ){ - LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); - return 1; - }else if( pf_file ){ - if( p->enable_pf == TERN_TRUE ){ - /* We only write PF rules from LDAP if - * pf_client_default_accept and pf_subnet_default_accept - * are defined - */ - if( lp->pf_client_default_accept != TERN_UNDEF && lp->pf_subnet_default_accept != TERN_UNDEF ){ - char *pf_rules = NULL; - pf_rules = ldap_profile_generate_pf_rules( lp ); - if( pf_rules ){ - rc = ldap_profile_write_to_pf_file( pf_file, pf_rules ); - la_free( pf_rules ); - }else{ - LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules\n"); - return 1; - } - }else if( p->default_pf_rules ){ - char *rules = str_replace_all( p->default_pf_rules, "\\n", "\n" ); - int res = ldap_profile_write_to_pf_file( pf_file, rules ); - if( rules ) la_free( rules ); - return res; - }else{ - /* set up default pf_rules */ - /* - * If pf_client_default_accept or pf_subnet_default_accept - * is not defined, we default to openvpn standard behaviour: - * allow everything - */ - return ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL); - } - }else{ - /* profile has PF disabled */ - return ldap_profile_write_to_pf_file( pf_file, PF_ALLOW_ALL ); - } - } - return rc; -} - /** * la_ldap_handle_allowed_timeframe * check if a user LDAP profile can log in @@ -547,6 +426,4 @@ ldap_profile_handle_allowed_timeframe( ldap_profile_t *p ){ return 0; } - - #endif diff --git a/src/ldap_profile.h b/src/ldap_profile.h index ab2613f..5abcf5a 100644 --- a/src/ldap_profile.h +++ b/src/ldap_profile.h @@ -34,7 +34,6 @@ #include "client_context.h" -#define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" typedef struct ldap_profile { @@ -100,16 +99,6 @@ extern int ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, extern char *ldap_account_get_options_to_string( ldap_account_t *account ); -/* write a value to pf_file */ -extern int ldap_profile_write_to_pf_file( char *pf_file, char *value ); - -/** - * la_ldap_handle_pf_file - * Given the plugin config, used profile_config and ldap_profile - * will write to pf_file the right - */ -extern int ldap_profile_handle_pf_file(config_t *c, profile_config_t *p, ldap_profile_t *lp, char *pf_file); - /** * la_ldap_handle_allowed_timeframe * check if a user LDAP profile can log in From 10d5da4c0e413a1c52fa66a538e3e2e7846a4d0e Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 3 Aug 2010 11:24:28 +0200 Subject: [PATCH 23/44] Handle ldap version from config correctly It use to expect *ldap_version* parameter instead of *version* --- src/cnf.c | 10 +++++----- src/cnf.h | 2 +- src/la_ldap.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index 288e6e7..1637fff 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -58,7 +58,7 @@ config_set_default( config_t *c){ #ifdef OBINDPW STRDUP_IFNOTSET(c->ldap->bindpw, OBINDPW); #endif - if(!c->ldap->ldap_version) c->ldap->ldap_version = OLDAP_VERSION; + if(!c->ldap->version) c->ldap->version = OLDAP_VERSION; #ifdef OSSL STRDUP_IFNOTSET(c->ldap->ssl, OSSL ); #endif @@ -131,7 +131,7 @@ ldap_config_dup( const ldap_config_t *c ){ if( c->uri ) nc->uri = strdup( c->uri ); if( c->binddn ) nc->binddn = strdup( c->binddn ); if( c->bindpw ) nc->bindpw = strdup( c->bindpw ); - nc->ldap_version = c->ldap_version; + nc->version = c->version; if( c->ssl ) nc->ssl = strdup( c->ssl ); if( c->tls_cacertfile ) nc->tls_cacertfile = strdup( c->tls_cacertfile ); if( c->tls_cacertdir ) nc->tls_cacertdir = strdup( c->tls_cacertdir ); @@ -333,8 +333,8 @@ config_parse_file( const char *filename, config_t *c ){ STRDUP_IFNOTSET(c->ldap->binddn, val ); }else if ( !strcmp( arg, "bindpw" ) ) { STRDUP_IFNOTSET(c->ldap->bindpw, val ); - }else if ( !strcmp( arg, "ldap_version" ) ){ - if(!c->ldap->ldap_version) c->ldap->ldap_version = atoi(val); + }else if ( !strcmp( arg, "version" ) ){ + if(!c->ldap->version) c->ldap->version = atoi(val); }else if ( !strcmp( arg, "ssl" ) ){ STRDUP_IFNOTSET(c->ldap->ssl, val ); }else if ( !strcmp( arg, "tls_cacertfile" ) ){ @@ -417,7 +417,7 @@ config_dump( config_t *c){ STRPRINT_IFSET(c->ldap->uri,"\tURI"); STRPRINT_IFSET(c->ldap->binddn,"\tBindDN"); fprintf( stderr, "\tSSL:\t%s\n", c->ldap->ssl ); - fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->ldap_version ); + fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->version ); fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); #if 0 fprintf( stderr, "*Default Profile:*\n" ); diff --git a/src/cnf.h b/src/cnf.h index 44e7fec..60515ce 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -43,7 +43,7 @@ typedef struct ldap_config{ char *binddn; char *bindpw; - int ldap_version; + int version; int timeout; /* TLS/SSL */ diff --git a/src/la_ldap.c b/src/la_ldap.c index 15674bd..1372f17 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -401,9 +401,9 @@ connect_ldap( ldap_context_t *l ){ goto connect_ldap_error; } /* Version */ - rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->ldap_version)); + rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->version)); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"\n", config->ldap->ldap_version, rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"\n", config->ldap->version, rc, ldap_err2string(rc) ); goto connect_ldap_error; } /* Timeout */ From fef8c94376c19b80bb4c10e42e6c076cc12e4457 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 3 Aug 2010 17:06:10 +0200 Subject: [PATCH 24/44] Reintegrating default_gw_hack --- src/cnf.c | 61 ++++++++++++++++++++++------------ src/cnf.h | 8 +++-- src/la_ldap.c | 13 ++++++-- src/ldap-auth.c | 38 ++++++++++++++++++--- tests/openvpn-ldap-auth-test.c | 2 ++ tests/openvpn-ldap-search.c | 2 +- 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/src/cnf.c b/src/cnf.c index 1637fff..327c696 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -83,15 +83,6 @@ config_set_default( config_t *c){ #ifdef OTIMEOUT if( !c->ldap->timeout ) c->ldap->timeout = OTIMEOUT; #endif -#ifdef OGROUPDN - STRDUP_IFNOTSET(c->profile->groupdn, OGROUPDN ); -#endif -#ifdef OGROUP_SEARCH_FILTER - STRDUP_IFNOTSET(c->profile->group_search_filter, OGROUP_SEARCH_FILTER ); -#endif -#ifdef OMEMBER_ATRIBUTE - STRDUP_IFNOTSET(c->profile->member_attribute, OMEMBER_ATRIBUTE ); -#endif } @@ -160,6 +151,9 @@ profile_config_free ( profile_config_t *c ){ check_and_free( c->group_search_filter ); check_and_free( c->member_attribute ); check_and_free( c->default_pf_rules ); + /* redirect gateway */ + check_and_free( c->redirect_gateway_prefix ); + check_and_free( c->redirect_gateway_flags ); #ifdef ENABLE_LDAPUSERCONF check_and_free( c->default_profiledn ); #endif @@ -191,11 +185,16 @@ profile_config_dup( const profile_config_t *c ){ if( c->basedn ) nc->basedn = strdup( c->basedn ); if( c->search_filter ) nc->search_filter = strdup( c->search_filter ); nc->search_scope = c->search_scope; + /* Group */ if( c->groupdn ) nc->groupdn = strdup( c->groupdn ); if( c->group_search_filter ) nc->group_search_filter = strdup( c->group_search_filter ); if( c->member_attribute ) nc->member_attribute = strdup( c->member_attribute ); + /* PF */ if( c->default_pf_rules ) nc->default_pf_rules = strdup( c->default_pf_rules ); nc->enable_pf = c->enable_pf; + /* default gw */ + if( c->redirect_gateway_prefix ) nc->redirect_gateway_prefix = strdup( c->redirect_gateway_prefix ); + if( c->redirect_gateway_flags ) nc->redirect_gateway_flags = strdup( c->redirect_gateway_flags ); #ifdef ENABLE_LDAPUSERCONF if( c->default_profiledn ) nc->default_profiledn = strdup( c->default_profiledn ); #endif @@ -367,6 +366,7 @@ config_parse_file( const char *filename, config_t *c ){ }else if( !strcasecmp( val, "LDAP_SCOPE_SUBTREE" ) ){ p->search_scope = LA_SCOPE_SUBTREE; } + /* Group */ }else if( !strcmp( arg, "groupdn" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); STRDUP_IFNOTSET(p->groupdn, val ); @@ -376,6 +376,14 @@ config_parse_file( const char *filename, config_t *c ){ }else if( !strcmp( arg, "member_attribute" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); STRDUP_IFNOTSET(p->member_attribute, val ); + /* Default GW */ + }else if( !strcmp( arg, "redirect_gateway_prefix" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->redirect_gateway_prefix, val ); + }else if( !strcmp( arg, "redirect_gateway_flags" ) ){ + CHECK_IF_IN_PROFILE( arg, in_profile ); + STRDUP_IFNOTSET(p->redirect_gateway_flags, val ); + /* PF */ }else if( !strcmp( arg, "enable_pf" ) ){ CHECK_IF_IN_PROFILE( arg, in_profile ); p->enable_pf = string_to_ternary( val ); @@ -419,17 +427,6 @@ config_dump( config_t *c){ fprintf( stderr, "\tSSL:\t%s\n", c->ldap->ssl ); fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->version ); fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); -#if 0 - fprintf( stderr, "*Default Profile:*\n" ); - STRPRINT_IFSET(c->profile->basedn, "\tBaseDN"); - fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(c->profile->enable_pf)); - fprintf( stderr, "\tSearch Scope:\t%s\n", config_search_scope_to_string( c->profile->search_scope ) ); - fprintf( stderr, "\tSearch filter:\t%s\n", c->profile->search_filter ); - STRPRINT_IFSET(c->profile->groupdn,"\tGroupDN"); - STRPRINT_IFSET(c->profile->group_search_filter, "\tGroup Search Filter"); - STRPRINT_IFSET(c->profile->member_attribute,"\tMember Attribute"); - STRPRINT_IFSET(c->profile->profiledn,"\tProfile DN"); -#endif /* Dump each profiles */ list_item_t *item; profile_config_t *p; @@ -442,7 +439,6 @@ config_dump( config_t *c){ STRPRINT_IFSET(p->groupdn,"\tGroupDN"); STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); STRPRINT_IFSET(p->member_attribute,"\tMember Attribute"); - STRPRINT_IFSET(p->profiledn,"\tProfile DN"); fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); fprintf( stderr, "\tDefault PF rules:\t%s\n", p->default_pf_rules ? p->default_pf_rules : "Undefined" ); #ifdef ENABLE_LDAPUSERCONF @@ -467,6 +463,27 @@ config_is_pf_enabled( config_t *c ){ return enabled; } int -config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ){ +config_is_pf_enabled_for_profile( profile_config_t *p ){ return p->enable_pf == TERN_TRUE; } + +int +config_is_redirect_gw_enabled( config_t *c ){ + int enabled = 0; + list_item_t *item; + profile_config_t *pc = NULL; + + for( item = list_first( c->profiles ); item; item = item->next ){ + pc = item->data; + if( pc->redirect_gateway_prefix != NULL ){ + enabled = 1; + break; + } + } + return enabled; +} + +int +config_is_redirect_gw_enabled_for_profile( profile_config_t *p ){ + return p->redirect_gateway_prefix != NULL; +} diff --git a/src/cnf.h b/src/cnf.h index 60515ce..0545bfd 100644 --- a/src/cnf.h +++ b/src/cnf.h @@ -66,7 +66,9 @@ typedef struct profile_config{ char *groupdn; char *group_search_filter; char *member_attribute; - char *profiledn; + /* default gw hack */ + char *redirect_gateway_prefix; + char *redirect_gateway_flags; /* packet filtering */ ternary_t enable_pf; char *default_pf_rules; @@ -93,5 +95,7 @@ extern void config_free( config_t *c ); extern void config_dump( config_t *c ); extern void config_set_default( config_t *c ); extern int config_is_pf_enabled( config_t *c ); -extern int config_is_pf_enabled_for_profile( config_t *c, profile_config_t *p ); +extern int config_is_pf_enabled_for_profile( profile_config_t *p ); +extern int config_is_redirect_gw_enabled( config_t *c ); +extern int config_is_redirect_gw_enabled_for_profile( profile_config_t *p ); #endif /* _CNF_H_ */ diff --git a/src/la_ldap.c b/src/la_ldap.c index 1372f17..eec611e 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -280,6 +280,7 @@ la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ char * ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char *username, profile_config_t *p){ char *userdn = NULL; + char *real_username = NULL; struct timeval timeout; char *attrs[] = { NULL }; char *dn = NULL; @@ -295,9 +296,17 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char /* initialise timeout values */ la_ldap_set_timeout( config, &timeout ); - if( username && p->search_filter ){ - search_filter = str_replace(p->search_filter, "%u", username ); + if( p->redirect_gateway_prefix + && strncmp( p->redirect_gateway_prefix, username, strlen( p->redirect_gateway_prefix ) ) == 0 ){ + real_username = strdup( username + strlen( p->redirect_gateway_prefix ) ); + }else{ + real_username = strdup( username ); + } + if( real_username && p->search_filter ){ + search_filter = str_replace(p->search_filter, "%u", real_username ); } + if( real_username ) la_free( real_username ); + if( DODEBUG( ldap_context->verb ) ) LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); ldap_scope = la_ldap_config_search_scope_to_ldap( p->search_scope ); diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 1d3f00d..7f08b3f 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -58,6 +58,7 @@ #include "ldap_profile.h" #define DODEBUG(verb) ((verb) >= 4) +#define DFT_REDIRECT_GATEWAY_FLAGS "def1 bypass-dhcp" pthread_mutex_t action_mutex; pthread_cond_t action_cond; @@ -277,6 +278,10 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char #ifdef ENABLE_LDAPUSERCONF *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT); +#else + if( config_is_redirect_gw_enabled( context->config ) ){ + *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2); + } #endif const char *verb_string = get_env ("verb", envp); @@ -410,14 +415,35 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, * yet. Let assume it is enabled, we will define default somewhere */ return OPENVPN_PLUGIN_FUNC_SUCCESS; - } -#ifdef ENABLE_LDAPUSERCONF - else if( type == OPENVPN_PLUGIN_CLIENT_CONNECT_V2 ){ + }else if( type == OPENVPN_PLUGIN_CLIENT_CONNECT_V2 ){ /* on client connect, we return conf options through return list */ + const char *username = get_env ("username", envp); client_context_t *cc = per_client_context; + char *ccd_options = NULL; + /* sanity check */ + if (!username){ + LOGERROR("No username supplied to OpenVPN plugin"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + if (!cc || !cc->profile){ + LOGERROR("No profile found for user\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } +#ifdef ENABLE_LDAPUSERCONF ldap_account_t *a = cc->ldap_account; - char *ccd_options = ldap_account_get_options_to_string( cc->ldap_account ); + ccd_options = ldap_account_get_options_to_string( cc->ldap_account ); +#endif + if( cc->profile->redirect_gateway_prefix && strlen( cc->profile->redirect_gateway_prefix ) > 0 ){ + /* do the username start with prefix? */ + if( strncmp( cc->profile->redirect_gateway_prefix, username, strlen( cc->profile->redirect_gateway_prefix ) ) == 0 ){ + char *tmp_ccd = ccd_options; + ccd_options = strdupf("push \"redirect-gateway %s\"\n%s", + cc->profile->redirect_gateway_flags ? cc->profile->redirect_gateway_flags : DFT_REDIRECT_GATEWAY_FLAGS, + tmp_ccd ? tmp_ccd : ""); + if( tmp_ccd ) la_free( tmp_ccd ); + } + } if( ccd_options ){ *return_list = la_malloc( sizeof( struct openvpn_plugin_string_list ) ); if( *return_list != NULL){ @@ -427,7 +453,9 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, } } return OPENVPN_PLUGIN_FUNC_SUCCESS; - }else if( type == OPENVPN_PLUGIN_CLIENT_DISCONNECT ){ + } +#ifdef ENABLE_LDAPUSERCONF + else if( type == OPENVPN_PLUGIN_CLIENT_DISCONNECT ){ /* nothing done for now * potentially, session could be logged */ diff --git a/tests/openvpn-ldap-auth-test.c b/tests/openvpn-ldap-auth-test.c index 2dc032c..759dbb6 100644 --- a/tests/openvpn-ldap-auth-test.c +++ b/tests/openvpn-ldap-auth-test.c @@ -135,6 +135,7 @@ int main(int argc, const char *argv[]) { printf("client-connect failed!\n"); } else { printf("client-connect succeed!\n"); + printf("Config returned by plugin: %s\n", return_list ? return_list->value : "Nothing"); } struct openvpn_plugin_string_list *rl, *next; @@ -145,6 +146,7 @@ int main(int argc, const char *argv[]) { rl = next; next = next->next; free( rl ); + rl = NULL; } /* Client Disconnect */ err = openvpn_plugin_func_v2(handle, OPENVPN_PLUGIN_CLIENT_DISCONNECT, argv, envp, client_contexts[i], NULL); diff --git a/tests/openvpn-ldap-search.c b/tests/openvpn-ldap-search.c index fa70e49..551e562 100644 --- a/tests/openvpn-ldap-search.c +++ b/tests/openvpn-ldap-search.c @@ -115,7 +115,7 @@ main( int argc, char **argv){ return 1; } - rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->ldap_version)); + rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->version)); if( rc != LDAP_OPT_SUCCESS ){ ERROR( "ERROR: ldap_set_option returned (%d) \"%s\"\n", rc, ldap_err2string(rc) ); return 1; From 476ac732952a299128fe241049a7ad89bce3d475 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 3 Aug 2010 19:44:50 +0200 Subject: [PATCH 25/44] Removing trailing whitespaces --- src/action.c | 2 +- src/action.h | 4 ++-- src/cnf.c | 6 +++--- src/defines.h | 3 +-- src/la_ldap.c | 12 ++++++------ src/la_ldap.h | 4 ++-- src/ldap-auth.c | 23 +++++++++++------------ src/list.c | 14 +++++++------- src/types.h | 2 +- src/utils.c | 2 +- tests/openvpn-ldap-auth-test.c | 5 ++--- 11 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/action.c b/src/action.c index c0460a1..888abb8 100644 --- a/src/action.c +++ b/src/action.c @@ -28,7 +28,7 @@ action_new( ) action_t *a = NULL; a = la_malloc( sizeof( action_t ) ); if( a ){ - la_memset( a, 0, sizeof( action_t ) ); + la_memset( a, 0, sizeof( action_t ) ); } return a; } diff --git a/src/action.h b/src/action.h index a04670e..d9401b8 100644 --- a/src/action.h +++ b/src/action.h @@ -30,9 +30,9 @@ enum ldap_auth_action { typedef struct action{ enum ldap_auth_action type; - void *context; + void *context; void *client_context; /*this should not be freed, openvpn plugin call will take care of it */ - void (*context_free_func)( void *data ); + void (*context_free_func)( void *data ); } action_t; extern action_t *action_new( void ); diff --git a/src/cnf.c b/src/cnf.c index 327c696..c709f97 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -64,7 +64,7 @@ config_set_default( config_t *c){ #endif #ifdef OTLS_CACERTFILE STRDUP_IFNOTSET(c->ldap->tls_cacertfile, OTLS_CACERTFILE ); -#endif +#endif #ifdef OTLS_CACERTDIR STRDUP_IFNOTSET(c->ldap->tls_cacertdir, OTLS_CACERTDIR ); #endif @@ -133,7 +133,7 @@ ldap_config_dup( const ldap_config_t *c ){ nc->timeout = c->timeout; - return nc; + return nc; } /** @@ -464,7 +464,7 @@ config_is_pf_enabled( config_t *c ){ } int config_is_pf_enabled_for_profile( profile_config_t *p ){ - return p->enable_pf == TERN_TRUE; + return p->enable_pf == TERN_TRUE; } int diff --git a/src/defines.h b/src/defines.h index e37c953..8699900 100644 --- a/src/defines.h +++ b/src/defines.h @@ -28,7 +28,7 @@ #define OSEARCH_FILTER "(uid=%u)" //#define OSEARCH_FILTER NULL #define OSSL "off" -//#define OTLS_CACERTFILE +//#define OTLS_CACERTFILE //#define OTLS_CACERTDIR //#define OTLS_CERTFILE //#define OTLS_CERTKEY @@ -37,4 +37,3 @@ #define OTIMEOUT 15 #endif - diff --git a/src/la_ldap.c b/src/la_ldap.c index eec611e..5312b3e 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -84,8 +84,8 @@ auth_context_free( auth_context_t *a ){ auth_context_t * auth_context_new( void ){ auth_context_t *a = NULL; - a = la_malloc( sizeof( auth_context_t ) ); - if( a ) la_memset( a, 0, sizeof( auth_context_t ) ); + a = la_malloc( sizeof( auth_context_t ) ); + if( a ) la_memset( a, 0, sizeof( auth_context_t ) ); return a; } @@ -494,7 +494,7 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, client_context_ return 1; } config = ldap_context->config; - + /* initialise timeout values */ la_ldap_set_timeout( config, &timeout); if( userdn && p->group_search_filter && p->member_attribute ){ @@ -537,7 +537,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ ldap = connect_ldap( l ); if( ldap == NULL ){ LOGERROR( "Could not connect to URI %s\n", config->ldap->uri ); - goto la_ldap_handle_authentication_exit; + goto la_ldap_handle_authentication_exit; } /* bind to LDAP server anonymous or authenticated */ rc = ldap_binddn( ldap, config->ldap->binddn, config->ldap->bindpw ); @@ -560,7 +560,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ LOGWARNING( "LDAP user *%s* was not found \n", auth_context->username ); goto la_ldap_handle_authentication_free; } - + if (auth_context && l->config ){ if (auth_context->username && strlen (auth_context->username) > 0 && auth_context->password){ if (DODEBUG (l->verb)) { @@ -606,7 +606,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ if( userdn ) free( userdn ); la_ldap_handle_authentication_exit: - + return res; } diff --git a/src/la_ldap.h b/src/la_ldap.h index 7e5e63e..91422db 100644 --- a/src/la_ldap.h +++ b/src/la_ldap.h @@ -45,7 +45,7 @@ typedef struct ldap_context /** - * Data to be passed to a + * Data to be passed to a * thread for user authentication */ typedef struct auth_context @@ -56,7 +56,7 @@ typedef struct auth_context char *pf_file; } auth_context_t; -/** +/** * Allocate Authentication context resources */ extern auth_context_t * auth_context_new( void ); diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 7f08b3f..5eeec56 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -5,7 +5,7 @@ * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. - * + * * ldap-auth.c * OpenVPN LDAP authentication plugin * @@ -75,7 +75,7 @@ action_push( list_t *list, action_t *action) if( action->type == LDAP_AUTH_ACTION_QUIT ) list_prepend( list, ( void * )action ); else - list_append( list, ( void * )action ); + list_append( list, ( void * )action ); if( list_length( list ) == 1 ){ pthread_cond_signal( &action_cond ); LOGINFO( "Sent signal to authenticating loop\n" ); @@ -147,7 +147,7 @@ get_env (const char *name, const char *envp[]) static void dump_env (const char *envp[]) { - + fprintf (stderr, "//START of dump_env\\\\\n"); if (envp){ int i; @@ -217,7 +217,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char */ context = ldap_context_new( ); if( !context ){ - LOGERROR( "Failed to initialize context\n" ); + LOGERROR( "Failed to initialize context\n" ); goto error; } /* @@ -260,17 +260,17 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char /** * Parse configuration file is -c filename is provided - */ + */ if( configfile ) config_parse_file( configfile, context->config ); /** * Set default config values - */ + */ config_set_default( context->config ); /* * Get verbosity level from environment */ - + /* when ldap userconf is define, we need to hook onto those callbacks */ if( config_is_pf_enabled( context->config )){ *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); @@ -289,7 +289,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char context->verb = atoi (verb_string); if( DODEBUG( context->verb ) ) - config_dump( context->config ); + config_dump( context->config ); /* set up mutex/cond */ @@ -299,7 +299,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char /* start our authentication thread */ pthread_attr_setdetachstate(&action_thread_attr, PTHREAD_CREATE_JOINABLE); rc = pthread_create(&action_thread, &action_thread_attr, action_thread_main_loop, context); - + switch( rc ){ case EAGAIN: LOGERROR( "pthread_create returned EAGAIN: lacking resources\n" ); @@ -367,7 +367,7 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, pthread_t tid; action_t *action = NULL; - + config_t *config = context->config; int rc; int res = OPENVPN_PLUGIN_FUNC_ERROR; @@ -408,7 +408,6 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, action->context_free_func = auth_context_free; action_push( context->action_list, action ); return OPENVPN_PLUGIN_FUNC_DEFERRED; - } else if (type == OPENVPN_PLUGIN_ENABLE_PF){ /* unfortunately, at this stage we dont know anything about the client @@ -440,7 +439,7 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, char *tmp_ccd = ccd_options; ccd_options = strdupf("push \"redirect-gateway %s\"\n%s", cc->profile->redirect_gateway_flags ? cc->profile->redirect_gateway_flags : DFT_REDIRECT_GATEWAY_FLAGS, - tmp_ccd ? tmp_ccd : ""); + tmp_ccd ? tmp_ccd : ""); if( tmp_ccd ) la_free( tmp_ccd ); } } diff --git a/src/list.c b/src/list.c index 91fbda5..b5b7e8c 100644 --- a/src/list.c +++ b/src/list.c @@ -83,8 +83,8 @@ list_free_item( list_t *l, list_item_t *i, void (*item_free_func)( void *data ) /** * list_remove_item * Remove an item from the list. The item cell is freed - * BUT the item data is not freed - * The caller will need to free it, or memory will be lost + * BUT the item data is not freed + * The caller will need to free it, or memory will be lost */ void * list_remove_item( list_t *l, list_item_t *i ){ @@ -92,11 +92,11 @@ list_remove_item( list_t *l, list_item_t *i ){ if( !i ) return NULL; data = i->data; list_free_item( l, i, NULL ); - return data; + return data; } /** * list_remove_item_at - * + * */ void * @@ -104,7 +104,7 @@ list_remove_item_at( list_t *l, uint32_t index ){ list_item_t *i; i = list_item_at(l, index ); if( !i ) return NULL; - return list_remove_item( l, i ); + return list_remove_item( l, i ); } /** @@ -143,7 +143,7 @@ list_append( list_t *l, void *data ){ } } l->counter++; - return i; + return i; } /** @@ -167,7 +167,7 @@ list_prepend( list_t *l, void *data ){ } } l->counter++; - return i; + return i; } diff --git a/src/types.h b/src/types.h index 3e48cdb..3cfd37c 100644 --- a/src/types.h +++ b/src/types.h @@ -22,7 +22,7 @@ #ifndef _TYPES_H_ #define _TYPES_H_ - + typedef enum ternary { TERN_FALSE = -1, TERN_UNDEF = 0, diff --git a/src/utils.c b/src/utils.c index 43a0a4a..298c94a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -158,7 +158,7 @@ char *get_passwd( const char *prompt ){ if( prompt ) fprintf( stdout, "%s", prompt ); while( ( c = getc( stdin )) != '\n' ){ if( c == BACKSPACE ){ - /* never happens as getc only read once \n is entered */ + /* never happens as getc only read once \n is entered */ if( size > 0 ) size--; }else{ size ++; diff --git a/tests/openvpn-ldap-auth-test.c b/tests/openvpn-ldap-auth-test.c index 759dbb6..92109a5 100644 --- a/tests/openvpn-ldap-auth-test.c +++ b/tests/openvpn-ldap-auth-test.c @@ -18,7 +18,7 @@ * 3. Neither the name of Landon Fuller nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -60,7 +60,7 @@ int main(int argc, const char *argv[]) { pid_t pid = getpid(); char command[100]; - + /* Grab username and password */ printf("Username: "); if(!scanf("%s", username)){ @@ -168,6 +168,5 @@ int main(int argc, const char *argv[]) { free((char *) envp[0]); free((char *) envp[1]); - exit (0); } From 723c3bd029619bbc5b9769ec3199f1242d1043d2 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 3 Aug 2010 20:28:50 +0200 Subject: [PATCH 26/44] Adding some docs on 0.0.X to 0.1.X upgrade Details a bit more what the config can handle. --- UPGRADE-from-0.0.X.txt | 142 +++++++++++++++++++++++++++++++++++++++++ tests/config.conf | 40 ++++++++++-- 2 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 UPGRADE-from-0.0.X.txt diff --git a/UPGRADE-from-0.0.X.txt b/UPGRADE-from-0.0.X.txt new file mode 100644 index 0000000..10974ec --- /dev/null +++ b/UPGRADE-from-0.0.X.txt @@ -0,0 +1,142 @@ +Important notes: + += User config stored in LDAP +Users configuration can now be stored in LDAP. +the feature is enable by default but can be disabled by running: + +./configure --disable-ldapuserconfig + +If you use this feature, you ldap server must include ovpn.schema: +in slapd.conf add: +include /etc/ldap/schema/ovpn.schema + +The schema can be found in tests/ovpn.schema. + +An OpenVPNAccount can have any attributes from +OpenVPNProfile plus: +OvpnProfile: the DN of a profile where to get default settings +OvpnCCDIfconfigPush: to define a static IP for this user + +This allows to provide the same settings for many user belonging +to the same group. + +An example LDAP ldif would look like: +dn: uid=user1,ou=thirdparty,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: OpenVPNAccount +uid: user1 +cn: user1 +userPassword:: dXNlcjE= +sn: user1sn +OvpnProfile: cn=default,ou=profiles,ou=openvpn,dc=example,dc=com +OvpnCCDPushOption: route 192.168.32.0 255.255.255.0 +OvpnPFRulesClientDefaultAccept: true +OvpnPFRulesSubnetDefaultAccept: true +OvpnPFRulesSubnet:: KzE5Mi4xNjguMzMuMTkKLTE5Mi4xNjguMzMuMC8yNAorMTkyLjE2OC4zMi + 4wLzI4Ci0xOTIuMTY4LjMyLjAvMjQ= +OvpnEndDate: 20100810100000Z + +dn: cn=default,ou=profiles,ou=openvpn,dc=example,dc=com +objectClass: OpenVPNProfile +objectClass: person +cn: default +sn: dummy +OvpnCCDPushReset: TRUE +OvpnCCDPushOption: route 192.168.33.0 255.255.255.0 +OvpnCCDPushOption: route 192.168.34.0 255.255.255.0 +OvpnStartDate: 20100728000000Z +OvpnEndDate: 20100802100000Z +OvpnPFRulesSubnet:: KzE5Mi4xNjguMzIuMC8yNAotMTkyLjE2OC4zMy4wLzI4CisxOTIuMTY4Lj + MzLjAvMjQK +OvpnPFRulesSubnetDefaultAccept: true +OvpnPFRulesClientDefaultAccept: false + + +default profile allow users to connect from: +28/07/2010 00:00:00 GMT until 02/08/2010 00:00:00 GMT +global push info will be reset +default packet filter rules to clients will drop packets, while it will accept to subnets +The rules for subnets are base64 encoded and is equivalent to: ++192.168.32.0/24 +-192.168.33.0/28 ++192.168.33.0/24 +Also, the routes 192.168.33.0/24 and 192.168.34.0/24 will be pushed. + +user1 inherits those settings but override some of them: +It wont be able to connect after 10/08/2010 10:00:00 GTM instead of 02/08/2010 00:00:00 GMT +It will also get 192.168.32.0/24 route pushed to it +Default PF rules are overriden and are instead changed to accept packets to clients +Its PF subnets rules are ++192.168.33.19 +-192.168.33.0/24 ++192.168.32.0/28 +-192.168.32.0/24 + += Multiple profiles + +Since 0.0.X, the config syntax has changed a little. +Most importantly, release greater than 0.0.X support multiple profiles +which allow defining different type of openvpn group. + +From now on, all information which is not related to LDAP connection details +must be enclosed within + + +tags. + +== LDAP server connection details parameters +uri=ldap://192.168.9.135 +binddn=cn=admin,dc=example,dc=com +bindpw=secret +version=3 +#ssl=start_tls +ssl=off +timeout + +Some more parameters exist which are ignore at the moment and might be subject +to change, so it is not recommended you use them: +tls_cacertfile +tls_cacertdir +tls_certfile +tls_certkey +tls_ciphersuite +tls_reqcert + +== Profile parameters +Profiles allow to define how to find users. Each profile can have different rules +applied to it. + +The following parameters can be defined whithin tag. +As many profile as you like can be defined. +The first one that can match a user will be used. + +Here are the parameters you can use: +basedn +search_filter +search_scope +groupdn +group_search_filter +member_attribute +redirect_gateway_prefix +redirect_gateway_flags +enable_pf +default_pf_rules + +If the plugin was compiled with ldapuserconfig support, you can also use: +default_profiledn + +An example config file can be found in tests/config.conf + + += group_search_filter syntax change + +In 0.0.X releases, group_search_filter syntax was not needing parentheses +and was looking like: +group_search_filter=|(cn=vpn)(cn=sysadmins) + +Since 0.1.X the syntax has changed to be consistant with search_filter and +MUST now be within parentheses. +As such, the previous filter need to be changed to: +group_search_filter=(|(cn=vpn)(cn=sysadmins)) + + diff --git a/tests/config.conf b/tests/config.conf index 2144746..0792487 100644 --- a/tests/config.conf +++ b/tests/config.conf @@ -1,11 +1,41 @@ uri=ldap://192.168.9.135 -search_filter=(uid=%u) -basedn=ou=users,dc=example,dc=com binddn=cn=admin,dc=example,dc=com bindpw=secret version=3 #ssl=start_tls ssl=off -groupdn=ou=roles,dc=example,dc=com -group_search_filter=(|(cn=vpn)(cn=sysadmins)) -member_attribute=member + +#In this profile, users will be search directly under +#ou=users,dc=example,dc=com DN. +#Users need to be members of sysadmins or vpn group +#to be able to connect + search_filter=(uid=%u) + basedn=ou=users,dc=example,dc=com + groupdn=ou=roles,dc=example,dc=com + group_search_filter=(|(cn=vpn)(cn=sysadmins)) + member_attribute=member +#enable user to use the VPN to pass all traffic through it if +#username is prepended with "fulltunnel-" + redirect_gateway_prefix=fulltunnel- + redirect_gateway_flags=def1 bypass-dhcp + + +# in this profile, users will be search under dn: +# ou=thirdparty,dc=example,dc=com DN at any depth +# (SCOPE_TREE) +# User need not to be members of any groups but need to have an +# object class OpenVPNAccount +# If no LDAP profile is found for the account, it will default to +# cn=default,ou=profiles,ou=openvpn,dc=example,dc=com +# +# Packet filter will be enabled +# If no packet filtering rules exists in the LDAP profile +# of the user, it will default to DROP all BUT packets for subnet +# 192.168.100.0/28 + basedn=ou=thirdparty,dc=example,dc=com + search_scope=LDAP_SCOPE_SUBTREE + search_filter=(&(uid=%u)(objectClass=OpenVPNAccount)) + enable_pf=true + default_pf_rules=[CLIENTS DROP]\n[SUBNETS DROP]\n+192.168.100.0/28\n[END] + default_profiledn=cn=default,ou=profiles,ou=openvpn,dc=example,dc=com + From 0972701e4a942a4eec39c3611a3ceaa1fbcfca6c Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 11 Aug 2010 06:24:15 +0200 Subject: [PATCH 27/44] search_scope default to SCOPE_ONELEVEL --- src/cnf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cnf.c b/src/cnf.c index c709f97..c36c3ff 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -171,6 +171,7 @@ profile_config_new ( void ){ profile_config_t *c = la_malloc( sizeof( profile_config_t ) ); if( !c ) return NULL; la_memset (c, 0, sizeof( profile_config_t ) ); + c->search_scope = LA_SCOPE_ONELEVEL; return c; } From d5a0b04d1c23dc6bd99fcff00a0cd5f2fceae5f1 Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 11 Aug 2010 06:55:38 +0200 Subject: [PATCH 28/44] Apply default_profiledn to any LDAP entries When a LDAP entry is neither an OpenVPNAccount or OpenVPNProfile and default_profiledn is defined, apply its settings --- src/ldap_profile.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ldap_profile.c b/src/ldap_profile.c index 947b249..b012d88 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -280,6 +280,7 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, c LDAPMessage *e, *result; config_t *config = NULL; uint8_t is_account = 0; + uint8_t is_profile = 0; int rc; /* if a NULL value was given for account, no action is taken */ @@ -324,7 +325,11 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, c for( i = 0; vals[i]; i++ ){ if( strcasecmp( vals[i]->bv_val, "OpenVPNAccount" ) == 0 ){ is_account = 1; - break; + continue; + } + if( strcasecmp( vals[i]->bv_val, "OpenVPNProfile" ) == 0 ){ + is_profile = 1; + continue; } } ldap_value_free_len( vals ); @@ -351,6 +356,16 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, c ldap_account_load_from_dn( ldap_context, ldap, cc->profile->default_profiledn, cc ); } } + }else if( !is_account && !is_profile && cc->profile->default_profiledn){ + /* if item is neither an openvpnaccount or openvpnprofile + * but a default profile is defined, load it + */ + /* reset ld_errno */ + int ec = LDAP_SUCCESS; + ldap_set_option( ldap, LDAP_OPT_ERROR_NUMBER, &ec ); + if( cc->profile->default_profiledn ){ + ldap_account_load_from_dn( ldap_context, ldap, cc->profile->default_profiledn, cc ); + } } ldap_account_load_from_entry( ldap, e, account ); ldap_msgfree( result ); From b418affb159c9f6e1b17c2394942bb0388606bf3 Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 11 Aug 2010 07:40:46 +0200 Subject: [PATCH 29/44] Fix free corruption uint8_t was use to handle size string returned by ldap_account_get_options_to_string This can easily be > 256 and was crashing app --- src/ldap_profile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ldap_profile.c b/src/ldap_profile.c index b012d88..af5f2ae 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -380,7 +380,8 @@ ldap_account_load_from_dn( ldap_context_t *ldap_context, LDAP *ldap, char *dn, c char * ldap_account_get_options_to_string( ldap_account_t *account ){ - uint8_t tot_size = 0; + /* FIXME check if total written data is not > 2^32 (max tot_size) */ + uint32_t tot_size = 0; list_item_t *elem = NULL; char *res = NULL; if (account->profile->push_reset == TERN_TRUE) From a6c1e36c8282c385b68bb09e0382b6f5b11113fa Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 13 Aug 2010 18:50:13 +0200 Subject: [PATCH 30/44] Compile against newer gcc Remove unused variables... --- src/ldap-auth.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 5eeec56..62a3910 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -144,6 +144,7 @@ get_env (const char *name, const char *envp[]) * Given an environmental variable name, dumps * the envp array values. */ +/* static void dump_env (const char *envp[]) { @@ -156,7 +157,7 @@ dump_env (const char *envp[]) } fprintf (stderr, "//END of dump_env\\\\\n"); } - +*/ /* * Return the length of a string array @@ -364,12 +365,9 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, { ldap_context_t *context = (ldap_context_t *) handle; auth_context_t *auth_context = NULL; - pthread_t tid; action_t *action = NULL; - config_t *config = context->config; - int rc; int res = OPENVPN_PLUGIN_FUNC_ERROR; if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY){ @@ -405,7 +403,7 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, action->type = LDAP_AUTH_ACTION_AUTH; action->context = auth_context; action->client_context = per_client_context; - action->context_free_func = auth_context_free; + action->context_free_func = (void *)auth_context_free; action_push( context->action_list, action ); return OPENVPN_PLUGIN_FUNC_DEFERRED; } @@ -430,7 +428,6 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, return OPENVPN_PLUGIN_FUNC_ERROR; } #ifdef ENABLE_LDAPUSERCONF - ldap_account_t *a = cc->ldap_account; ccd_options = ldap_account_get_options_to_string( cc->ldap_account ); #endif if( cc->profile->redirect_gateway_prefix && strlen( cc->profile->redirect_gateway_prefix ) > 0 ){ From fc843b4b5bd6c8b92b062cc89f999a4ec45baaf5 Mon Sep 17 00:00:00 2001 From: chantra Date: Mon, 16 Aug 2010 10:34:27 +0200 Subject: [PATCH 31/44] Removing config.h.in from git repository --- config.h.in | 64 ----------------------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 config.h.in diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 0e4bea9..0000000 --- a/config.h.in +++ /dev/null @@ -1,64 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Enable user ldap settings */ -#undef ENABLE_LDAPUSERCONF - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `ldap' library (-lldap). */ -#undef HAVE_LIBLDAP - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -#undef HAVE_LIBPTHREAD - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION From db89d467c2e94eba96a5bd3e76eea13f54097575 Mon Sep 17 00:00:00 2001 From: chantra Date: Sun, 27 Feb 2011 21:20:07 +0100 Subject: [PATCH 32/44] str_replace_all: Fix infinite loop When the replacement string is part of the needle, the while loop never exit. ex: str_replace_all("foobar", "foo", "foo2"); The plugin was not affected as we only replace_all "\\n" by "\n" --- src/utils.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 298c94a..fe26228 100644 --- a/src/utils.c +++ b/src/utils.c @@ -119,12 +119,14 @@ str_replace_all ( const char *string, const char *substr, const char *replacemen char *tok = NULL; char *newstr = NULL; char *oldstr = NULL; + char *head = NULL; /* if either substr or replacement is NULL, duplicate string a let caller * handle it */ if ( substr == NULL || replacement == NULL ) return strdup (string); newstr = strdup (string); - while ( (tok = strstr ( newstr, substr ))){ + head = newstr; + while ( (tok = strstr ( head, substr ))){ oldstr = newstr; newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 ); /*failed to alloc mem, free old string and return NULL */ @@ -136,6 +138,8 @@ str_replace_all ( const char *string, const char *substr, const char *replacemen memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) ); memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) ); memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 ); + /* move back head right after the last replacement */ + head = newstr + (tok - oldstr) + strlen( replacement ); free (oldstr); } return newstr; From a1b88343718db7b18f698ff546e5b71ffeb2970e Mon Sep 17 00:00:00 2001 From: chantra Date: Sun, 6 Mar 2011 15:39:30 +0100 Subject: [PATCH 33/44] Adding config.h.in to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 809df86..b0b285f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,6 @@ aclocal.m4 Makefile configure config.h +config.h.in testplugin tools/ From d29d0c1989129ac391dc823389f9db19e40908a4 Mon Sep 17 00:00:00 2001 From: chantra Date: Sun, 6 Mar 2011 15:58:07 +0100 Subject: [PATCH 34/44] Adding syslog support Cleaning up debugging and allowing to use syslog while in daemon mode --- configure.in | 3 ++ src/cnf.c | 42 ++++++++-------- src/debug.c | 59 +++++++++++++++++++++-- src/debug.h | 36 ++++++++++---- src/la_ldap.c | 94 ++++++++++++++++++------------------ src/ldap-auth.c | 116 +++++++++++++++++++-------------------------- src/ldap_profile.c | 47 ++++++++---------- src/utils.c | 2 +- 8 files changed, 226 insertions(+), 173 deletions(-) diff --git a/configure.in b/configure.in index d1b5359..1454e57 100644 --- a/configure.in +++ b/configure.in @@ -40,6 +40,9 @@ AC_CHECK_HEADER([pthread.h], [AC_CHECK_LIB(pthread, [pthread_create])], [AC_MSG_ERROR("pthread headers not found")]) +AC_CHECK_HEADERS([syslog.h]) + + AC_PROG_INSTALL AC_OUTPUT( Makefile src/Makefile tests/Makefile ) diff --git a/src/cnf.c b/src/cnf.c index c36c3ff..71b4920 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -33,10 +33,10 @@ #include #include /* isspace */ -#define STRPRINT_IFSET(a,prefix) if(a) fprintf(stderr, "%s:\t%s\n", prefix, a); +#define LOGDEBUG_IFSET(a,prefix) if(a) LOGDEBUG( "%s: %s", prefix, a); #define STRDUP_IFNOTSET(a,b) if(!a && b) a=strdup(b); #define CHECK_IF_IN_PROFILE(a,b) if(!b){ \ -LOGWARNING("%s is not defined within . It will be ignored\n", a);\ +LOGWARNING("%s is not defined within . It will be ignored", a);\ free( line );\ continue;\ } @@ -294,7 +294,7 @@ config_parse_file( const char *filename, config_t *c ){ profile_config_t *p = NULL; fd = open( filename, O_RDONLY ); if( fd == -1 ){ - LOGERROR( "Could not open file %s: (%d) %s\n", filename, errno, strerror( errno ) ); + LOGERROR( "Could not open file %s: (%d) %s", filename, errno, strerror( errno ) ); return 1; } val = NULL; @@ -309,7 +309,7 @@ config_parse_file( const char *filename, config_t *c ){ p = profile_config_new( ); free(line); if( p == NULL ){ - LOGERROR( "Could not allocate memory for new profile\n" ); + LOGERROR( "Could not allocate memory for new profile" ); rc = 1; break; } @@ -397,7 +397,7 @@ config_parse_file( const char *filename, config_t *c ){ STRDUP_IFNOTSET(p->default_profiledn, val ); #endif }else{ - LOGWARNING("Unrecognized option *%s=%s*\n", arg, val); + LOGWARNING("Unrecognized option *%s=%s*", arg, val); } } @@ -422,28 +422,28 @@ config_search_scope_to_string( ldap_search_scope_t scope){ } void config_dump( config_t *c){ - fprintf( stderr, "Config Dump:\n*LDAP:*\n"); - STRPRINT_IFSET(c->ldap->uri,"\tURI"); - STRPRINT_IFSET(c->ldap->binddn,"\tBindDN"); - fprintf( stderr, "\tSSL:\t%s\n", c->ldap->ssl ); - fprintf( stderr, "\tLDAP VERSION:\t%d\n", c->ldap->version ); - fprintf( stderr, "\tLDAP TIMEOUT:\t%d\n", c->ldap->timeout ); + LOGDEBUG( "Config Dump: *LDAP:*"); + LOGDEBUG_IFSET(c->ldap->uri," URI"); + LOGDEBUG_IFSET(c->ldap->binddn," BindDN"); + LOGDEBUG( " SSL: %s", c->ldap->ssl ); + LOGDEBUG( " LDAP VERSION: %d", c->ldap->version ); + LOGDEBUG( " LDAP TIMEOUT: %d", c->ldap->timeout ); /* Dump each profiles */ list_item_t *item; profile_config_t *p; for( item = list_first( c->profiles ); item; item = item->next){ p = item->data; - fprintf( stderr, "*Custom Profile:*\n" ); - STRPRINT_IFSET(p->basedn, "\tBaseDN"); - fprintf( stderr, "\tSearch Scope:\t%s\n", config_search_scope_to_string( p->search_scope ) ); - fprintf( stderr, "\tSearch filter:\t%s\n", p->search_filter ); - STRPRINT_IFSET(p->groupdn,"\tGroupDN"); - STRPRINT_IFSET(p->group_search_filter, "\tGroup Search Filter"); - STRPRINT_IFSET(p->member_attribute,"\tMember Attribute"); - fprintf( stderr, "\tEnable PF:\t%s\n", ternary_to_string(p->enable_pf)); - fprintf( stderr, "\tDefault PF rules:\t%s\n", p->default_pf_rules ? p->default_pf_rules : "Undefined" ); + LOGDEBUG( "*Custom Profile:*" ); + LOGDEBUG_IFSET(p->basedn, " BaseDN"); + LOGDEBUG( " Search Scope: %s", config_search_scope_to_string( p->search_scope ) ); + LOGDEBUG( " Search filter: %s", p->search_filter ); + LOGDEBUG_IFSET(p->groupdn," GroupDN"); + LOGDEBUG_IFSET(p->group_search_filter, " Group Search Filter"); + LOGDEBUG_IFSET(p->member_attribute," Member Attribute"); + LOGDEBUG( " Enable PF: %s", ternary_to_string(p->enable_pf)); + LOGDEBUG( " Default PF rules: %s", p->default_pf_rules ? p->default_pf_rules : "Undefined" ); #ifdef ENABLE_LDAPUSERCONF - fprintf( stderr, "\tDefault Profile DN:\t%s\n", p->default_profiledn ? p->default_profiledn : "Undefined" ); + LOGDEBUG( " Default Profile DN: %s", p->default_profiledn ? p->default_profiledn : "Undefined" ); #endif } diff --git a/src/debug.c b/src/debug.c index e03b521..fc7d351 100644 --- a/src/debug.c +++ b/src/debug.c @@ -20,10 +20,46 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ +#include "config.h" #include #include +#include +#include #include "debug.h" +#if HAVE_SYSLOG_H +#include +#else +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ +#endif + +typedef struct log_value{ + char *name; + int syslog_val; +} log_value_t; + + +log_value_t log_values[] = { + {"EMERG", LOG_EMERG}, + {"ALERT", LOG_ALERT}, + {"CRIT", LOG_CRIT}, + {"ERROR", LOG_ERR}, + {"WARNING", LOG_WARNING}, + {"NOTICE", LOG_NOTICE}, + {"INFO", LOG_INFO}, + {"DEBUG", LOG_DEBUG}, + {NULL, -1} +}; + + +char use_syslog = 0; void _debug( int level, const char *file, int line, const char *func, const char *fmt, ... ){ va_list argp; @@ -64,12 +100,29 @@ void _error( const char *file, int line, const char *func, const char *fmt, ... fprintf( stderr, "\n" ); } -void _log( const char *level, const char *fmt, ... ){ +void _log( int level, const char *fmt, ... ){ va_list argp; - fprintf( stderr, "LDAP-AUTH: [%s] ", level); + char s[BUFSIZ]; + size_t cur_len = 0; + snprintf(s, BUFSIZ, "LDAP-AUTH: [%s] ", log_values[level].name); va_start( argp, fmt ); - vfprintf( stderr, fmt, argp ); + cur_len = strlen(s); + vsnprintf( s+cur_len, BUFSIZ-cur_len, fmt, argp ); va_end( argp ); + +#if HAVE_SYSLOG_H + if (use_syslog) + syslog(log_values[level].syslog_val, "%s", s); + else +#endif + { + time_t t = time(NULL); + struct tm tmp; + localtime_r(&t, &tmp); + char strtime[26]; + strftime(strtime, 26, "%a %b %e %T %Y", &tmp); + fprintf( stderr, "%s %s\n", strtime, s); + } } diff --git a/src/debug.h b/src/debug.h index f83d649..455d585 100644 --- a/src/debug.h +++ b/src/debug.h @@ -24,10 +24,21 @@ #define _DEBUG_H_ +extern char use_syslog; + +#define D_EMERG 0 /* system is unusable */ +#define D_ALERT 1 /* action must be taken immediately */ +#define D_CRIT 2 /* critical conditions */ +#define D_ERR 3 /* error conditions */ +#define D_WARNING 4 /* warning conditions */ +#define D_NOTICE 5 /* normal but significant condition */ +#define D_INFO 6 /* informational */ +#define D_DEBUG 7 /* debug-level messages */ + +#define DONOTICE(verb) ((verb) >= 4) +#define DOINFO(verb) ((verb) >= 5) +#define DODEBUG(verb) ((verb) >= 6) -#define DEBUG_SQL 0 -#define DEBUG_USER 0 -#define DEBUG_MAIN 1 void _printdebug( int debug, const char *fmt, ... ); @@ -40,15 +51,24 @@ void _error( const char *file, int line, const char *func, const char *fmt, ... void _debug( int level, const char *file, int line, const char *func, const char *fmt, ... ); #define DEBUG( level, fmt, args... ) _debug( level, __FILE__, __LINE__, __FUNCTION__, fmt, ##args ) -void _log( const char *level, const char *fmt, ... ); +void _log( int level, const char *fmt, ... ); + + +#define LOGEMERG( fmt, args... ) _log( D_EMERG, fmt, ##args ) + +#define LOGALERT( fmt, args... ) _log( D_ALERT, fmt, ##args ) + +#define LOGCRIT( fmt, args... ) _log( D_CRIT, fmt, ##args ) + +#define LOGERROR( fmt, args... ) _log( D_ERR, fmt, ##args ) -#define LOGERROR( fmt, args... ) _log( "ERROR", fmt, ##args ) +#define LOGWARNING( fmt, args... ) _log( D_WARNING, fmt, ##args ) -#define LOGWARNING( fmt, args... ) _log( "WARNING", fmt, ##args ) +#define LOGNOTICE( fmt, args... ) _log( D_NOTICE, fmt, ##args ) -#define LOGINFO( fmt, args... ) _log( "INFO", fmt, ##args ) +#define LOGINFO( fmt, args... ) _log( D_INFO, fmt, ##args ) -#define LOGDEBUG( fmt, args... ) _log( "DEBUG", fmt, ##args ) +#define LOGDEBUG( fmt, args... ) _log( D_DEBUG, fmt, ##args ) #endif /* _DEBUG_H_ */ diff --git a/src/la_ldap.c b/src/la_ldap.c index 5312b3e..525e8e6 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -19,8 +19,6 @@ * */ -#define DODEBUG(verb) ((verb) >= 4) - #include #include #include @@ -170,7 +168,7 @@ la_ldap_generate_pf_rules( ldap_profile_t *lp ){ lp->pf_client_rules ? lp->pf_client_rules : "", la_ldap_default_rule_to_string( lp->pf_subnet_default_accept ), lp->pf_subnet_rules ? lp->pf_subnet_rules : "" ); - LOGDEBUG("pf_rules = %s\n", res); + LOGDEBUG("pf_rules = %s", res); return res; } #endif @@ -180,27 +178,27 @@ la_ldap_write_to_pf_file( char *pf_file, char *value ) { int fd, rc = 0; if( pf_file == NULL ){ - LOGERROR( "pf_file is null\n"); + LOGERROR( "pf_file is null"); return 1; } fd = open( pf_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU ); if( fd == -1 ){ - LOGERROR( "Could not open file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + LOGERROR( "Could not open file %s: (%d) %s", pf_file, errno, strerror( errno ) ); return 1; } rc = write( fd, value, strlen(value) ); if( rc == -1 ){ - LOGERROR( "Could not write value %s to file %s: (%d) %s\n", value, pf_file, errno, strerror( errno ) ); + LOGERROR( "Could not write value %s to file %s: (%d) %s", value, pf_file, errno, strerror( errno ) ); rc = 1; }else if( rc !=strlen(value) ){ - LOGERROR( "Could not write all of %s to file %s\n", value, pf_file ); + LOGERROR( "Could not write all of %s to file %s", value, pf_file ); rc = 1; }else{ rc = 0; } if( close( fd ) != 0 ){ - LOGERROR( "Could not close file %s: (%d) %s\n", pf_file, errno, strerror( errno ) ); + LOGERROR( "Could not close file %s: (%d) %s", pf_file, errno, strerror( errno ) ); } return rc; } @@ -217,11 +215,11 @@ la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ int rc = 0; /* check if pf is enabled */ - LOGDEBUG("PF enable for this profile: %s\n", + LOGDEBUG("PF enable for this profile: %s", p->enable_pf == TERN_TRUE ? "TRUE" : "FALSE" ); /* write to pf_file */ if( pf_file == NULL && config_is_pf_enabled(c) ){ - LOGERROR("PF is enabled but environment pf_file variable is NULL.\n"); + LOGERROR("PF is enabled but environment pf_file variable is NULL."); return 1; }else if( pf_file ){ if( p->enable_pf == TERN_TRUE ){ @@ -235,17 +233,17 @@ la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ char *pf_rules = NULL; pf_rules = la_ldap_generate_pf_rules( lp ); if( pf_rules ){ - LOGDEBUG("Using PF rules from ldap backend\n"); + LOGDEBUG("Using PF rules from ldap backend"); rc = la_ldap_write_to_pf_file( pf_file, pf_rules ); la_free( pf_rules ); }else{ - LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules\n"); + LOGERROR("ldap_profile_handle_pf_file: could not generate pf_rules"); return 1; } }else #endif if( p->default_pf_rules ){ - LOGDEBUG("Using default PF rules from config\n"); + LOGDEBUG("Using default PF rules from config"); char *rules = str_replace_all( p->default_pf_rules, "\\n", "\n" ); int res = la_ldap_write_to_pf_file( pf_file, rules ); if( rules ) la_free( rules ); @@ -257,12 +255,12 @@ la_ldap_handle_pf_file(config_t *c, client_context_t *cc, char *pf_file){ * is not defined, we default to openvpn standard behaviour: * allow everything */ - LOGDEBUG("No PF rules found, default to accept all\n"); + LOGDEBUG("No PF rules found, default to accept all"); return la_ldap_write_to_pf_file( pf_file, PF_ALLOW_ALL); } }else{ /* profile has PF disabled */ - LOGDEBUG("PF rules disabled for this profile, default to accept all\n"); + LOGDEBUG("PF rules disabled for this profile, default to accept all"); return la_ldap_write_to_pf_file( pf_file, PF_ALLOW_ALL ); } } @@ -308,29 +306,30 @@ ldap_find_user_for_profile( LDAP *ldap, ldap_context_t *ldap_context, const char if( real_username ) la_free( real_username ); if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); + LOGDEBUG( "Searching user using filter %s with basedn: %s and scope %s", search_filter, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); ldap_scope = la_ldap_config_search_scope_to_ldap( p->search_scope ); rc = ldap_search_ext_s( ldap, p->basedn, ldap_scope, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ int nbrow = ldap_count_entries( ldap, result ); if( nbrow > 1 ){ - LOGERROR( "ldap_search_ext_s returned %d results, only 1 is supported\n", ldap_count_entries( ldap, result ) ); + LOGERROR( "ldap_search_ext_s returned %d results, only 1 is supported", ldap_count_entries( ldap, result ) ); }else if( nbrow == 0 ){ - LOGWARNING( "ldap_search_ext_s: unknown user %s\n", username ); + if( DODEBUG( ldap_context->verb ) ) + LOGDEBUG( "ldap_search_ext_s: unknown user %s in basedn %s and scope %s", username, p->basedn, la_ldap_ldap_scope_to_string( p->search_scope ) ); }else if( nbrow == 1 ){ /* get the first entry (and only) */ e = ldap_first_entry( ldap, result ); if( e != NULL ){ dn = ldap_get_dn( ldap, e ); if( DODEBUG( ldap_context->verb ) ) - LOGINFO("found dn: %s\n", dn ); + LOGDEBUG("found dn: %s", dn ); }else{ - LOGERROR( "searched returned and entry but we could not retrieve it!!!\n" ); + LOGERROR( "searched returned and entry but we could not retrieve it!!!" ); } } }else{ - LOGERROR( "ldap_search_ext_s did not succeed (%d) %s\n", rc, ldap_err2string( rc )); + LOGERROR( "ldap_search_ext_s did not succeed (%d) %s", rc, ldap_err2string( rc )); } /* free the returned result */ if( result != NULL ) ldap_msgfree( result ); @@ -366,7 +365,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, /* arguments sanity check */ if( !ldap_context || !username || !ldap){ - LOGERROR("ldap_find_user missing required parameter\n"); + LOGERROR("ldap_find_user missing required parameter"); return NULL; } @@ -384,7 +383,7 @@ ldap_find_user( LDAP *ldap, ldap_context_t *ldap_context, const char *username, } } }else{ - LOGERROR("No profiles defined. Please make sure you have a section in your config.\n"); + LOGERROR("No profiles defined. Please make sure you have a section in your config."); } return userdn; @@ -406,20 +405,20 @@ connect_ldap( ldap_context_t *l ){ /* init connection to ldap */ rc = ldap_initialize(&ldap, config->ldap->uri); if( rc!= LDAP_SUCCESS ){ - LOGERROR( "ldap_initialize returned (%d) \"%s\" : %s\n", rc, ldap_err2string(rc), strerror(errno) ); + LOGERROR( "ldap_initialize returned (%d) \"%s\" : %s", rc, ldap_err2string(rc), strerror(errno) ); goto connect_ldap_error; } /* Version */ rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &(config->ldap->version)); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"\n", config->ldap->version, rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option version %d returned (%d) \"%s\"", config->ldap->version, rc, ldap_err2string(rc) ); goto connect_ldap_error; } /* Timeout */ la_ldap_set_timeout( config, &timeout); rc = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout ); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option timeout %ds returned (%d) \"%s\"\n", config->ldap->timeout, rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option timeout %ds returned (%d) \"%s\"", config->ldap->timeout, rc, ldap_err2string(rc) ); goto connect_ldap_error; } /* SSL/TLS */ @@ -428,15 +427,15 @@ connect_ldap( ldap_context_t *l ){ ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"\n", rc, ldap_err2string(rc) ); + LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"", rc, ldap_err2string(rc) ); goto connect_ldap_error; } rc = ldap_start_tls_s( ldap, NULL, NULL ); if( rc != LDAP_SUCCESS && rc != LDAP_LOCAL_ERROR ){ - LOGERROR( "ldap_start_tls_s returned (%d) \"%s\"\n", rc, ldap_err2string(rc) ); + LOGERROR( "ldap_start_tls_s returned (%d) \"%s\"", rc, ldap_err2string(rc) ); goto connect_ldap_error; }else if( rc == LDAP_LOCAL_ERROR ){ - LOGWARNING( "ldap_start_tls_s TLS context already exist\n" ); + LOGWARNING( "ldap_start_tls_s TLS context already exist" ); } } return ldap; @@ -444,7 +443,7 @@ connect_ldap( ldap_context_t *l ){ connect_ldap_error: rc = ldap_unbind_ext_s( ldap, NULL, NULL ); if( rc != LDAP_SUCCESS ){ - LOGERROR( "ldap_unbind_ext_s returned: %d/0x%2X %s\n", rc, rc, ldap_err2string( rc ) ); + LOGERROR( "ldap_unbind_ext_s returned: %d/0x%2X %s", rc, rc, ldap_err2string( rc ) ); } return NULL; } @@ -490,7 +489,7 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, client_context_ /* arguments sanity check */ if( !ldap_context || !userdn || !ldap){ - LOGERROR("ldap_group_membership missing required parameter\n"); + LOGERROR("ldap_group_membership missing required parameter"); return 1; } config = ldap_context->config; @@ -503,17 +502,17 @@ ldap_group_membership( LDAP *ldap, ldap_context_t *ldap_context, client_context_ ldap_scope = la_ldap_config_search_scope_to_ldap( p->search_scope ); if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "Searching user using filter %s with basedn: %s and scope %s\n", search_filter, p->groupdn, la_ldap_ldap_scope_to_string( p->search_scope ) ); + LOGDEBUG( "Searching user using filter %s with basedn: %s and scope %s", search_filter, p->groupdn, la_ldap_ldap_scope_to_string( p->search_scope ) ); rc = ldap_search_ext_s( ldap, p->groupdn, ldap_scope, search_filter, attrs, 0, NULL, NULL, &timeout, 1000, &result ); if( rc == LDAP_SUCCESS ){ /* Check how many entries were found. Only one should be returned */ int nbrow = ldap_count_entries( ldap, result ); if( nbrow < 1 ){ - LOGWARNING( "ldap_search_ext_s: user %s do not match group filter %s\n", userdn, search_filter ); + LOGWARNING( "ldap_search_ext_s: user %s do not match group filter %s", userdn, search_filter ); }else{ if( DODEBUG( ldap_context->verb ) ) - LOGINFO( "User %s matches %d groups with filter %s\n", userdn, nbrow, search_filter ); + LOGDEBUG( "User %s matches %d groups with filter %s", userdn, nbrow, search_filter ); res = 0; } } @@ -536,43 +535,43 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ /* Connection to LDAP backend */ ldap = connect_ldap( l ); if( ldap == NULL ){ - LOGERROR( "Could not connect to URI %s\n", config->ldap->uri ); + LOGERROR( "Could not connect to URI %s", config->ldap->uri ); goto la_ldap_handle_authentication_exit; } /* bind to LDAP server anonymous or authenticated */ rc = ldap_binddn( ldap, config->ldap->binddn, config->ldap->bindpw ); switch( rc ){ case LDAP_SUCCESS: - if( DODEBUG( l->verb ) ) - LOGINFO( "ldap_sasl_bind_s %s success\n", config->ldap->binddn ? config->ldap->binddn : "Anonymous" ); + if( DOINFO( l->verb ) ) + LOGINFO( "ldap_sasl_bind_s %s success", config->ldap->binddn ? config->ldap->binddn : "Anonymous" ); break; case LDAP_INVALID_CREDENTIALS: - LOGERROR( "ldap_binddn: Invalid Credentials\n" ); + LOGERROR( "ldap_binddn: Invalid Credentials" ); goto la_ldap_handle_authentication_free; default: - LOGERROR( "ldap_binddn: return value: %d/0x%2X %s\n", rc, rc, ldap_err2string( rc ) ); + LOGERROR( "ldap_binddn: return value: %d/0x%2X %s", rc, rc, ldap_err2string( rc ) ); goto la_ldap_handle_authentication_free; } /* find user and return userdn */ userdn = ldap_find_user( ldap, l, auth_context->username, client_context ); if( !userdn ){ - LOGWARNING( "LDAP user *%s* was not found \n", auth_context->username ); + LOGWARNING( "LDAP user *%s* was not found", auth_context->username ); goto la_ldap_handle_authentication_free; } if (auth_context && l->config ){ if (auth_context->username && strlen (auth_context->username) > 0 && auth_context->password){ - if (DODEBUG (l->verb)) { - LOGINFO ("LDAP-AUTH: Authenticating Username:%s\n", auth_context->username ); + if (DOINFO (l->verb)) { + LOGINFO ("LDAP-AUTH: Authenticating Username:%s", auth_context->username ); } rc = ldap_binddn( ldap, userdn, auth_context->password ); if( rc != LDAP_SUCCESS ){ - LOGERROR( "rebinding: return value: %d/0x%2X %s\n", rc, rc, ldap_err2string( rc ) ); + LOGERROR( "rebinding: return value: %d/0x%2X %s", rc, rc, ldap_err2string( rc ) ); }else{ /* success, let set our return value to SUCCESS */ - if( DODEBUG( l->verb ) ) - LOGINFO( "User *%s* successfully authenticate\n", auth_context->username ); + if( DOINFO( l->verb ) ) + LOGINFO( "User *%s* successfully authenticate", auth_context->username ); #ifdef ENABLE_LDAPUSERCONF /* load user settings from LDAP profile */ ldap_account_load_from_dn( l, ldap, userdn, client_context ); @@ -581,7 +580,8 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ res = OPENVPN_PLUGIN_FUNC_ERROR; goto la_ldap_handle_authentication_free; } - /* ldap_account_dump( client_context->ldap_account ); */ + if(DODEBUG(l->verb)) + ldap_account_dump( client_context->ldap_account ); #endif /* handle pf_rules if any, default value otherwise */ la_ldap_handle_pf_file( config, client_context, auth_context->pf_file ); @@ -601,7 +601,7 @@ la_ldap_handle_authentication( ldap_context_t *l, action_t *a){ la_ldap_handle_authentication_free: rc = ldap_unbind_ext_s( ldap, NULL, NULL ); if( rc != LDAP_SUCCESS ){ - LOGERROR( "ldap_unbind_ext_s: return value: %d/0x%2X %s\n", rc, rc, ldap_err2string( rc ) ); + LOGERROR( "ldap_unbind_ext_s: return value: %d/0x%2X %s", rc, rc, ldap_err2string( rc ) ); } if( userdn ) free( userdn ); diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 62a3910..5898dbc 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -57,7 +57,6 @@ #include "client_context.h" #include "ldap_profile.h" -#define DODEBUG(verb) ((verb) >= 4) #define DFT_REDIRECT_GATEWAY_FLAGS "def1 bypass-dhcp" pthread_mutex_t action_mutex; @@ -78,7 +77,7 @@ action_push( list_t *list, action_t *action) list_append( list, ( void * )action ); if( list_length( list ) == 1 ){ pthread_cond_signal( &action_cond ); - LOGINFO( "Sent signal to authenticating loop\n" ); + LOGINFO( "Sent signal to authenticating loop" ); } pthread_mutex_unlock( &action_mutex ); } @@ -140,11 +139,11 @@ get_env (const char *name, const char *envp[]) return NULL; } +#if 0 /* * Given an environmental variable name, dumps * the envp array values. */ -/* static void dump_env (const char *envp[]) { @@ -157,7 +156,7 @@ dump_env (const char *envp[]) } fprintf (stderr, "//END of dump_env\\\\\n"); } -*/ +#endif /* * Return the length of a string array @@ -173,52 +172,31 @@ string_array_len (const char *array[]) return i; } -#ifdef DO_DAEMONIZE - -/* - * Daemonize if "daemon" env var is true. - * Preserve stderr across daemonization if - * "daemon_log_redirect" env var is true. - */ -static void -daemonize (const char *envp[]) -{ - const char *daemon_string = get_env ("daemon", envp); - if (daemon_string && daemon_string[0] == '1') - { - const char *log_redirect = get_env ("daemon_log_redirect", envp); - int fd = -1; - if (log_redirect && log_redirect[0] == '1') - fd = dup (2); - if (daemon (0, 0) < 0) - { - fprintf (stderr, "LDAP-AUTH: daemonization failed\n"); - } - else if (fd >= 3) - { - dup2 (fd, 2); - close (fd); - } - } -} - -#endif - OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list) { ldap_context_t *context; + const char *daemon_string = NULL; + const char *log_redirect = NULL; const char *configfile = NULL; int rc = 0; + /* Are we in daemonized mode? If so, are we redirecting the logs? */ + daemon_string = get_env ("daemon", envp); + use_syslog = 0; + if( daemon_string && daemon_string[0] == '1'){ + log_redirect = get_env ("daemon_log_redirect", envp); + if( !(log_redirect && log_redirect[0] == '1')) + use_syslog = 1; + } /* * Allocate our context */ context = ldap_context_new( ); if( !context ){ - LOGERROR( "Failed to initialize context\n" ); + LOGERROR( "Failed to initialize ldap_context, no memory available?" ); goto error; } /* @@ -248,13 +226,13 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char context->config->ldap->timeout = atoi( optarg ); break; case '?': - fprintf( stderr, "LDAP-AUTH: Unknown Option -%c !!\n", optopt ); + LOGERROR("Unknown Option -%c !!", optopt ); break; case ':': - fprintf( stderr, "LDAP-AUTH: Missing argument for option -%c !!\n", optopt ); + LOGERROR ("Missing argument for option -%c !!", optopt ); break; default: - fprintf(stderr, "LDAP-AUTH: ?? getopt returned character code 0%o ??\n", rc); + LOGERROR ("?? getopt returned character code 0%o ??", rc); abort(); } } @@ -268,9 +246,6 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char */ config_set_default( context->config ); - /* - * Get verbosity level from environment - */ /* when ldap userconf is define, we need to hook onto those callbacks */ if( config_is_pf_enabled( context->config )){ @@ -285,6 +260,9 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char } #endif + /* + * Get verbosity level from environment + */ const char *verb_string = get_env ("verb", envp); if (verb_string) context->verb = atoi (verb_string); @@ -303,18 +281,18 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char switch( rc ){ case EAGAIN: - LOGERROR( "pthread_create returned EAGAIN: lacking resources\n" ); + LOGERROR( "pthread_create returned EAGAIN: lacking resources" ); break; case EINVAL: - LOGERROR( "pthread_create returned EINVAL: invalid attributes\n" ); + LOGERROR( "pthread_create returned EINVAL: invalid attributes" ); break; case EPERM: - LOGERROR( "pthread_create returned EPERM: no permission to create thread\n" ); + LOGERROR( "pthread_create returned EPERM: no permission to create thread" ); break; case 0: break; default: - LOGERROR( "pthread_create returned an unhandled value: %d\n", rc ); + LOGERROR( "pthread_create returned an unhandled value: %d", rc ); } if( rc == 0) return (openvpn_plugin_handle_t) context; @@ -336,21 +314,27 @@ int write_to_auth_control_file( char *auth_control_file, char value ) { int fd, rc; + int err = 0; fd = open( auth_control_file, O_WRONLY | O_CREAT, 0700 ); if( fd == -1 ){ - LOGERROR( "Could not open file %s: %s\n", auth_control_file, strerror( errno ) ); + LOGERROR( "Could not open file auth_control_file %s: %s", auth_control_file, strerror( errno ) ); return -1; } rc = write( fd, &value, 1 ); if( rc == -1 ){ - LOGERROR( "Could not write value %c to file %s: %s\n", value, auth_control_file, strerror( errno ) ); + LOGERROR( "Could not write value %c to auth_control_file %s: %s", value, auth_control_file, strerror( errno ) ); + err = 1; }else if( rc !=1 ){ - LOGERROR( "Could not write value %c to file %s\n", value, auth_control_file ); + LOGERROR( "Could not write value %c to auth_control_file %s", value, auth_control_file ); + err = 1; } rc = close( fd ); if( rc != 0 ){ - LOGERROR( "Could not close file %s: %s\n", auth_control_file, strerror( errno ) ); + LOGERROR( "Could not close file auth_control_file %s: %s", auth_control_file, strerror( errno ) ); } + /* Give the user a hind on why it potentially failed */ + if( err != 0) + LOGERROR( "Is *tmp-dir* set up correctly in openvpn config?"); return rc == 0; } @@ -387,7 +371,7 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, auth_context = auth_context_new( ); if( !auth_context ){ - LOGERROR( "Could not allocate auth_context before calling thread\n" ); + LOGERROR( "Could not allocate auth_context before calling thread" ); return res; } if( username ) auth_context->username = strdup( username ); @@ -424,7 +408,7 @@ openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, return OPENVPN_PLUGIN_FUNC_ERROR; } if (!cc || !cc->profile){ - LOGERROR("No profile found for user\n"); + LOGERROR("No profile found for user"); return OPENVPN_PLUGIN_FUNC_ERROR; } #ifdef ENABLE_LDAPUSERCONF @@ -467,16 +451,16 @@ openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) ldap_context_t *context = (ldap_context_t *) handle; action_t *action = action_new( ); - if (DODEBUG (context->verb)) - LOGINFO( "close\n" ); + if (DOINFO (context->verb)) + LOGINFO( "%s() called", __FUNCTION__ ); if( action){ action->type = LDAP_AUTH_ACTION_QUIT; action_push( context->action_list, action ); if( DODEBUG( context->verb ) ) - LOGINFO ("Waiting for thread to return\n"); + LOGDEBUG ("Waiting for thread to return"); pthread_join( action_thread, NULL ); if( DODEBUG( context->verb ) ) - LOGINFO ("Thread returned queries left in queue: %d\n", list_length( context->action_list )); + LOGDEBUG ("Thread returned queries left in queue: %d", list_length( context->action_list )); pthread_attr_destroy( &action_thread_attr ); pthread_mutex_destroy( &action_mutex ); pthread_cond_destroy( &action_cond ); @@ -492,16 +476,16 @@ openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) if (context) { action_t *action = action_new( ); - if (DODEBUG (context->verb)) - LOGINFO( "close\n" ); + if (DOINFO (context->verb)) + LOGINFO( "%s() called", __FUNCTION__ ); if( action){ action->type = LDAP_AUTH_ACTION_QUIT; action_push( context->action_list, action ); if( DODEBUG( context->verb ) ) - LOGINFO ("Waiting for thread to return\n"); + LOGDEBUG ("Waiting for thread to return"); pthread_join( action_thread, NULL ); if( DODEBUG( context->verb ) ) - LOGINFO ("Thread returned queries left in queue: %d\n", list_length( context->action_list )); + LOGDEBUG ("Thread returned queries left in queue: %d", list_length( context->action_list )); pthread_attr_destroy( &action_thread_attr ); pthread_mutex_destroy( &action_mutex ); pthread_cond_destroy( &action_cond ); @@ -530,14 +514,14 @@ action_thread_main_loop (void *c) if (action){ switch (action->type){ case LDAP_AUTH_ACTION_AUTH: - if( DODEBUG(context->verb ) ){ - LOGINFO( "Authentication requested for user %s\n", + if( DOINFO(context->verb ) ){ + LOGINFO ( "Authentication requested for user %s", ((auth_context_t *)action->context)->username); } rc = la_ldap_handle_authentication( context, action ); /* we need to write the result to auth_control_file */ if( DODEBUG(context->verb ) ){ - LOGINFO( "User %s: Writing %c to file %s\n", + LOGDEBUG( "User %s: Writing %c to auth_control_file %s", ((auth_context_t *)action->context)->username, rc == OPENVPN_PLUGIN_FUNC_SUCCESS ? '1' : '0', ((auth_context_t *)action->context)->auth_control_file); @@ -546,15 +530,13 @@ action_thread_main_loop (void *c) rc == OPENVPN_PLUGIN_FUNC_SUCCESS ? '1' : '0'); break; case LDAP_AUTH_ACTION_QUIT: - if( DODEBUG(context->verb ) ){ + if( DOINFO(context->verb ) ){ LOGINFO( "Authentication thread received ACTION_QUIT\n"); } loop = 0; break; default: - if (DODEBUG (context->verb) ){ - LOGINFO( "Unknown action %d\n", action->type); - } + LOGWARNING( "%s:%d %s() Unknown action %d", __FILE__, __LINE__, __FUNCTION__, action->type); } action_free( action ); } diff --git a/src/ldap_profile.c b/src/ldap_profile.c index af5f2ae..929a62d 100644 --- a/src/ldap_profile.c +++ b/src/ldap_profile.c @@ -24,7 +24,6 @@ #ifdef ENABLE_LDAPUSERCONF -#define DODEBUG(verb) ((verb) >= 4) #include "debug.h" #include "utils.h" @@ -70,30 +69,28 @@ ldap_profile_free( ldap_profile_t *l ){ void ldap_profile_dump( ldap_profile_t *l ){ - fprintf(stdout, "Account profile:\n\ -\tstart_date:\t\t%u\n\ -\tend_date:\t\t%u\n\ -\tpf_client_default_accept:\t\t%s\n\ -\tpf_subnet_default_accept:\t\t%s\n\ -\tpf_client_rules:\t\t%s\n\ -\tpf_subnet_rules:\t\t%s\n\ -\tpush_reset:\t\t%s\n\ -\tconfig:\t\t%s\n", - (unsigned int)l->start_date, (unsigned int)l->end_date, - l->pf_client_default_accept == TERN_TRUE ? "ACCEPT" : l->pf_client_default_accept == TERN_FALSE ? "DROP": "Undef", - l->pf_subnet_default_accept == TERN_TRUE ? "ACCEPT" : l->pf_subnet_default_accept == TERN_FALSE ? "DROP" : "Undef", - l->pf_client_rules ? l->pf_client_rules : "None", - l->pf_subnet_rules ? l->pf_subnet_rules : "None", - l->push_reset == TERN_TRUE ? "TRUE" : l->push_reset == TERN_FALSE ? "FALSE" : "Undef", - l->config ? l->config : "None"); - fprintf( stdout, "\tpush options:\n" ); + LOGDEBUG("Account profile:"); + LOGDEBUG("start_date: %u", (unsigned int)l->start_date); + LOGDEBUG("end_date: %u", (unsigned int)l->end_date); + LOGDEBUG("pf_client_default_accept: %s", + l->pf_client_default_accept == TERN_TRUE ? "ACCEPT" : + l->pf_client_default_accept == TERN_FALSE ? "DROP": "Undef"); + LOGDEBUG("pf_subnet_default_accept: %s", + l->pf_subnet_default_accept == TERN_TRUE ? "ACCEPT" : + l->pf_subnet_default_accept == TERN_FALSE ? "DROP" : "Undef"); + LOGDEBUG("pf_client_rules: %s", l->pf_client_rules ? l->pf_client_rules : "None"); + LOGDEBUG("pf_subnet_rules: %s", l->pf_subnet_rules ? l->pf_subnet_rules : "None"); + LOGDEBUG("push_reset: %s", + l->push_reset == TERN_TRUE ? "TRUE" : l->push_reset == TERN_FALSE ? "FALSE" : "Undef"); + LOGDEBUG("config: %s", l->config ? l->config : "None"); + LOGDEBUG("push options:" ); list_item_t *i; for(i = list_first( l->push_options ); i!=NULL; i = list_item_next( i ) ){ - fprintf( stdout, "\t\t\t%s\n", i->data ? (char *)(i->data) : "None"); + LOGDEBUG(" %s", i->data ? (char *)(i->data) : "None"); } - fprintf( stdout, "\tiroutes:\n" ); + LOGDEBUG("iroutes:" ); for(i = list_first( l->iroutes ); i!=NULL; i = list_item_next( i ) ){ - fprintf( stdout, "\t\t\t%s\n", i->data ? (char *)i->data : "None"); + LOGDEBUG(" %s", i->data ? (char *)i->data : "None"); } } @@ -128,11 +125,9 @@ ldap_account_free( ldap_account_t *l){ void ldap_account_dump( ldap_account_t *l ){ - fprintf(stdout, "LDAP account dump:\n\ -\tifconfig_push:\t\t%s\n\ -\tprofile_dn:\t\t%s\n", - l->ifconfig_push ? l->ifconfig_push : "None", - l->profile_dn ? l->profile_dn : "None"); + LOGDEBUG("LDAP account dump:"); + LOGDEBUG("ifconfig_push: %s", l->ifconfig_push ? l->ifconfig_push : "None"); + LOGDEBUG("profile_dn: %s", l->profile_dn ? l->profile_dn : "None"); ldap_profile_dump( l->profile ); } diff --git a/src/utils.c b/src/utils.c index fe26228..1dff851 100644 --- a/src/utils.c +++ b/src/utils.c @@ -44,7 +44,7 @@ la_memset( void *s, int c, size_t n ){ } /** - * same as stdup but given a va_list + * same as strdup but given a va_list */ char * vstrdupf (const char *fmt, va_list vargs){ From c9e70c29f9193d303ce7c7bbd4a5c0527ccd9fb2 Mon Sep 17 00:00:00 2001 From: chantra Date: Fri, 13 May 2011 15:15:45 +0200 Subject: [PATCH 35/44] Make LDAP_OPT_X_TLS_REQUIRE_CERT work works without modifying /etc/ldap/ldap.conf --- src/la_ldap.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/la_ldap.c b/src/la_ldap.c index 525e8e6..2a4355c 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -402,6 +402,20 @@ connect_ldap( ldap_context_t *l ){ int ldap_tls_require_cert; struct timeval timeout; + /* SSL/TLS */ + if( strcmp( config->ldap->ssl, "start_tls" ) == 0){ + /** + * TODO handle certif properly. Seems that LDAP_OPT_X_TLS_REQUIRE_CERT + * needs to be set up before handle initialization + */ + ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); + if( rc != LDAP_OPT_SUCCESS ){ + LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"", rc, ldap_err2string(rc) ); + goto connect_ldap_error; + } + } + /* init connection to ldap */ rc = ldap_initialize(&ldap, config->ldap->uri); if( rc!= LDAP_SUCCESS ){ @@ -424,12 +438,15 @@ connect_ldap( ldap_context_t *l ){ /* SSL/TLS */ if( strcmp( config->ldap->ssl, "start_tls" ) == 0){ /*TODO handle certif properly */ + /** + * Handled earlier in code, deprecated ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); if( rc != LDAP_OPT_SUCCESS ){ LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"", rc, ldap_err2string(rc) ); goto connect_ldap_error; } + */ rc = ldap_start_tls_s( ldap, NULL, NULL ); if( rc != LDAP_SUCCESS && rc != LDAP_LOCAL_ERROR ){ LOGERROR( "ldap_start_tls_s returned (%d) \"%s\"", rc, ldap_err2string(rc) ); From 4ed93a9f12d9e64006038ef99218e4fc56e16c28 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 12 Jul 2011 00:40:33 +0200 Subject: [PATCH 36/44] [TLS] Adding support for TLS_REQCERT tls_reqcert=never|allow|try|demand|hard is now supported in config. Defaults to *never* --- src/la_ldap.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/la_ldap.c b/src/la_ldap.c index 2a4355c..ef65db1 100644 --- a/src/la_ldap.c +++ b/src/la_ldap.c @@ -39,6 +39,22 @@ #define PF_ALLOW_ALL "[CLIENTS ACCEPT]\n[SUBNETS ACCEPT]\n[END]\n" +int +ldap_tlsreqcert_from_string(char *s){ + if( strcasecmp(s, "never") == 0) + return LDAP_OPT_X_TLS_NEVER; + if( strcasecmp(s, "hard") == 0) + return LDAP_OPT_X_TLS_HARD; + if (strcasecmp(s, "demand") == 0) + return LDAP_OPT_X_TLS_DEMAND; + if (strcasecmp(s, "allow") == 0) + return LDAP_OPT_X_TLS_ALLOW; + if (strcasecmp(s, "try") == 0) + return LDAP_OPT_X_TLS_TRY; + + return -1; +} + void ldap_context_free( ldap_context_t *l ){ if( !l ) return; @@ -408,11 +424,15 @@ connect_ldap( ldap_context_t *l ){ * TODO handle certif properly. Seems that LDAP_OPT_X_TLS_REQUIRE_CERT * needs to be set up before handle initialization */ - ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; + ldap_tls_require_cert = ldap_tlsreqcert_from_string(config->ldap->tls_reqcert); + if( ldap_tls_require_cert == -1){ + LOGERROR( "%s is not a valid TLS_REQCERT value", config->ldap->tls_reqcert); + return NULL; + } rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); if( rc != LDAP_OPT_SUCCESS ){ LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"", rc, ldap_err2string(rc) ); - goto connect_ldap_error; + return NULL; } } @@ -438,15 +458,6 @@ connect_ldap( ldap_context_t *l ){ /* SSL/TLS */ if( strcmp( config->ldap->ssl, "start_tls" ) == 0){ /*TODO handle certif properly */ - /** - * Handled earlier in code, deprecated - ldap_tls_require_cert = LDAP_OPT_X_TLS_NEVER; - rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_require_cert ); - if( rc != LDAP_OPT_SUCCESS ){ - LOGERROR( "ldap_set_option TLS_REQ_CERT returned (%d) \"%s\"", rc, ldap_err2string(rc) ); - goto connect_ldap_error; - } - */ rc = ldap_start_tls_s( ldap, NULL, NULL ); if( rc != LDAP_SUCCESS && rc != LDAP_LOCAL_ERROR ){ LOGERROR( "ldap_start_tls_s returned (%d) \"%s\"", rc, ldap_err2string(rc) ); From a9efa5084670302f13ba82fef3217a4546a0090b Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 12 Jul 2011 00:43:45 +0200 Subject: [PATCH 37/44] Updating README/UPGRADE DOC --- README | 1 + UPGRADE-from-0.0.X.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README b/README index c37c981..d655703 100644 --- a/README +++ b/README @@ -39,6 +39,7 @@ binddn=cn=admin,dc=example,dc=com bindpw=secret version=3 #ssl=start_tls +#tls_reqcert=never ssl=off groupdn=ou=roles,dc=example,dc=com group_search_filter=|(cn=vpn)(cn=sysadmins) diff --git a/UPGRADE-from-0.0.X.txt b/UPGRADE-from-0.0.X.txt index 10974ec..018b8ec 100644 --- a/UPGRADE-from-0.0.X.txt +++ b/UPGRADE-from-0.0.X.txt @@ -90,9 +90,12 @@ binddn=cn=admin,dc=example,dc=com bindpw=secret version=3 #ssl=start_tls +#tls_reqcert=never ssl=off timeout +tls_reqcert can take the following values (default to never): never|try|allow|hard|demand + Some more parameters exist which are ignore at the moment and might be subject to change, so it is not recommended you use them: tls_cacertfile @@ -100,7 +103,6 @@ tls_cacertdir tls_certfile tls_certkey tls_ciphersuite -tls_reqcert == Profile parameters Profiles allow to define how to find users. Each profile can have different rules From 449585a0a697b8eecb6c66d87fd03aaa6bdecc57 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 12 Jul 2011 01:01:07 +0200 Subject: [PATCH 38/44] Fix unused vaue warning for gcc 4.6.1 --- src/cnf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cnf.c b/src/cnf.c index 71b4920..8771952 100644 --- a/src/cnf.c +++ b/src/cnf.c @@ -404,7 +404,7 @@ config_parse_file( const char *filename, config_t *c ){ free( line ); } close( fd ); - return 0; + return rc; } const char * From 948b849ef4f66c34b7e998220b3e3741ef6f393b Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 12 Jul 2011 01:01:36 +0200 Subject: [PATCH 39/44] [configure] Add lber.h header to autoconf Needed on Debian Wheezy --- configure.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.in b/configure.in index 1454e57..75288a7 100644 --- a/configure.in +++ b/configure.in @@ -36,6 +36,10 @@ AC_CHECK_HEADER([ldap.h], [AC_CHECK_LIB(ldap, [ldap_initialize])], [AC_MSG_ERROR("ldap headers not found")]) +AC_CHECK_HEADER([lber.h], + [AC_CHECK_LIB(lber, [ber_free])], + [AC_MSG_ERROR("lber headers not found")]) + AC_CHECK_HEADER([pthread.h], [AC_CHECK_LIB(pthread, [pthread_create])], [AC_MSG_ERROR("pthread headers not found")]) From 75f196eaae31a6bfaa1d14667475fb1d0bfa9ce8 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 26 Jul 2011 02:12:48 +0200 Subject: [PATCH 40/44] [config] use a default config filename In case -c option is not used, the plugin will use a default filename to load the config from. this will must exist even though it might be empty --- src/ldap-auth.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 5898dbc..ac5c91e 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -58,6 +58,8 @@ #include "ldap_profile.h" #define DFT_REDIRECT_GATEWAY_FLAGS "def1 bypass-dhcp" +#define OCONFIG "/etc/openvpn/openvpn-ldap.conf" + pthread_mutex_t action_mutex; pthread_cond_t action_cond; @@ -239,8 +241,16 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char /** * Parse configuration file is -c filename is provided + * If not provided, use a default config file OCONFIG + * This file must exists even though it might be empty */ - if( configfile ) config_parse_file( configfile, context->config ); + if( configfile == NULL) { + configfile = OCONFIG; + } + + if( config_parse_file( configfile, context->config ) ){ + goto error; + } /** * Set default config values */ From 48c1b4c3907dbdbe8f35122b66a3fd7cc6d351b9 Mon Sep 17 00:00:00 2001 From: chantra Date: Tue, 26 Jul 2011 02:24:11 +0200 Subject: [PATCH 41/44] updating changelog --- Changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changelog b/Changelog index 882e033..6213e4e 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +version 1.0.0 undef + * Features: + + handle TLS_REQCERT to some extend + + Use LDAP backend to keep user settings + * Improvements: + + Fallback to default config filename + version 0.0.6 2010-08-03 * Handle *version* argument correctly From 6dd653a52d413d15d30b4fc95a11954a183e4ed0 Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 21 Sep 2011 12:43:58 +0200 Subject: [PATCH 42/44] Adding -C option to generate cores --- configure.in | 2 +- src/ldap-auth.c | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 75288a7..beb705b 100644 --- a/configure.in +++ b/configure.in @@ -44,7 +44,7 @@ AC_CHECK_HEADER([pthread.h], [AC_CHECK_LIB(pthread, [pthread_create])], [AC_MSG_ERROR("pthread headers not found")]) -AC_CHECK_HEADERS([syslog.h]) +AC_CHECK_HEADERS([syslog.h sys/resource.h ]) AC_PROG_INSTALL diff --git a/src/ldap-auth.c b/src/ldap-auth.c index ac5c91e..ef90be3 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -38,7 +38,15 @@ #include #include #include + +#ifdef HAVE_SYSLOG_H #include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#include +#endif #include #include @@ -174,6 +182,26 @@ string_array_len (const char *array[]) return i; } +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) +static void +unlimit_core_size(void) +{ + struct rlimit lim; + + getrlimit(RLIMIT_CORE, &lim); + if (lim.rlim_max == 0) + { + LOGERROR("Cannot set core file size limit; disallowed by hard limit"); + return; + } + else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max) + { + lim.rlim_cur = lim.rlim_max; + setrlimit(RLIMIT_CORE, &lim); + } +} +#endif + OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list) { @@ -183,6 +211,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char const char *log_redirect = NULL; const char *configfile = NULL; + uint8_t allow_core_files = 0; int rc = 0; /* Are we in daemonized mode? If so, are we redirecting the logs? */ @@ -206,7 +235,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char */ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); - while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:t:WZ" ) ) != - 1 ){ + while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:t:WZC" ) ) != - 1 ){ switch( rc ) { case 'H': context->config->ldap->uri = strdup(optarg); @@ -227,6 +256,9 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char case 't': context->config->ldap->timeout = atoi( optarg ); break; + case 'C': + allow_core_files = 1; + break; case '?': LOGERROR("Unknown Option -%c !!", optopt ); break; @@ -239,6 +271,11 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char } } +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) + if (allow_core_files) + unlimit_core_size(); +#endif + /** * Parse configuration file is -c filename is provided * If not provided, use a default config file OCONFIG From 3886bca90119db444f8690c328881ff4d4fee8d2 Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 21 Sep 2011 13:18:25 +0200 Subject: [PATCH 43/44] Really allowing core generation --- configure.in | 1 + src/ldap-auth.c | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index beb705b..769ae74 100644 --- a/configure.in +++ b/configure.in @@ -45,6 +45,7 @@ AC_CHECK_HEADER([pthread.h], [AC_MSG_ERROR("pthread headers not found")]) AC_CHECK_HEADERS([syslog.h sys/resource.h ]) +AC_CHECK_FUNCS([getrlimit]) AC_PROG_INSTALL diff --git a/src/ldap-auth.c b/src/ldap-auth.c index ef90be3..83205cb 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -28,6 +28,7 @@ */ +#include "config.h" #include #include #include @@ -55,7 +56,6 @@ #include -#include "config.h" #include "cnf.h" #include "utils.h" #include "debug.h" @@ -73,6 +73,7 @@ pthread_mutex_t action_mutex; pthread_cond_t action_cond; pthread_attr_t action_thread_attr; pthread_t action_thread = 0; +uint8_t allow_core_files = 0; /* forward declaration of main loop */ static void *action_thread_main_loop (void *c); @@ -188,7 +189,10 @@ unlimit_core_size(void) { struct rlimit lim; - getrlimit(RLIMIT_CORE, &lim); + if(getrlimit(RLIMIT_CORE, &lim) != 0){ + LOGERROR("Could not get Core file size limits, err (%d): %s", errno, strerror(errno)); + return; + } if (lim.rlim_max == 0) { LOGERROR("Cannot set core file size limit; disallowed by hard limit"); @@ -197,7 +201,11 @@ unlimit_core_size(void) else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max) { lim.rlim_cur = lim.rlim_max; - setrlimit(RLIMIT_CORE, &lim); + if (setrlimit(RLIMIT_CORE, &lim) != 0){ + LOGERROR("Could not set RLIMIT_CORE to %lld", lim.rlim_cur); + } + }else { + LOGDEBUG("Limit not set, soft limit %lld, hardlimit %lld", lim.rlim_cur, lim.rlim_max); } } #endif @@ -211,7 +219,6 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char const char *log_redirect = NULL; const char *configfile = NULL; - uint8_t allow_core_files = 0; int rc = 0; /* Are we in daemonized mode? If so, are we redirecting the logs? */ @@ -257,6 +264,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char context->config->ldap->timeout = atoi( optarg ); break; case 'C': + LOGDEBUG("Core file generation requested"); allow_core_files = 1; break; case '?': @@ -272,8 +280,10 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char } #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) - if (allow_core_files) + if (allow_core_files){ + LOGDEBUG ("Setting core file"); unlimit_core_size(); + } #endif /** From c21bce666a7a592b6b372ed204335df3db5972bd Mon Sep 17 00:00:00 2001 From: chantra Date: Wed, 21 Sep 2011 13:20:18 +0200 Subject: [PATCH 44/44] allow_core_files do not need to be global --- src/ldap-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ldap-auth.c b/src/ldap-auth.c index 83205cb..4affc6f 100644 --- a/src/ldap-auth.c +++ b/src/ldap-auth.c @@ -73,7 +73,6 @@ pthread_mutex_t action_mutex; pthread_cond_t action_cond; pthread_attr_t action_thread_attr; pthread_t action_thread = 0; -uint8_t allow_core_files = 0; /* forward declaration of main loop */ static void *action_thread_main_loop (void *c); @@ -220,6 +219,7 @@ openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char const char *configfile = NULL; int rc = 0; + uint8_t allow_core_files = 0; /* Are we in daemonized mode? If so, are we redirecting the logs? */ daemon_string = get_env ("daemon", envp);