[svn-commits] oej: branch oej/res_auth r45739 - in /team/oej/res_auth: ./ build_tools/ chan...

svn-commits at lists.digium.com svn-commits at lists.digium.com
Fri Oct 20 00:03:35 MST 2006


Author: oej
Date: Fri Oct 20 02:03:34 2006
New Revision: 45739

URL: http://svn.digium.com/view/asterisk?rev=45739&view=rev
Log:
Update from Philippe Sultan, INRIA (issue #5424)

Modified:
    team/oej/res_auth/build_tools/menuselect-deps.in
    team/oej/res_auth/channels/chan_sip.c
    team/oej/res_auth/configure.ac
    team/oej/res_auth/include/asterisk/auth.h
    team/oej/res_auth/makeopts.in
    team/oej/res_auth/res/res_auth.c

Modified: team/oej/res_auth/build_tools/menuselect-deps.in
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/build_tools/menuselect-deps.in?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/build_tools/menuselect-deps.in (original)
+++ team/oej/res_auth/build_tools/menuselect-deps.in Fri Oct 20 02:03:34 2006
@@ -13,6 +13,7 @@
 NETSNMP=@PBX_NETSNMP@
 NEWT=@PBX_NEWT@
 OGG=@PBX_OGG@
+OPENLDAP=@PBX_OPENLDAP@
 OSPTK=@PBX_OSPTK@
 OSSAUDIO=@PBX_OSS@
 PGSQL=@PBX_PGSQL@

Modified: team/oej/res_auth/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/channels/chan_sip.c?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/channels/chan_sip.c (original)
+++ team/oej/res_auth/channels/chan_sip.c Fri Oct 20 02:03:34 2006
@@ -7827,6 +7827,8 @@
 	int  wrongnonce = FALSE;
 	int  good_response;
 	const char *usednonce = p->randdata;
+	char pwd[256];                       /* used by res_auth */
+	struct ast_flags res = {0};          /* used by res_auth */
 
 	/* table of recognised keywords, and their value in the digest */
 	enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST };
@@ -7914,108 +7916,94 @@
 		return AUTH_USERNAME_MISMATCH;
 	}
 
-<<<<<<< .working
+	res.flags = ast_parse_secret(username, secret, pwd);
+		
+	/* password has been retrieved from config file, or from
+	   an external source. Let's now process it */
+	if (ast_test_flag(&res, PW_SET)) {
 		char a1[256];
-		char pwd[256];
-		struct ast_flags res = {0};
 		
-		res.flags = ast_parse_secret(username, secret, pwd);
+		if (ast_test_flag(&res, PW_FILE)) {
+			ast_log(LOG_DEBUG, "Doing LOCAL authentication for user '%s'\n", username);
+		}
+		else if (ast_test_flag(&res, PW_LDAP)) {
+			ast_log(LOG_DEBUG, "LDAP password retrieved for user '%s'\n", username);
+			ast_log(LOG_DEBUG, "LDAP password : '%s'\n", pwd);
+		}							
+		snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, pwd);
+		ast_md5_hash(a1_hash, a1);
 		
