Add Novell patch for reading the user's Universal Password from LDAP (eDirectory).
authorkkalev <kkalev>
Sun, 2 Jan 2005 13:36:33 +0000 (13:36 +0000)
committerkkalev <kkalev>
Sun, 2 Jan 2005 13:36:33 +0000 (13:36 +0000)
raddb/radiusd.conf.in
src/modules/rlm_ldap/Makefile.in
src/modules/rlm_ldap/configure.in
src/modules/rlm_ldap/edir_ldapext.c [new file with mode: 0644]
src/modules/rlm_ldap/rlm_ldap.c

index 300b0d1..5c97c9f 100644 (file)
@@ -798,6 +798,10 @@ $INCLUDE ${confdir}/eap.conf
                #  Without the leading "0x", NT-Passwords will not work.
                #  This goes for NT-Passwords stored in SQL, too.
                #
+               # Set password_attribute = nspmPassword to get user's password
+               # from a Novell eDirectory backend. This will work *only if*
+               # freeRADIUS is configured to build with --with-edir option.
+               #                                                                               
                # password_attribute = userPassword
                # groupname_attribute = cn
                # groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"
index 04bfa68..5a0b98c 100644 (file)
@@ -1,5 +1,5 @@
 TARGET     = @targetname@
-SRCS       = rlm_ldap.c
+SRCS       = rlm_ldap.c @edir@
 HEADERS    =
 RLM_CFLAGS = @ldap_cflags@
 RLM_LIBS   = @ldap_ldflags@
index c0a7d20..5e1d15f 100644 (file)
@@ -123,8 +123,24 @@ if test x"$fail" != x""; then
        fi
 fi
 
+dnl extra argument: --with-edir
+dnl If using Novell eDirectory, enable UP and Novell specific code
+WITH_EDIRECTORY=no
+AC_ARG_WITH(edir,
+[  --with-edir           Enable Novell eDirectory integration.  (default=no) ],
+[ case "$withval" in
+    yes)
+       SMART_CFLAGS="$SMART_CFLAGS -DNOVELL_UNIVERSAL_PASSWORD "
+       edir="edir_ldapext.c"
+        ;;
+    *)
+        ;;
+  esac ]
+)
+
 ldap_ldflags=$SMART_LIBS
 ldap_cflags=$SMART_CFLAGS
+AC_SUBST(edir)
 AC_SUBST(ldap_ldflags)
 AC_SUBST(ldap_cflags)
 AC_SUBST(targetname)
