diff -u -r freeradius-1.1.7/src/modules/rlm_ldap/configure.in work/src/modules/rlm_ldap/configure.in --- freeradius-1.1.7/src/modules/rlm_ldap/configure.in 2007-06-26 03:34:58.000000000 -0400 +++ work/src/modules/rlm_ldap/configure.in 2007-11-03 14:49:46.000000000 -0400 @@ -70,6 +70,75 @@ ;; esac ]) + dnl extra argument: --with-rlm-ldap-krb5-include-dir + rlm_ldap_krb5_inc_dir= + AC_ARG_WITH(rlm-ldap-krb5-include-dir, + [ --with-rlm-ldap-krb5-include-dir=DIR Directory for krb5 include files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need rlm-ldap-krb5-include-dir) + ;; + yes) + ;; + *) + rlm_ldap_krb5_include_dir="$withval" + ;; + esac ] + ) + + dnl extra argument: --with-rlm-ldap-sasl2-include-dir + rlm_ldap_sasl2_inc_dir= + AC_ARG_WITH(rlm-ldap-sasl2-include-dir, + [ --with-rlm-ldap-sasl2-include-dir=DIR Directory for sasl2 include files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need rlm-ldap-sasl2-include-dir) + ;; + yes) + ;; + *) + rlm_ldap_sasl2_include_dir="$withval" + ;; + esac ] + ) + + dnl extra argument: --with-rlm-ldap-sasl2 + rlm_ldap_with_sasl2=yes + AC_ARG_WITH(rlm-ldap-sasl2, + [ --with-rlm-ldap-sasl2 use sasl2, if available. (default=yes) ], + [ case "$withval" in + no) + rlm_ldap_with_sasl2=no + ;; + *) + ;; + esac ]) + + if test "x$rlm_ldap_with_sasl2" = "xyes"; then + AC_DEFINE(USE_SASL2, [], [Defined if building with SASL2 support]) + fi + + dnl extra argument: --with-rlm-ldap-krb5 + rlm_ldap_with_krb5=yes + AC_ARG_WITH(rlm-ldap-krb5, + [ --with-rlm-ldap-krb5 use krb5, if available. (default=yes) ], + [ case "$withval" in + no) + rlm_ldap_with_krb5=no + ;; + *) + ;; + esac ]) + + if test "x$rlm_ldap_with_krb5" = "xyes"; then + if test "x$rlm_ldap_with_sasl2" != "xyes"; then + fail="$fail sasl2 if using krb5" + # force sasl on if using krb5 + #rlm_ldap_with_sasl2="yes" + fi + AC_DEFINE(USE_KRB5, [], [Defined if building with krb5 support]) + fi + dnl ############################################################ dnl # Check for libraries dnl ############################################################ @@ -102,6 +171,20 @@ fi fi + if test "x$rlm_ldap_with_sasl2" = "xyes"; then + AC_SMART_CHECK_LIB(sasl2, sasl_client_start) + if test "x$ac_cv_lib_sasl2_sasl_client_start" != "xyes"; then + fail="$fail libsasl2" + fi + fi + + if test "x$rlm_ldap_with_krb5" = "xyes"; then + AC_SMART_CHECK_LIB(krb5, krb5_init_context) + if test "x$ac_cv_lib_krb5_krb5_init_context" != xyes; then + fail="$fail krb5" + fi + fi + dnl ############################################################ dnl # Check for header files dnl ############################################################ @@ -112,6 +195,23 @@ fail="$fail ldap.h" fi + if test "x$rlm_ldap_with_sasl2" = "xyes"; then + smart_try_dir=$rlm_ldap_sasl2_include_dir + AC_SMART_CHECK_INCLUDE(sasl.h) + if test "$ac_cv_header_sasl_h" != "yes"; then + fail="$fail sasl.h" + fi + fi + + if test "x$rlm_ldap_with_krb5" = "xyes"; then + smart_try_dir=$rlm_ldap_krb5_include_dir + AC_SMART_CHECK_INCLUDE(krb5.h) + if test "$ac_cv_header_krb5_h" != "yes"; then + fail="$fail krb5.h" + fi + fi + + dnl ############################################################ dnl # Check for library functions dnl ############################################################ @@ -168,4 +268,5 @@ AC_SUBST(ldap_ldflags) AC_SUBST(ldap_cflags) AC_SUBST(targetname) +AC_CONFIG_HEADER(config.h) AC_OUTPUT(Makefile) diff -u -r freeradius-1.1.7/src/modules/rlm_ldap/rlm_ldap.c work/src/modules/rlm_ldap/rlm_ldap.c --- freeradius-1.1.7/src/modules/rlm_ldap/rlm_ldap.c 2007-11-01 13:16:18.000000000 -0400 +++ work/src/modules/rlm_ldap/rlm_ldap.c 2007-11-09 16:52:36.000000000 -0500 @@ -1,3 +1,4 @@ +// -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; -*- /* * rlm_ldap.c LDAP authorization and authentication module. * @@ -159,7 +160,9 @@ */ static const char rcsid[] = "$Id: freeradius-1.1.7-ipa.patch,v 1.2 2007/11/16 13:34:48 jdennis Exp $"; +#define _GNU_SOURCE #include "autoconf.h" +#include "config.h" #include #include @@ -187,6 +190,14 @@ #include "modules.h" #include "rad_assert.h" +#ifdef USE_KRB5 +#include +#endif + +#ifdef USE_SASL2 +#include +#endif + #ifndef HAVE_PTHREAD_H /* * This is a lot simpler than putting ifdef's around @@ -274,6 +285,19 @@ #endif } LDAP_CONN; +#ifdef USE_KRB5 +typedef struct krb_session { + krb5_context context; + char *realm_name; + krb5_principal principal; + krb5_keytab keytab; + char *ccname; + char *ccache_file; + krb5_ccache ccache; + krb5_creds creds; +} krb_session; +#endif + typedef struct { char *server; int port; @@ -322,6 +346,17 @@ int edir_account_policy_check; #endif int set_auth_type; +#ifdef USE_SASL2 + int use_sasl; + char *sasl_mech; +#endif +#ifdef USE_KRB5 + char *krb_keytab; + char *krb_principal; + krb_session krb; +#endif + char *clients_basedn; + char *clients_filter; } ldap_instance; /* The default setting for TLS Certificate Verification */ @@ -370,6 +405,16 @@ #endif {"set_auth_type", PW_TYPE_BOOLEAN, offsetof(ldap_instance,set_auth_type), NULL, "yes"}, +#ifdef USE_SASL2 + {"use_sasl", PW_TYPE_BOOLEAN, offsetof(ldap_instance,use_sasl), NULL, "no"}, + {"sasl_mech", PW_TYPE_STRING_PTR, offsetof(ldap_instance,sasl_mech), NULL, "GSSAPI"}, +#endif +#ifdef USE_KRB5 + {"krb_keytab", PW_TYPE_STRING_PTR, offsetof(ldap_instance,krb_keytab), NULL, "${confdir}/krb5.keytab"}, + {"krb_principal", PW_TYPE_STRING_PTR, offsetof(ldap_instance,krb_principal), NULL, NULL}, +#endif + {"clients_basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,clients_basedn), NULL, NULL}, + {"clients_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,clients_filter), NULL, "(objectclass=radiusClientProfile)"}, {NULL, -1, 0, NULL, NULL} }; @@ -380,11 +425,220 @@ #ifdef FIELDCPY static void fieldcpy(char *, char **); #endif + +#ifdef USE_KRB5 +static krb5_timestamp ticket_lifetime = 300; + +static void krb_session_zero(krb_session *krb) +{ + DEBUG("rlm_ldap: krb_session_zero (%p)", krb); + krb->context = NULL; + krb->realm_name = NULL; + memset ((char*)&krb->principal, 0, sizeof(krb->principal)); + krb->keytab = NULL; + krb->ccname = NULL; + krb->ccache_file = NULL; + krb->ccache = NULL; + memset ((char*)&krb->creds, 0, sizeof(krb->creds)); +} + +static void krb_session_free(krb_session *krb) +{ + DEBUG("rlm_ldap: krb_session_free (%p)", krb); + if (krb->ccache_file) { + unlink(krb->ccache_file); + free(krb->ccache_file); + } + + if (krb->ccname) { + free(krb->ccname); + if (unsetenv("KRB5CCNAME") < 0) { + radlog(L_ERR, "rlm_ldap: Unable remove the environment variable KRB5CCNAME (%d)%s", + errno, strerror(errno)); + } + } + + if (krb->context) { + krb5_free_cred_contents(krb->context, &krb->creds); + if (krb->ccache) krb5_cc_close(krb->context, krb->ccache); + if (krb->keytab) krb5_kt_close(krb->context, krb->keytab); + if (krb->principal) krb5_free_principal(krb->context, krb->principal); + if (krb->realm_name) krb5_free_default_realm(krb->context, krb->realm_name); + krb5_free_context(krb->context); + } + krb_session_zero(krb); +} + +static int krb_session_expired(krb_session *krb) +{ + int retval; + krb5_timestamp currenttime; + krb5_timestamp epsilon = 60; + + if (!krb->context) return TRUE; + + if ((retval = krb5_timeofday (krb->context, ¤ttime))){ + radlog(L_ERR, "rlm_ldap: could not get time of day (%s)", krb5_get_error_message(krb->context, retval)); + return TRUE; + } + + if (krb->creds.times.endtime < currenttime+epsilon) { + return TRUE; + } else { + return FALSE; + } + +} + +static char *get_tmp_file() +{ + char *tmp_template = "/tmp/XXXXXX"; + char *tmp_file = NULL; + int fd = -1; + + if (!(tmp_file = strdup(tmp_template))) { + radlog(L_ERR, "rlm_ldap: Out of memory!"); + return NULL; + } + + if ((fd = mkstemp(tmp_file)) < 0) { + radlog(L_ERR, "rlm_ldap: Failed to create tmp file with errno: (%d)%s", errno, strerror(errno)); + free(tmp_file); + return NULL; + } + /* close mimmediately, we don't need to keep the file open */ + close(fd); + return tmp_file; +} + +static int krb_session_get_ticket(krb_session *krb) +{ + int krberr; + int ticket_expired; + krb5_get_init_creds_opt options; + + ticket_expired = krb_session_expired(krb); + DEBUG("rlm_ldap: krb_session_get_ticket, %s", + ticket_expired ? "expired, getting new ticket":"ticket still valid, returning"); + if (!ticket_expired) return 0; + + memset(&options, 0, sizeof(options)); + krb5_get_init_creds_opt_set_address_list(&options, NULL); + krb5_get_init_creds_opt_set_forwardable(&options, 0); + krb5_get_init_creds_opt_set_proxiable(&options, 0); + /* set a very short lifetime, we don't keep the ticket around */ + krb5_get_init_creds_opt_set_tkt_life(&options, ticket_lifetime); + + if ((krberr = krb5_get_init_creds_keytab(krb->context, &krb->creds, krb->principal, + krb->keytab, 0, NULL, &options))) { + radlog(L_ERR, "rlm_ldap: Failed to init credentials: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + if ((krberr = krb5_cc_initialize(krb->context, krb->ccache, krb->principal))) { + radlog(L_ERR, "rlm_ldap: Failed to init ccache: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + if ((krberr = krb5_cc_store_cred(krb->context, krb->ccache, &krb->creds))) { + radlog(L_ERR, "rlm_ldap: Failed to store creds: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + return 0; +} + +static int krb_session_init(void *instance, krb_session *krb) +{ + ldap_instance *inst = instance; + int krberr; + + DEBUG("rlm_ldap: krb_session_init (%p) principal=%s keytab=%s" , krb, inst->krb_principal, inst->krb_keytab); + if ((krberr = krb5_init_context(&krb->context))) { + radlog(L_ERR, "rlm_ldap: Failed to init kerberos context"); + return -1; + } + + if ((krberr = krb5_get_default_realm(krb->context, &krb->realm_name))) { + radlog(L_ERR, "rlm_ldap: Failed to get default realm name: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + if ((krberr = krb5_parse_name(krb->context, inst->krb_principal, &krb->principal))) { + radlog(L_ERR, "rlm_ldap: Unable to parse principal %s: %s", inst->krb_principal, krb5_get_error_message(krb->context, krberr)); + return -1; + } + + if ((krberr = krb5_kt_resolve(krb->context, inst->krb_keytab, &krb->keytab))) { + radlog(L_ERR, "rlm_ldap: Failed to read keytab file: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + if (!(krb->ccache_file = get_tmp_file())) { + radlog(L_ERR, "rlm_ldap: could not create krb credential cached file"); + return -1; + } + + if (asprintf(&krb->ccname, "FILE:%s", krb->ccache_file) < 0) { + radlog(L_ERR, "rlm_ldap: Out of memory!"); + return -1; + } + + if (setenv("KRB5CCNAME", krb->ccname, 1) < 0) { + radlog(L_ERR, "rlm_ldap: Unable to set environment variable KRB5CCNAME (%d)%s", errno, strerror(errno)); + return -1; + } + + if ((krberr = krb5_cc_resolve(krb->context, krb->ccname, &krb->ccache))) { + radlog(L_ERR, "rlm_ldap: Failed to set cache name: %s", krb5_get_error_message(krb->context, krberr)); + return -1; + } + + return 0; +} + +#endif + +#ifdef USE_SASL2 +static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *in) +{ + sasl_interact_t *interact = NULL; + int ret = LDAP_OTHER; + + DEBUG("rlm_ldap: ldap_sasl_interact"); + + if (!ld) return LDAP_PARAM_ERROR; + + for (interact = in; interact->id != SASL_CB_LIST_END; interact++) { + switch(interact->id) { + case SASL_CB_USER: + interact->result = ""; + interact->len = strlen(interact->result); + ret = LDAP_SUCCESS; + break; + case SASL_CB_GETREALM: + interact->result = ""; + interact->len = strlen(interact->result); + ret = LDAP_SUCCESS; + break; + default: + radlog(L_ERR, "rlm_ldap: Unhandled SASL int. option %ld", interact->id); + interact->result = NULL; + interact->len = 0; + ret = LDAP_OTHER; + } + } + return ret; +} + +#endif + static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char); static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **); static int ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING); static LDAP *ldap_connect(void *instance, const char *, const char *, int, int *, char **); static int read_mappings(ldap_instance* inst); +static int generate_ldap_clients(ldap_instance* inst); static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance) { @@ -662,6 +916,15 @@ DEBUG("conns: %p",inst->conns); +#ifdef USE_KRB5 + if (krb_session_init(inst, &inst->krb)) { + radlog(L_ERR, "rlm_ldap: Failed to init kerberos session"); + } +#endif + if (generate_ldap_clients(inst)) { + radlog(L_ERR, "rlm_ldap: Failed to read client list from ldap"); + } + *instance = inst; @@ -770,7 +1033,7 @@ static int perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter, - char **attrs, LDAPMessage ** result) + char **attrs, int single, LDAPMessage ** result) { int res = RLM_MODULE_OK; int ldap_errno = 0; @@ -854,11 +1117,13 @@ return (RLM_MODULE_FAIL); } - if ((ldap_count_entries(conn->ld, *result)) != 1) { + + if (single && (ldap_count_entries(conn->ld, *result)) != 1) { DEBUG("rlm_ldap: object not found or got ambiguous search result"); res = RLM_MODULE_NOTFOUND; ldap_msgfree(*result); } + return res; } @@ -914,6 +1179,156 @@ } /* + * generate_ldap_clients(). read clients from ldap, append to client list + */ + +static int generate_ldap_clients(ldap_instance* inst) +{ + LDAP_CONN *conn; + int conn_id = -1; + int res; + LDAPMessage *result, *entry; + int client_idx; + + if (!inst->clients_basedn) { + DEBUG("rlm_ldap: generate_ldap_clients, client basedn not set, skipping..."); + return 0; + } + DEBUG("rlm_ldap: generate_ldap_clients, client_basedn=%s", inst->clients_basedn); + + + if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ + radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + return 1; + } + if ((res = perform_search(inst, conn, inst->clients_basedn, LDAP_SCOPE_SUBTREE, + inst->clients_filter, NULL, FALSE, &result)) != RLM_MODULE_OK){ + DEBUG("rlm_ldap::generate_ldap_clients: search failed"); + ldap_release_conn(conn_id,inst->conns); + return 1; + } + + for (entry = ldap_first_entry(conn->ld, result), client_idx = 0; + entry != NULL; + entry = ldap_next_entry(conn->ld, entry), client_idx++) { + char *val, **vals; + RADCLIENT client, *p_client; + char *netmask; + char ip_buf[64]; + + memset(&client, 0, sizeof(client)); + + if ((vals = ldap_get_values(conn->ld, entry, "radiusClientNASIpAddress")) != NULL) { + val = vals[0]; + if (strlen(val) >= sizeof(client.longname)) { + radlog(L_ERR, "rlm_ldap, retrieving clients: address (%s) length %d exceeds %d maximum", + val, strlen(val), sizeof(client.longname)-1); + ldap_value_free(vals); + continue; + } else { + strcpy(client.longname, val); + ldap_value_free(vals); + } + } + + + if ((vals = ldap_get_values(conn->ld, entry, "radiusClientSecret")) != NULL) { + val = vals[0]; + if (strlen(val) >= sizeof(client.secret)) { + radlog(L_ERR, "rlm_ldap, retrieving clients: secret length %d exceeds %d maximum", + strlen(val), sizeof(client.secret)-1); + ldap_value_free(vals); + continue; + } else { + strcpy(client.secret, val); + ldap_value_free(vals); + } + } + + + if ((vals = ldap_get_values(conn->ld, entry, "radiusClientNASType")) != NULL) { + val = vals[0]; + if (strlen(val) >= sizeof(client.nastype)) { + radlog(L_ERR, "rlm_ldap, retrieving clients:NAS Type (%s) length %d exceeds %d maximum", + val, strlen(val), sizeof(client.nastype)-1); + ldap_value_free(vals); + continue; + } else { + strcpy(client.nastype, val); + ldap_value_free(vals); + } + } + + + if ((vals = ldap_get_values(conn->ld, entry, "radiusClientShortName")) != NULL) { + val = vals[0]; + if (strlen(val) >= sizeof(client.shortname)) { + radlog(L_ERR, "rlm_ldap, retrieving clients: address (%s) length %d exceeds %d maximum", + val, strlen(val), sizeof(client.shortname)-1); + ldap_value_free(vals); + continue; + } else { + strcpy(client.shortname, val); + ldap_value_free(vals); + } + } + + + /* Look for a mask in the hostname */ + netmask = strchr(client.longname, '/'); + client.netmask = ~0; + if (netmask) { + int mask_length; + + *netmask = '\0'; + netmask++; + + mask_length = atoi(netmask); + if ((mask_length < 0) || (mask_length > 32)) { + radlog(L_ERR, "rlm_ldap: Invalid value '%s' for IP network mask.for %s", netmask, client.longname); + continue; + } + + if (mask_length == 0) { + client.netmask = 0; + } else { + client.netmask = ~0 << (32 - mask_length); + } + } + + client.ipaddr = ip_getaddr(client.longname); + if (client.ipaddr == INADDR_NONE) { + radlog(L_ERR, "rlm_ldap: Failed to look up hostname %s", client.longname); + continue; + } + client.netmask = htonl(client.netmask); + client.ipaddr &= client.netmask; /* addr & mask are in network order */ + if (netmask) *netmask = '/'; + + + DEBUG("rlm_ldap: client[%2d] client=%s ip=%s mask=0x%x shortname=%s nastype=%s", + client_idx, client.longname, ip_ntoa(ip_buf, client.ipaddr), client.netmask, client.shortname, client.nastype); + + + if ((p_client = rad_malloc(sizeof(RADCLIENT))) == NULL) { + radlog(L_ERR, "rlm_ldap: Out of memory!"); + ldap_msgfree(result); + ldap_release_conn(conn_id,inst->conns); + return 1; + } + memcpy(p_client, &client, sizeof(client)); + p_client->next = mainconfig.clients; + mainconfig.clients = p_client; + + } + + ldap_msgfree(result); + ldap_release_conn(conn_id,inst->conns); + // client_walk(); /* uncomment for debugging */ + return 0; +} + +/* * ldap_groupcmp(). Implement the Ldap-Group == "group" filter */ @@ -967,7 +1382,7 @@ return 1; } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, - filter, attrs, &result)) != RLM_MODULE_OK){ + filter, attrs, TRUE, &result)) != RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: search failed"); ldap_release_conn(conn_id,inst->conns); return 1; @@ -1012,7 +1427,7 @@ } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, - filter, attrs, &result)) == RLM_MODULE_OK){ + filter, attrs, TRUE, &result)) == RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s", (char *)check->strvalue); ldap_msgfree(result); @@ -1042,7 +1457,7 @@ return 1; } if ((res = perform_search(inst, conn, (char *)vp_user_dn->strvalue, LDAP_SCOPE_BASE, - filter, group_attrs,&result)) != RLM_MODULE_OK){ + filter, group_attrs, TRUE, &result)) != RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); ldap_release_conn(conn_id, inst->conns); return 1; @@ -1066,7 +1481,7 @@ (char *)check->strvalue); if ((res = perform_search(inst, conn, vals[i], LDAP_SCOPE_BASE, filter, - attrs, &gr_result)) != RLM_MODULE_OK){ + attrs, TRUE, &gr_result)) != RLM_MODULE_OK){ if (res != RLM_MODULE_NOTFOUND){ DEBUG("rlm_ldap::ldap_groupcmp: \ Search returned error"); @@ -1161,7 +1576,7 @@ ldap_free_urldesc(ldap_url); return 0; } - if ((res = perform_search(inst, conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, &result)) != RLM_MODULE_OK){ + if ((res = perform_search(inst, conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, TRUE, &result)) != RLM_MODULE_OK){ if (res == RLM_MODULE_NOTFOUND){ DEBUG("rlm_ldap: Search returned not found"); ldap_free_urldesc(ldap_url); @@ -1275,7 +1690,7 @@ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return RLM_MODULE_FAIL; } - if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) { + if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, TRUE, &result)) != RLM_MODULE_OK) { DEBUG("rlm_ldap: search failed"); if (res == RLM_MODULE_NOTFOUND){ snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found"); @@ -1360,7 +1775,7 @@ if (profile && strlen(profile)){ if ((res = perform_search(instance, conn, profile, LDAP_SCOPE_BASE, - filter, inst->atts, &def_result)) == RLM_MODULE_OK){ + filter, inst->atts, TRUE, &def_result)) == RLM_MODULE_OK){ if ((def_msg = ldap_first_entry(conn->ld,def_result))){ if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) { if (inst->do_xlat){ @@ -1399,7 +1814,7 @@ while(vals[i] != NULL && strlen(vals[i])){ if ((res = perform_search(instance, conn, vals[i], LDAP_SCOPE_BASE, - filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){ + filter, inst->atts, TRUE, &def_attr_result)) == RLM_MODULE_OK){ if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){ if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) { if (inst->do_xlat){ @@ -1778,7 +2193,7 @@ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return RLM_MODULE_FAIL; } - if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) { + if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, TRUE, &result)) != RLM_MODULE_OK) { if (res == RLM_MODULE_NOTFOUND){ snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); @@ -2167,6 +2582,12 @@ ldap_version = LDAP_VERSION3; if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) { radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3"); +#ifdef USE_SASL2 + if (inst->use_sasl) { + radlog(L_ERR, "rlm_ldap: sasl was enabled, but sasl requires LDAP V3, disabling sasl"); + inst->use_sasl = FALSE; + } +#endif } #ifdef HAVE_LDAP_START_TLS if(inst->tls_mode) { @@ -2208,7 +2629,7 @@ #ifdef HAVE_LDAP_INT_TLS_CONFIG - if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, + if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, (inst->tls_require_cert) ) != LDAP_OPT_SUCCESS) { radlog(L_ERR, "rlm_ldap: could not set " @@ -2273,6 +2694,25 @@ else{ DEBUG("rlm_ldap: bind as %s/%s to %s:%d", dn, password, inst->server, inst->port); } +#ifdef USE_SASL2 + if (inst->use_sasl) { + DEBUG("rlm_ldap: performing sasl bind"); +#ifdef USE_KRB5 + if (krb_session_get_ticket(&inst->krb)) { + radlog(L_ERR, "rlm_ldap: could not get kerberos ticket"); + } +#endif + ldap_errno = ldap_sasl_interactive_bind_s(ld, /* ldap connection */ + NULL, /* dn */ + "GSSAPI", /* mechanism */ + NULL, /* server controls */ + NULL, /* client controls */ + LDAP_SASL_QUIET, /* flags */ + ldap_sasl_interact, /* callback function */ + NULL); /* defaults */ + } else { +#endif + DEBUG("rlm_ldap: performing simple bind"); msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE); if (msgid == -1) { ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); @@ -2314,6 +2754,9 @@ return (NULL); } ldap_errno = ldap_result2error(ld, res, 1); +#ifdef USE_SASL2 + } +#endif switch (ldap_errno) { case LDAP_SUCCESS: DEBUG("rlm_ldap: Bind was successful"); @@ -2406,6 +2849,18 @@ free(inst->conns); } +#ifdef USE_SASL2 + if (inst->sasl_mech) + free((char *)inst->sasl_mech); +#endif +#ifdef USE_KRB5 + if (inst->krb_keytab) + free((char *)inst->krb_keytab); + if (inst->krb_principal) + free((char *)inst->krb_principal); + krb_session_free(&inst->krb); +#endif + #ifdef NOVELL if (inst->apc_conns){ int i;