-		/* password has been retrieved from config file, or from
-		   an external source. Let's now process it */
-		if (ast_test_flag(&res, PW_SET)) {
-
-			if (ast_test_flag(&res, PW_CLEAR)) {
-				ast_log(LOG_NOTICE, "Doing LOCAL (clear pw) authentication for user '%s'\n", username);
-							
-				snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, pwd);
-				ast_md5_hash(a1_hash, a1);
-				
-			}
-			else if (ast_test_flag(&res, PW_MD5)) {
-				ast_log(LOG_NOTICE, "Doing LOCAL (HA1 pw) authentication for user '%s'\n", username);
-				ast_copy_string(a1_hash, pwd, sizeof(a1_hash));				
-			}
-		}
-		/* no password retrieved, let's try to directly authenticate
-		   the user */
-
-		/* With RADIUS SIP DIGEST authentication 
-		   (draft-sterman-aaa-sip-00.txt etc) */
-		else if (ast_test_flag(&res, AUTH_RADIUS)) {
-			int retval;
-			const char* user = username;
-			struct digest_parameters params;
-			digest_attr_t aux;
-
-			ast_log(LOG_NOTICE, "Doing RADIUS authentication for user '%s'\n", username);						
-
-			memset(&params, 0, sizeof(params));
-			
-			/* Build up the params structure with the attributes we got after having parsed the URI */        
-			params.num_attrs = 0;
-			ast_copy_string(params.digest_response, keys[K_RESP].s, sizeof(params.digest_response));
-			
-
-			/* realm attribute */
-			aux.type = PW_DIGEST_REALM;
-			aux.length = strlen(global_realm);
-			ast_copy_string(aux.value, global_realm, sizeof(aux.value));
-			push_digest_attribute(&params, &aux);
-			
-			/* nonce attribute */
-			aux.type = PW_DIGEST_NONCE;
-			aux.length = strlen(keys[K_NONCE].s);
-			ast_copy_string(aux.value, keys[K_NONCE].s, sizeof(aux.value));
-			push_digest_attribute(&params, &aux);
-			
-			/* method attribute */
-			aux.type = PW_DIGEST_METHOD;
-			aux.length = strlen(sip_methods[sipmethod].text);
-			ast_copy_string(aux.value, sip_methods[sipmethod].text, sizeof(aux.value));
-			push_digest_attribute(&params, &aux);
-			
-			/* uri attribute */
-			aux.type = PW_DIGEST_URI;
-			aux.length = strlen(keys[K_URI].s);
-			ast_copy_string(aux.value, keys[K_URI].s, sizeof(aux.value));
-			push_digest_attribute(&params, &aux);
-
-			/* algo attribute */
-			aux.type = PW_DIGEST_ALGORITHM;
-			aux.length = strlen("MD5");
-			ast_copy_string(aux.value, "MD5", sizeof("MD5"));
-			push_digest_attribute(&params, &aux);
-			
-			/* Username attribute */
-			aux.type = PW_DIGEST_USER_NAME; 
-			aux.length = strlen(keys[K_USER].s);
-			ast_copy_string(aux.value, keys[K_USER].s, sizeof(aux.value));
-			push_digest_attribute(&params, &aux);
-			
-			retval = ast_digest_authenticate(user, &params);			
-			return retval;
-			
-		}
-
-		/* overwrite with md5secret for backward compatibility */
-		if (!ast_strlen_zero(md5secret)) {
-			ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
-		}
-=======
+	}
+	/* no password retrieved, let's try to directly authenticate
+	   the user */
+	
+	/* With RADIUS SIP DIGEST authentication 
+	   (draft-sterman-aaa-sip-00.txt etc) */
+	else if (ast_test_flag(&res, AUTH_RADIUS)) {
+		int retval;
+		const char* user = username;
+		struct digest_parameters params;
+		digest_attr_t aux;
+		
+		ast_log(LOG_NOTICE, "Doing RADIUS authentication for user '%s'\n", username);						
+		
+		memset(&params, 0, sizeof(params));
+		
+		/* Build up the params structure with the attributes we got after having parsed the URI */        
+		params.num_attrs = 0;
+		ast_copy_string(params.digest_response, keys[K_RESP].s, sizeof(params.digest_response));
+		
+		
+		/* realm attribute */
+		aux.type = PW_DIGEST_REALM;
+		aux.length = strlen(global_realm);
+		ast_copy_string(aux.value, global_realm, sizeof(aux.value));
+		ast_push_digest_attribute(&params, &aux);
+		
+		/* nonce attribute */
+		aux.type = PW_DIGEST_NONCE;
+		aux.length = strlen(keys[K_NONCE].s);
+		ast_copy_string(aux.value, keys[K_NONCE].s, sizeof(aux.value));
+		ast_push_digest_attribute(&params, &aux);
+		
+		/* method attribute */
+		aux.type = PW_DIGEST_METHOD;
+		aux.length = strlen(sip_methods[sipmethod].text);
+		ast_copy_string(aux.value, sip_methods[sipmethod].text, sizeof(aux.value));
+		ast_push_digest_attribute(&params, &aux);
+		
+		/* uri attribute */
+		aux.type = PW_DIGEST_URI;
+		aux.length = strlen(keys[K_URI].s);
+		ast_copy_string(aux.value, keys[K_URI].s, sizeof(aux.value));
+		ast_push_digest_attribute(&params, &aux);
+		
+		/* algo attribute */
+		aux.type = PW_DIGEST_ALGORITHM;
+		aux.length = strlen("MD5");
+		ast_copy_string(aux.value, "MD5", sizeof("MD5"));
+		ast_push_digest_attribute(&params, &aux);
+		
+		/* Username attribute */
+		aux.type = PW_DIGEST_USER_NAME; 
+		aux.length = strlen(keys[K_USER].s);
+		ast_copy_string(aux.value, keys[K_USER].s, sizeof(aux.value));
+		ast_push_digest_attribute(&params, &aux);
+		
+		retval = ast_digest_authenticate(user, &params);			
+		return retval;
+		
+	}
+	
+	/* overwrite with md5secret for backward compatibility */
+	if (!ast_strlen_zero(md5secret)) {
+		ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
+	}
+
 	/* Verify nonce from request matches our nonce.  If not, send 401 with new nonce */
 	if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
 		wrongnonce = TRUE;
 		usednonce = keys[K_NONCE].s;