diff --git a/src/modules/rlm_ldap/edir_ldapext.c b/src/modules/rlm_ldap/edir_ldapext.c
new file mode 100644 (file)
index 0000000..6dd4b72
--- /dev/null
@@ -0,0 +1,361 @@
+/* 
+ * Copyright (C) 2002-2004 Novell, Inc.
+ *
+ * edir_ldapext.c  LDAP extension for reading eDirectory universal password
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * 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, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact  information at www.novell.com.
+ */ 
+
+#include <ldap.h>
+#include <stdio.h>
+/* NMAS error codes */
+#define NMAS_E_BASE                       (-1600)
+
+#define NMAS_SUCCESS                      0
+#define NMAS_E_SUCCESS                    NMAS_SUCCESS         /* Alias  */
+#define NMAS_OK                           NMAS_SUCCESS         /* Alias  */
+
+#define NMAS_E_FRAG_FAILURE               (NMAS_E_BASE-31)     /* -1631 0xFFFFF9A1 */
+#define NMAS_E_BUFFER_OVERFLOW            (NMAS_E_BASE-33)     /* -1633 0xFFFFF99F */
+#define NMAS_E_SYSTEM_RESOURCES           (NMAS_E_BASE-34)     /* -1634 0xFFFFF99E */
+#define NMAS_E_INSUFFICIENT_MEMORY        (NMAS_E_BASE-35)     /* -1635 0xFFFFF99D */
+#define NMAS_E_NOT_SUPPORTED              (NMAS_E_BASE-36)     /* -1636 0xFFFFF99C */
+#define NMAS_E_INVALID_PARAMETER          (NMAS_E_BASE-43)     /* -1643 0xFFFFF995 */
+#define NMAS_E_INVALID_VERSION            (NMAS_E_BASE-52)     /* -1652 0xFFFFF98C */
+
+/* OID of LDAP extenstion calls to read Universal Password */
+#define NMASLDAP_GET_PASSWORD_REQUEST         "2.16.840.1.113719.1.39.42.100.13"
+#define NMASLDAP_GET_PASSWORD_RESPONSE        "2.16.840.1.113719.1.39.42.100.14"
+
+#define NMAS_LDAP_EXT_VERSION 1
+
+
+
+/* ------------------------------------------------------------------------
+ *     berEncodePasswordData
+ *     ==============================
+ *     RequestBer contents:
+ *             clientVersion                           INTEGER
+ *             targetObjectDN                          OCTET STRING
+ *             password1                                       OCTET STRING
+ *             password2                                       OCTET STRING
+ *
+ *     Description:
+ *             This function takes the request BER value and input data items
+ *             and BER encodes the data into the BER value
+ *
+ * ------------------------------------------------------------------------ */
+int berEncodePasswordData(
+       struct berval **requestBV,
+       char    *objectDN,
+       char    *password,
+       char    *password2)
+{
+       int err = 0, rc=0;
+       BerElement *requestBer = NULL;
+
+       char    * utf8ObjPtr = NULL;
+       int     utf8ObjSize = 0;
+       char    * utf8PwdPtr = NULL;
+       int     utf8PwdSize = 0;
+       char    * utf8Pwd2Ptr = NULL;
+       int     utf8Pwd2Size = 0;
+
+
+       utf8ObjSize = strlen(objectDN)+1;
+       utf8ObjPtr = objectDN;
+
+       if (password != NULL)
+       {
+               utf8PwdSize = strlen(password)+1;
+               utf8PwdPtr = password;
+       }
+
+       if (password2 != NULL)
+       {
+               utf8Pwd2Size = strlen(password2)+1;
+               utf8Pwd2Ptr = password2;
+       }
+
+       /* Allocate a BerElement for the request parameters.*/
+       if((requestBer = ber_alloc()) == NULL)
+       {
+               err = NMAS_E_FRAG_FAILURE;
+               goto Cleanup;
+       }
+
+       if (password != NULL && password2 != NULL)
+       {
+               /* BER encode the NMAS Version, the objectDN, and the password */
+               rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size);
+       }
+       else if (password != NULL)
+       {
+               /* BER encode the NMAS Version, the objectDN, and the password */
+               rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize);
+       }
+       else
+       {
+               /* BER encode the NMAS Version and the objectDN */
+               rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
+       }
+
+       if (rc < 0)
+       {
+               err = NMAS_E_FRAG_FAILURE;
+               goto Cleanup;
+       }
+       else
+       {
+               err = 0;
+       }
+
+       /* 
+        * Convert the BER we just built to a berval that we'll send with the extended request. 
+        */
+       if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
+       {
+               err = NMAS_E_FRAG_FAILURE;
+               goto Cleanup;
+       }
+
+Cleanup:
+
+       if(requestBer)
+       {
+               ber_free(requestBer, 1);
+       }
+
+       return err;
+} /* End of berEncodePasswordData */
+
+/* ------------------------------------------------------------------------
+ *     berDecodeLoginData()
+ *     ==============================
+ *     ResponseBer contents:
+ *             serverVersion                           INTEGER
+ *             error                                   INTEGER
+ *             data                                            OCTET STRING
+ *
+ *     Description:
+ *             This function takes the reply BER Value and decodes the
+ *             NMAS server version and return code and if a non null retData
+ *             buffer was supplied, tries to decode the the return data and length
+ *
+ * ------------------------------------------------------------------------ */
+int berDecodeLoginData(
+       struct berval *replyBV,
+       int      *serverVersion,
+       size_t   *retDataLen,
+       void     *retData )
+{
+       int rc=0, err = 0;
+       BerElement *replyBer = NULL;
+       char    *retOctStr = NULL;
+       size_t  retOctStrLen = 0;
+
+       if((replyBer = ber_init(replyBV)) == NULL)
+       {
+               err = NMAS_E_SYSTEM_RESOURCES;
+               goto Cleanup;
+       }
+
+       if(retData)
+       {
+               retOctStrLen = *retDataLen + 1;
+               retOctStr = (char *)malloc(retOctStrLen);
+               if(!retOctStr)
+               {
+                       err = NMAS_E_SYSTEM_RESOURCES;
+                       goto Cleanup;
+               }
+
+               if( (rc = ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen)) != -1)
+               {
+                       if (*retDataLen >= retOctStrLen)
+                       {
+                               memcpy(retData, retOctStr, retOctStrLen);
+                       }
+                       else if (!err)
+                       {       
+                               err = NMAS_E_BUFFER_OVERFLOW;
+                       }
+
+                       *retDataLen = retOctStrLen;
+               }
+               else if (!err)
+               {
+                       err = NMAS_E_FRAG_FAILURE;
+               }
+       }
+       else
+       {
+               if( (rc = ber_scanf(replyBer, "{ii}", serverVersion, &err)) == -1)
+               {
+                       if (!err)
+                       {
+                               err = NMAS_E_FRAG_FAILURE;
+                       }
+               }
+       }
+
+Cleanup:
+
+       if(replyBer)
+       {
+               ber_free(replyBer, 1);
+       }
+
+       if (retOctStr != NULL)
+       {
+               memset(retOctStr, 0, retOctStrLen);
+               free(retOctStr);
+       }
+
+       return err;
+} /* End of berDecodeLoginData */
+
+/* -----------------------------------------------------------------------
+ *     nmasldap_get_password()
+ *     ==============================
+ *
+ *     Description:
+ *             This API attempts to get the universal password
+ *
+ * ------------------------------------------------------------------------ */
+int nmasldap_get_password(
+       LDAP     *ld,
+       char     *objectDN,
+       size_t   *pwdSize,      // in bytes
+       char     *pwd )
+{
+       int err = 0;
+
+       struct berval *requestBV = NULL;
+       char *replyOID = NULL;
+       struct berval *replyBV = NULL;
+       int serverVersion;
+       char *pwdBuf;
+       size_t pwdBufLen, bufferLen;
+
+#ifdef NOT_N_PLAT_NLM
+       int currentThreadGroupID;
+#endif
+
+       /* Validate char    parameters. */
+       if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
+       {
+               return NMAS_E_INVALID_PARAMETER;
+       }
+
+       bufferLen = pwdBufLen = *pwdSize;
+       pwdBuf = (char *)malloc(pwdBufLen+2);
+       if(pwdBuf == NULL)
+       {
+               return NMAS_E_INSUFFICIENT_MEMORY;
+       }
+
+#ifdef NOT_N_PLAT_NLM
+       currentThreadGroupID = SetThreadGroupID(nmasLDAPThreadGroupID);
+#endif
+
+       err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
+       if(err)
+       {
+               goto Cleanup;
+       }
+
+       /* Call the ldap_extended_operation (synchronously) */
+       if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
+       {
+               goto Cleanup;
+       }
+
+       /* Make sure there is a return OID */
+       if(!replyOID)
+       {
+               err = NMAS_E_NOT_SUPPORTED;
+               goto Cleanup;
+       }
+
+       /* Is this what we were expecting to get back. */
+       if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
+       {
+               err = NMAS_E_NOT_SUPPORTED;
+               goto Cleanup;
+       }
+
+       /* Do we have a good returned berval? */
+       if(!replyBV)
+       {
+               /* 
+                * No; returned berval means we experienced a rather drastic error.
+                * Return operations error.
+                */
+               err = NMAS_E_SYSTEM_RESOURCES;
+               goto Cleanup;
+       }
+
+       err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
+
+       if(serverVersion != NMAS_LDAP_EXT_VERSION)
+       {
+               err = NMAS_E_INVALID_VERSION;
+               goto Cleanup;
+       }
+
+       if (!err && pwdBufLen != 0)
+       {
+               if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
+               {
+                       memcpy(pwd, pwdBuf, pwdBufLen);
+                       pwd[pwdBufLen] = 0; /* add null termination */
+               }
+               *pwdSize = pwdBufLen; /* does not include null termination */
+       }
+
+Cleanup:
+
+       if(replyBV)
+       {
+               ber_bvfree(replyBV);
+       }
+
+       /* Free the return OID string if one was returned. */
+       if(replyOID)
+       {
+               ldap_memfree(replyOID);
+       }
+
+       /* Free memory allocated while building the request ber and berval. */
+       if(requestBV)
+       {
+               ber_bvfree(requestBV);
+       }
+
+       if (pwdBuf != NULL)
+       {
+               memset(pwdBuf, 0, bufferLen);
+               free(pwdBuf);
+       }
+
+#ifdef NOT_N_PLAT_NLM
+       SetThreadGroupID(currentThreadGroupID);
+#endif
+
+       /* Return the appropriate error/success code. */
+       return err;
+} /* end of nmasldap_get_password */
index 4395c6c..fbe2668 100644 (file)
@@ -91,6 +91,18 @@ static const char rcsid[] = "$Id$";
 #define MAX_FAILED_CONNS_RESTART       4
 #define MAX_FAILED_CONNS_START         5
 