-	}
->>>>>>> .merge-right.r45185
-
-	if (!ast_strlen_zero(md5secret))
-		ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
-	else {
-		char a1[256];
-		snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
-		ast_md5_hash(a1_hash, a1);
 	}
 
 	/* compute the expected response to compare with what we received */

Modified: team/oej/res_auth/configure.ac
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/configure.ac?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/configure.ac (original)
+++ team/oej/res_auth/configure.ac Fri Oct 20 02:03:34 2006
@@ -176,6 +176,7 @@
 AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
 AST_EXT_LIB_SETUP([UNIXODBC], [unixODBC], [odbc])
 AST_EXT_LIB_SETUP([OGG], [OGG], [ogg])
+AST_EXT_LIB_SETUP([OPENLDAP], [OpenLDAP], [openldap])
 AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk])
 AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss])
 AST_EXT_LIB_SETUP([POPT], [popt], [popt])
@@ -745,6 +746,8 @@
 
 AST_EXT_LIB_CHECK([OPENSSL], [ssl], [ssl2_connect], [openssl/ssl.h], [-lcrypto])
 
+AST_EXT_LIB_CHECK([OPENLDAP], [ldap], [ldap_first_attribute], [ldap.h])
+
 AST_EXT_LIB_CHECK([FREETDS], [tds], [tds_version], [tds.h])
 if test "${PBX_FREETDS}" != "0";
 then

Modified: team/oej/res_auth/include/asterisk/auth.h
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/include/asterisk/auth.h?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/include/asterisk/auth.h (original)
+++ team/oej/res_auth/include/asterisk/auth.h Fri Oct 20 02:03:34 2006
@@ -20,30 +20,26 @@
  * \brief User Authentication Module
  */
 
-#ifdef HAVE_RADIUS_CLIENT_H
+#define MAX_PW_LEN 128
+
+enum {
+	AUTH_ERR =      -1,
+	AUTH_LOCAL =    (1 << 0),
+	AUTH_LDAP =	(1 << 1),
+	AUTH_PAM =	(1 << 2),
+	AUTH_RADIUS =	(1 << 3)
+};
+
+enum {
+	PW_SET =        (1 << 4),
+	PW_FILE =       (1 << 5),
+	PW_LDAP =       (1 << 6)
+};
+
+int ast_parse_secret(const char*, const char *, char *);
+
+#ifdef HAVE_RADIUS
 #include <radiusclient-ng.h>
-
-#ifndef RC_CONFIG_FILE
-#define RC_CONFIG_FILE "/usr/local/etc/radiusclient-ng/radiusclient.conf"
-#endif
-
-#endif /* HAVE_RADIUS_CLIENT_H */
-
-
-/* define these attributes if we don't have the header file */
-#ifndef  HAVE_RADIUS_CLIENT_H
-#define	PW_DIGEST_REALM			1063	/* string */
-#define	PW_DIGEST_NONCE			1064	/* string */
-#define	PW_DIGEST_METHOD		1065	/* string */
-#define	PW_DIGEST_URI			1066	/* string */
-#define	PW_DIGEST_QOP			1067	/* string */
-#define	PW_DIGEST_ALGORITHM		1068	/* string */
-#define	PW_DIGEST_BODY_DIGEST		1069	/* string */
-#define	PW_DIGEST_CNONCE		1070	/* string */
-#define	PW_DIGEST_NONCE_COUNT		1071	/* string */
-#define	PW_DIGEST_USER_NAME		1072	/* string */
-#endif
-
 
 #define MAX_DIGEST_ATTRS 10		/* The maximum number of digest attributes in the RADIUS request we might send */
 
@@ -59,26 +55,9 @@
 	digest_attr_t d_attrs_list[MAX_DIGEST_ATTRS]; 
 };
 
- 
-
-#define AUTH_ERR        -1
-
-#define AUTH_LOCAL	(1 << 0)
-#define AUTH_LDAP	(1 << 1)
-#define AUTH_PAM	(1 << 2)
-#define AUTH_RADIUS	(1 << 3)
-
-#define PW_SET	        (1 << 4)
-#define PW_CLEAR	(1 << 5)
-#define PW_DIGEST_HA1	(1 << 6)
-#define PW_IAX_MD5	(1 << 7)
-#define PW_MD5          (1 << 8)
-
-int ast_parse_secret(const char*, const char *, char *);
-
-char* ast_get_auth(const char *);
-
-int push_digest_attribute(struct digest_parameters* , digest_attr_t*);
+int ast_push_digest_attribute(struct digest_parameters* , digest_attr_t*);
 
 int ast_digest_authenticate(const char*, struct digest_parameters *);
 
+#endif /* HAVE_RADIUS */
+

Modified: team/oej/res_auth/makeopts.in
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/makeopts.in?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/makeopts.in (original)
+++ team/oej/res_auth/makeopts.in Fri Oct 20 02:03:34 2006
@@ -99,6 +99,9 @@
 OGG_INCLUDE=@OGG_INCLUDE@
 OGG_LIB=@OGG_LIB@
 
+OPENLDAP_INCLUDE=@OPENLDAP_INCLUDE@
+OPENLDAP_LIB=@OPENLDAP_LIB@
+
 OSPTK_INCLUDE=@OSPTK_INCLUDE@
 OSPTK_LIB=@OSPTK_LIB@
 

Modified: team/oej/res_auth/res/res_auth.c
URL: http://svn.digium.com/view/asterisk/team/oej/res_auth/res/res_auth.c?rev=45739&r1=45738&r2=45739&view=diff
==============================================================================
--- team/oej/res_auth/res/res_auth.c (original)
+++ team/oej/res_auth/res/res_auth.c Fri Oct 20 02:03:34 2006
@@ -22,13 +22,20 @@
  *
  */
 
+/*** MODULEINFO
+	<use>openldap</use>
+	<use>radius</use>
+ ***/
+
+
+#include "asterisk.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 
-#include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
 
@@ -43,99 +50,168 @@
 #include "asterisk/utils.h"
 #include "asterisk/auth.h"
 
-static char *tdesc = "User Authentication Resource";
-
-#ifdef HAVE_RADIUS_CLIENT_H
+#define RES_AUTH_CONF "auth.conf"
+
+#ifdef HAVE_OPENLDAP
+#include <ldap.h>
+static LDAP *ldapConn = NULL;
+static char dbhost[512] = "";
+static char dbuser[512] = "";
+static char dbpass[50] = "";
+static char dbbasedn[512] = "";
+static int dbport = 389;
+static char username_attr[128] = "";
+static char userpw_attr [128] = "";
+static int get_ldap_password(const char *, char *);
+
+#endif /* HAVE_OPENLDAP */
+
+
+#ifdef HAVE_RADIUS
 AST_MUTEX_DEFINE_STATIC(rc_lock);
-
+#define RC_CONFIG_FILE "/usr/local/etc/radiusclient-ng/radiusclient.conf"
 static rc_handle *rh = NULL;