+#ifdef NOVELL_UNIVERSAL_PASSWORD
+
+/* Universal Password Length */
+#define UNIVERSAL_PASS_LEN 256
+
+int nmasldap_get_password(
+       LDAP     *ld,
+       char     *objectDN,
+       size_t   *pwdSize,      // in bytes
+       char     *pwd );
+
+#endif
 /* linked list of mappings between RADIUS attributes and LDAP attributes */
 struct TLDAP_RADIUS {
        char*                 attr;
@@ -1205,6 +1217,9 @@ ldap_authorize(void *instance, REQUEST * request)
                }
        }
        if (inst->passwd_attr && strlen(inst->passwd_attr)){
+#ifdef NOVELL_UNIVERSAL_PASSWORD
+               if(strcasecmp(inst->passwd_attr,"nspmPassword")!= 0){
+#endif
                VALUE_PAIR *passwd_item;
 
                if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
@@ -1245,6 +1260,67 @@ ldap_authorize(void *instance, REQUEST * request)
                                ldap_value_free(passwd_vals);
                        }
                }
+#ifdef NOVELL_UNIVERSAL_PASSWORD
+               }
+               else{
+               /*
+               * Read Universal Password from eDirectory
+               */
+                       VALUE_PAIR      *passwd_item;
+                       VALUE_PAIR      *vp_user_dn;
+                       int             passwd_len;
+                       char            *universal_password = NULL;
+                       int             universal_password_len = UNIVERSAL_PASS_LEN;
+                       char            *passwd_val = NULL;
+
+                       res = 0;
+
+                       if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
+                       
+                               universal_password = rad_malloc(universal_password_len);
+                               memset(universal_password, 0, universal_password_len);
+
+                               vp_user_dn = pairfind(request->config_items,PW_LDAP_USERDN);
+                               res = nmasldap_get_password(conn->ld,vp_user_dn->strvalue,&universal_password_len,universal_password);
+
+                               if (res == 0){
+                                       passwd_val = universal_password;
+
+                                       if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
+                                               passwd_val = strstr(passwd_val,inst->passwd_hdr);
+
+                                               if (passwd_val != NULL)
+                                                       passwd_val += strlen((char*)inst->passwd_hdr);
+                                               else
+                                                       DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->strvalue);
+                                       }
+
+                                       if (passwd_val){
+                                               if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
+                                                       radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
+                                                       ldap_msgfree(result);
+                                                       ldap_release_conn(conn_id,inst->conns);
+                                                       memset(universal_password, 0, universal_password_len);
+                                                       free(universal_password);
+                                                       return RLM_MODULE_FAIL;
+                                               }
+
+                                               passwd_len = strlen(passwd_val);
+                                               strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
+                                               passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
+                                               pairadd(&request->config_items,passwd_item);
+                                               DEBUG("rlm_ldap: Added the eDirectory password in check items");
+                                       }
+                               }
+                               else {
+                                       DEBUG("rlm_ldap: Error reading Universal Password.Return Code = %d",res);
+                               }
+
+                               memset(universal_password, 0, universal_password_len);
+                               free(universal_password);
+                       }
+               }                       
+#endif
        }