-#endif
+#endif /* HAVE_RADIUS */
 
 /*! \brief  Parses the secret configuration string for Asterisk resources 
   The user credentials format should be in the form : 
-  <auth>:[pw_form]:[password]
+  <auth_proxy>:[auth_db:[password]]
   
-  'auth' refers to the authentication protocol used to either 
-  effectively authenticate the user (ex : radius, pam), or to 
-  retrieve a password string from an external source (ex : ldap, sql).
-  In the latter case, the configuration info needed to connect to the
-  external source should be provided in config files.
-
-  'pw_form' : the password storage form : clear or md5 (or even RSA?).
-
-  'password' : the password string, or its MD5 hash, (or its location
-  if pw_form == rsa?)
+  'auth_proxy' indicates the actual location of the authentication process.
+  Asterisk may retrieve user passwords from an external database depending
+  on the value of 'auth_db', and then authenticate the users. Alternatively,
+  Asterisk can proxy the authentication to an external server such as RADIUS.
+  Values for this parameter are :
+  local: if the authenticaiton process runs on Asterisk
+  radius: if an external RADIUS server is used for authentication
+  pam: -- for future use --
+
+  'auth_db' refers to the database/protocol where user authentication 
+  information can be pulled from, in case the authentication process runs
+  on Asterisk.
+  Values for this parameter are :
+  file: if the password is stored in the matching configuration file 
+  (ex. sip.conf)
+
+  'password' : the password string, or its MD5 hash (for SIP users)
 
   \param username the user we want to authenticate
   \param secret the string that needs parsing
   \param pwd set to the fetch password if applicable, NULL instead
 
   \return a set of flags that needs to be interpreted by the resource
-  asking for authentication
+  resquesting authentication
 */
-
 int ast_parse_secret(const char *username, const char *secret, char *pwd)
 {
-	char auth[256];
-	char *pw_form;
-	char *password;
+	char buf[256];
+	char *auth_proxy = NULL;
+	char *auth_db = NULL;
+	char *password = NULL;
 	unsigned int res = 0;
 	struct ast_flags locflags = {0};
 
-	ast_copy_string(auth, secret, sizeof(auth));
+	ast_copy_string(buf, secret, sizeof(buf));
+
+	auth_proxy = buf;
 
 	/* split the auth string into pieces */
-	pw_form = strchr(auth, ':');
-	if (pw_form) {
-		*pw_form = '\0';
-		pw_form++;
-
-		password = strchr(pw_form, ':');
+	auth_db = strchr(buf, ':');
+
+	if (auth_db) {
+		*auth_db = '\0';
+		auth_db++;
+		password = strchr(auth_db, ':');
 		if (password) {
 			*password = '\0';
 			password ++;
-			ast_copy_string(pwd, password, strlen(password) + 1);
-			ast_set_flag(&locflags, PW_SET);
-		}
-		
-	}
-	else {
+		}
+	}
+	if (!ast_strlen_zero(auth_proxy))
+		ast_log(LOG_DEBUG, "auth_proxy : %s\n", auth_proxy);
+	if (!ast_strlen_zero(auth_db))
+		ast_log(LOG_DEBUG, "auth_db : %s\n", auth_db);
+	if (!ast_strlen_zero(password))
+		ast_log(LOG_DEBUG, "password : %s\n", password);
+
+	if (!auth_db) {
 		/* let's kindly accept old formatted secrets */
+		ast_log(LOG_DEBUG, "Old style password : %s\n", secret);
 		ast_copy_string(pwd, secret, strlen(secret) + 1);
 		ast_set_flag(&locflags, AUTH_LOCAL);
 		ast_set_flag(&locflags, PW_SET);
-		ast_set_flag(&locflags, PW_CLEAR);
+		ast_set_flag(&locflags, PW_FILE);
 		
 		res = locflags.flags;
 		return res;
 	}
 
-	/* check 'auth' string */
-	if (!ast_strlen_zero(auth)) {
-		if (!strcasecmp(auth, "local")) {
+	/* process 'auth_proxy' string. Return if authentication is proxied */
+	if (!ast_strlen_zero(auth_proxy)) {
+		if (!strcasecmp(auth_proxy, "ldap")) {
+#ifdef HAVE_OPENLDAP
+			ast_set_flag(&locflags, AUTH_LDAP);
+			return res = locflags.flags;
+#else
+			ast_log(LOG_ERROR, "OpenLDAP library was not found. Cannot use LDAP to authenticate users\n");
+			return res = AUTH_ERR;
+#endif /* HAVE_OPENLDAP */
+		}
+		else if (!strcasecmp(auth_proxy, "radius")) {
+#ifdef HAVE_RADIUS
+			ast_set_flag(&locflags, AUTH_RADIUS);
+			return res = locflags.flags;
+#else
+			ast_log(LOG_ERROR, "radiusclient-ng library was not found. Cannot use RADIUS to authenticate users\n");
+			return res = AUTH_ERR;
+#endif /* HAVE_RADIUS */
+		}
+		else if (!strcasecmp(auth_proxy, "pam")) {
+			ast_set_flag(&locflags, AUTH_PAM);
+			return res = locflags.flags;
+		}
+		else if (!strcasecmp(auth_proxy, "local")) {
 			ast_set_flag(&locflags, AUTH_LOCAL);
-		}
-		else if (!strcasecmp(auth, "ldap")) {
-			ast_set_flag(&locflags, AUTH_LDAP);
-		}
-		else if (!strcasecmp(auth, "radius")) {
-			ast_set_flag(&locflags, AUTH_RADIUS);
-		}
-		else if (!strcasecmp(auth, "pam")) {
-			ast_set_flag(&locflags, AUTH_PAM);
 		}		
 		else {
 			res = AUTH_ERR;
-		}
-	}
-
-	/* check pw_form */
-	if (!ast_strlen_zero(pw_form)) {
-		if (!strcasecmp(pw_form, "clear")) {
-			ast_set_flag(&locflags, PW_CLEAR);
-		}
-		if (!strcasecmp(pw_form, "md5")) {
-			ast_set_flag(&locflags, PW_MD5);
+			return res;
+		}		
+	}
+
+	/* check auth_db */
+	if (!ast_strlen_zero(auth_db)) {
+		/* password set in config file */
+		if (!strcasecmp(auth_db, "file")) {
+			ast_set_flag(&locflags, PW_FILE);
+			if (!ast_strlen_zero(password)) {
+				/* fill pwd and inform that password is set */
+				ast_copy_string(pwd, password, strlen(password) + 1);
+				ast_set_flag(&locflags, PW_SET);	
+			}
+			else {
+				ast_log(LOG_ERROR, "Password is missing.\n");
+				res = AUTH_ERR;
+			}
+		}
+		/* password should be pulled from an LDAP directory */
+		if (!strcasecmp(auth_db, "ldap")) {
+			/* retrieve password from LDAP, fill pwd and inform 
+			   that password is set */
+#ifdef HAVE_OPENLDAP		       
+			if (get_ldap_password(username, pwd) == 0) {
+				ast_set_flag(&locflags, PW_LDAP);
+				ast_set_flag(&locflags, PW_SET);
+			}
+			else {
+				ast_log(LOG_ERROR, "LDAP password not found\n");
+				res = AUTH_ERR;
+			}
+#else
+			ast_log(LOG_ERROR, "OpenLDAP library was not found. Cannot use LDAP to authenticate users\n");
+			res = AUTH_ERR;
+#endif /* HAVE_OPENLDAP */
+
 		}
 	}
 
@@ -143,16 +219,125 @@
 	return res;
 }
 
-char *ast_get_auth(const char *userid) 
-{
-	char *pwd = NULL;
-	return pwd;
-} 
+#ifdef HAVE_OPENLDAP
+/*!\brief Connects to the configured LDAP server
+
+  \return 1 if already connected, 0 on success, -1 on error
+*/
+static int ldap_connect(void)
+{
+	int bind_result = 0;
+	
+	if (ldapConn) {
+		ast_log(LOG_NOTICE, "Already connected.\n");
+		return 1;
+	}
+	
+	if (!dbhost) {
+		ast_log(LOG_ERROR, "Host parameter missing.\n");
+		return -1;
+	}
+	
+	if (!(ldapConn = ldap_init(dbhost, dbport))) {
+		ast_log(LOG_ERROR, "Failed to connect to %s on port %d.\n", dbhost, dbport);
+		return -1;
+	}
+
+	if (dbuser && *dbuser) {
+		ast_log(LOG_NOTICE, "Binding to %s as %s\n", dbhost, dbuser);
+			bind_result = ldap_simple_bind_s(ldapConn, dbuser, dbpass);
+	} else {
+		ast_log(LOG_NOTICE, "Binding anonymously to %s\n", dbhost);
+		bind_result = ldap_simple_bind_s(ldapConn, NULL, NULL);
+	}
+
+	if (bind_result == LDAP_SUCCESS) {
+		ast_log(LOG_NOTICE, "Successfully connected to database.\n");
+		return 0;
+	} else {
+		ast_log(LOG_WARNING, "Bind failed: %s\n", ldap_err2string(bind_result));
+		ldap_unbind(ldapConn);
+		ldapConn = NULL;
+		return -1;
+	}
+	
+}
+
+/*!\brief Disconnects from the LDAP server
+*/
+static int ldap_disconnect(void)
+{
+	ldap_unbind(ldapConn);
+	ldapConn = NULL;
+
+	return 1;
+	
+}
+
+/*!\brief A function that finds a user password from an LDAP database based
+  on the LDAP filter set in the auth.conf file
+
+  \param username the username which password is seeked
+  \param password the string filled with the retrieved LDAP password
+  attribute value
+
+  \return -1 if no entry nor value was found, 0 either
+*/
+static int get_ldap_password(const char *username, char* password)
+{
+	int result = 0;
+	LDAPMessage *ldap_result = NULL;
+	char ldap_filter[128];
+	int num_entry = 0;
+	char **values = NULL;
+
+	snprintf(ldap_filter, sizeof(ldap_filter), "(%s=%s)", username_attr, username);
+
+	result = ldap_search_s(ldapConn, dbbasedn,
+			       LDAP_SCOPE_SUBTREE, ldap_filter, NULL, 0,
+			       &ldap_result);
+
+	if (result < 0) {
+		ast_log(LOG_ERROR, "LDAP search failed.\n");		
+		return -1;
+	}
+	
+	num_entry = ldap_count_entries(ldapConn, ldap_result);
+
+	if (!num_entry) {
+		ast_log(LOG_ERROR, "No entry found. Filter : %s\n", ldap_filter);
+		return -1;
+	}
+	
+	/* only process the first retrieved entry */
+	LDAPMessage *ldap_entry = NULL;
+	ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+	
+	values = ldap_get_values(ldapConn, ldap_entry, userpw_attr);
+	/* only process the first retrieved value */
+	if (values) {
+		char **v = values;		
+		char *value = *v;
+		ast_copy_string(password, value, MAX_PW_LEN);
+		ldap_value_free(values);
+	}
+	else {
+		ast_log(LOG_ERROR, "No password found.\n");
+		return -1;
+	}
+	
+	ldap_msgfree(ldap_result);
+
+	return result;
+}
+#endif /* HAVE_OPENLDAP */
+
+#ifdef HAVE_RADIUS
 
 /*!\brief A utility function that helps filling correctly a digest_parameters 
   structure
 */
-int push_digest_attribute(struct digest_parameters *params, digest_attr_t *attr)
+int ast_push_digest_attribute(struct digest_parameters *params, digest_attr_t *attr)
 {        
 	params->d_attrs_list[params->num_attrs].type = attr->type;
 	params->d_attrs_list[params->num_attrs].length = attr->length;
@@ -161,7 +346,6 @@
 	return 1;
 }
 
-#ifdef HAVE_RADIUS_CLIENT_H
 /*!\brief Authenticate using the radiusclient-ng library
   Acting as a RADIUS client, Asterisk sends a RADIUS authentication request
   to a RADIUS server, and waits for the answer.
@@ -199,9 +383,7 @@
 		return -1;
 	}
 
-	/*
-	 * Fill in Digest attributes
-	 */
+	/* Fill in Digest attributes */
 	for (i = 0; i < aux.num_attrs; i++) {
 		aux.d_attrs_list[i].type = params->d_attrs_list[i].type;
 		aux.d_attrs_list[i].length = params->d_attrs_list[i].length;
@@ -226,50 +408,116 @@
 	/* send result */
 	return res;
 }
-#endif /* HAVE_RADIUS_CLIENT_H */
-
-char *description(void)
-{
-	return tdesc;
-}
-
-int usecount(void)
-{
+#endif /* HAVE_RADIUS */
+
+static int parse_config(void)
+{
+	const struct ast_config *config;
+	const char *s;
+
+	config = ast_config_load(RES_AUTH_CONF);
+
+	if (config) {
+
+#ifdef HAVE_OPENLDAP	      
+		if (!(s = ast_variable_retrieve(config, "ldap", "dbuser"))) {
+			ast_log(LOG_WARNING, "No database user found, anonymous binding as default.\n");
+			dbuser[0] = '\0';
+		} else 
+			ast_copy_string(dbuser, s, sizeof(dbuser));
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "dbpass"))) {
+			ast_log(LOG_WARNING, "No database password found, using 'asterisk' as default.\n");
+			ast_copy_string(dbpass, "asterisk", sizeof(dbpass));
+		} else
+			ast_copy_string(dbpass, s, sizeof(dbpass));
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "dbhost"))) {
+			ast_log(LOG_ERROR, "No host found.\n");
+			dbhost[0] = '\0';
+		} else 
+			ast_copy_string(dbhost, s, sizeof(dbhost));
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "dbbasedn"))) {
+			ast_log(LOG_ERROR, "No LDAP base dn found.\n");
+			dbbasedn[0] = '\0';
+		} else 
+			ast_copy_string(dbbasedn, s, sizeof(dbbasedn));
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "dbport"))) {
+			ast_log(LOG_WARNING, "No directory port found, using 389 as default.\n");
+			dbport = 389;
+		} else 
+			dbport = atoi(s);
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "user_name_attribute"))) {
+			ast_log(LOG_ERROR, "user_name_attribute is needed.\n");
+		} else 
+			ast_copy_string(username_attr, s, sizeof(username_attr));
+
+		if (!(s = ast_variable_retrieve(config, "ldap", "user_password_attribute"))) {
+			ast_log(LOG_ERROR, "user_password_attribute is needed.\n");
+		} else 
+			ast_copy_string(userpw_attr, s, sizeof(userpw_attr));
+
+	}
+
+	ast_log(LOG_NOTICE, "LDAP Host: %s\n", dbhost);
+	ast_log(LOG_NOTICE, "LDAP Port: %i\n", dbport);
+	ast_log(LOG_NOTICE, "LDAP User: %s\n", dbuser);
+	ast_log(LOG_NOTICE, "LDAP Password: %s\n", dbpass);
+	ast_log(LOG_NOTICE, "LDAP BaseDN: %s\n", dbbasedn);
+	ast_log(LOG_NOTICE, "LDAP User name attribute: %s\n", username_attr);
+	ast_log(LOG_NOTICE, "LDAP User password attribute: %s\n", userpw_attr);
+#endif /* HAVE_OPENLDAP */
+
+	ast_config_destroy(config);
 	return 1;
 }
 
-char *key()
-{
-	return ASTERISK_GPL_KEY;
-}
-
-int unload_module(void)
-{
+
+static int unload_module(void)
+{
+	ldap_disconnect();
 	ast_log(LOG_NOTICE, "res_auth unloaded.\n");
 	return 0;
 }
 
-int load_module(void)
-{
-#ifdef HAVE_RADIUS_CLIENT_H
+static int load_module(void)
+{
+
+	parse_config();
+
+#ifdef HAVE_OPENLDAP
+	if (ldap_connect() < 0) 
+		ast_log(LOG_ERROR, "Couldn't establish connection.\n");
+#endif /* HAVE_OPENLDAP */
+
+#ifdef HAVE_RADIUS
 	/* start logging */
 	rc_openlog("asterisk");
 
 	/* read radiusclient-ng config file */
 	if ((rh = rc_read_config(RC_CONFIG_FILE)) == NULL) {
-		ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", RC_CONFIG_FILE);
+		ast_log(LOG_ERROR, "Cannot load radiusclient-ng configuration file %s.\n", RC_CONFIG_FILE);
 		return -1;
 	}
 
 	/* read radiusclient-ng dictionaries */
 	if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
-		ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
-		return -1;
-	}
-
-#endif /* HAVE_RADIUS_CLIENT_H */
+		ast_log(LOG_ERROR, "Cannot load radiusclient-ng dictionary file.\n");
+		return -1;
+	}
+
+#endif /* HAVE_RADIUS */
+
 
 	ast_log(LOG_NOTICE, "res_auth loaded.\n");
 	return 0;
 }
 
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Authentication resource",
+		.load = load_module,
+		.unload = unload_module,
+	       );



More information about the svn-commits mailing list