Commit ee167d34 authored by Robert Dubner's avatar Robert Dubner
Browse files

Drive everything with search URIs from slapd.conf

parent 66e0a504
......@@ -306,8 +306,7 @@ build_ttls_challenge( RADIUS_PACKET *response,
}
static int
process_eap_message_identity( void *ctx,
RADIUS_INFO *radius_info,
process_eap_message_identity( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -378,8 +377,7 @@ process_eap_message_identity( void *ctx,
}
static int
process_eap_message_legacy_nak( void *ctx,
RADIUS_INFO *radius_info,
process_eap_message_legacy_nak( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -993,14 +991,14 @@ process_mschap_response(STATE *state)
// Fetch the password for username[] from the LDAP directory:
char password[MAXIMUM_PASSWORD_CHARACTERS+1];
int bad_search = radiusov_get_password_from_uid( volatiles->radius_info,
volatiles->sd,
int bad_search = radiusov_get_password_from_uid(
volatiles->radius_info,
p_username,
password,
sizeof(password) );
if( bad_search )
{
Debug( LDAP_DEBUG_TRACE,
Debug( LDAP_DEBUG_STATS,
"Unable to find the password for %s in the LDAP directory\n",
p_username);
}
......@@ -1839,8 +1837,8 @@ respond_to_ttls_md5_challenge( EAP_MESSAGE *internal_eap_message,
char password[MAXIMUM_PASSWORD_CHARACTERS+1];
int bad_search = radiusov_get_password_from_uid( volatiles->radius_info,
volatiles->sd,
int bad_search = radiusov_get_password_from_uid(
volatiles->radius_info,
username,
password,
sizeof(password));
......@@ -2223,8 +2221,7 @@ process_peap_application_data(STATE *state)
}
static int
process_eap_message_peap_or_ttls( void *ctx,
RADIUS_INFO *radius_info,
process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -2254,7 +2251,6 @@ process_eap_message_peap_or_ttls( void *ctx,
state->volatiles = ch_calloc(1, sizeof(STATE_VOLATILES));
state->volatiles->ctx = ctx ;
state->volatiles->radius_info = radius_info ;
state->volatiles->udp_socket = udp_socket ;
state->volatiles->client_addr = client_addr ;
......@@ -2483,8 +2479,7 @@ process_eap_message_peap_or_ttls( void *ctx,
}
static int
process_access_request( void *ctx,
RADIUS_INFO *radius_info,
process_access_request( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -2605,8 +2600,7 @@ process_access_request( void *ctx,
switch(eap_message->Type)
{
case EAP_MESSAGE_TYPE_IDENTITY:
rc = process_eap_message_identity( ctx,
radius_info,
rc = process_eap_message_identity( radius_info,
udp_socket,
client_addr,
sd,
......@@ -2615,8 +2609,7 @@ process_access_request( void *ctx,
break;
case EAP_MESSAGE_TYPE_LEGACY_NAK:
rc = process_eap_message_legacy_nak(ctx,
radius_info,
rc = process_eap_message_legacy_nak(radius_info,
udp_socket,
client_addr,
sd,
......@@ -2626,8 +2619,7 @@ process_access_request( void *ctx,
case EAP_MESSAGE_TYPE_PEAP:
case EAP_MESSAGE_TYPE_TTLS:
rc = process_eap_message_peap_or_ttls( ctx,
radius_info,
rc = process_eap_message_peap_or_ttls( radius_info,
udp_socket,
client_addr,
sd,
......@@ -2676,8 +2668,7 @@ process_access_request( void *ctx,
}
int
radiusov_protocol( void *ctx,
RADIUS_INFO *radius_info,
radiusov_protocol( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -2703,8 +2694,7 @@ radiusov_protocol( void *ctx,
switch(get_code(request))
{
case PC_Access_Request:
rc = process_access_request(ctx,
radius_info,
rc = process_access_request(radius_info,
udp_socket,
client_addr,
sd,
......
......@@ -48,39 +48,9 @@ ldap_pvt_thread_mutex_t libradius_mutex;
// when working with a Wireless Access Point that insists on retrying while you
// are trapping through code in a multi-threaded environment.
//
// A negative value means just process everything
// A negative value means just process everything without touching the counter
static int packet_eat_count = -5;
// For initial development, this is a static list. Eventually it will
// be established from a configuration file or database
static search_descriptor search_descriptors[] =
{
{
"127.0.0.1",
TEST_AND_DEVELOPMENT,
LDAP_SCOPE_SUBTREE,
"(uid=%s)",
"dc=renbud,dc=com",
"",
},
{
"10.0.1.250",
RADIUS_PROTOCOL,
LDAP_SCOPE_SUBTREE,
"(uid=%s)",
"dc=renbud,dc=com",
"testing123",
},
{
NULL, // This entry ends the list
INVALID_SEARCH_METHOD,
0,
NULL,
NULL,
NULL,
},
};
static int packet_eat_count = -1;
static void
ber_lower(BerValue *bv)
......@@ -252,8 +222,9 @@ radiusov_generalized_database_fetch(BackendDB *be,
// This routine is designed for handling just one attribute.
// I am including that single attribute, although there doesn't seem to
// be any point.
ber_printf(ber, "{s}", "userPassword");
// be any point: my observation is that even with this parameter, the
// callback routine gets all the attributes.
ber_printf(ber, "{s}", attribute_name);
ber_printf(ber,"}");
......@@ -295,31 +266,58 @@ radiusov_generalized_database_fetch(BackendDB *be,
return rc;
}
static int
radiusov_get_dn_from_uid( BackendDB *be,
const char *base,
int scope,
char *pszUsername,
struct berval *dn_retval,
size_t len)
static void
convert_search_string( char * const dest,
size_t len,
const char *uri_search_string, ...)
{
Debug(LDAP_DEBUG_TRACE,"=> %s(). UID is %s\n",__func__, pszUsername);
char *d = dest;
const char *s = uri_search_string;
size_t bytes_left = len-1;
int rc = 0; // Zero means Okay
va_list the_parameters;
va_start(the_parameters, uri_search_string);
char filter[1024];
sprintf(filter,"(uid=%s)",pszUsername);
while(bytes_left > 0)
{
char ch = *s++;
bytes_left -= 1;
if( ch == '\0' )
{
// We have copied over the whole search string
break;
}
if( ch == '$' )
{
// A dollar sign is the replacement flag. We are already past it.
// We are going to ignore any decimal digits that follow the dollar
// sign:
while( isdigit(*s) )
{
s += 1;
}
// And, in place of the dollar sign, tack on the next parameter
char *param = va_arg(the_parameters, char *);
while( *param && bytes_left > 0 )
{
*d++ = *param++;
bytes_left -= 1;
}
}
else
{
// Because the character isn't a dollar sign, we just copy it
// to the destination:
*d++ = ch;
}
}
*d++ = '\0';
va_end(the_parameters);
rc = radiusov_generalized_database_fetch(be,
base,
scope,
filter,
"dn",
dn_retval->bv_val,
len);
dn_retval->bv_len = strlen(dn_retval->bv_val);
return rc;
}
static int
......@@ -329,16 +327,28 @@ radiusov_verify_username_password( RADIUS_INFO *radius_info,
char *pszPassword)
{
Debug(LDAP_DEBUG_TRACE,"=> %s()\n",__func__);
// Starting with username, find its DN
// This was used for development and test of a couple of things. We are
// going to use radius_info->lud_simple_test to get the dn (the URI has to
// be in the correct for for that). Once we have the URI, we'll do a bind
// operation to determine the validity of the password and that dn
char achSearchString[256];
convert_search_string( achSearchString,
sizeof(achSearchString),
radius_info->lud_simple_test->lud_filter,
pszUsername );
char dnbuffer[1024];
BerValue dn = {0, dnbuffer};
int rc = radiusov_get_dn_from_uid(radius_info->radius_db,
sd->search_base,
sd->search_scope,
pszUsername,
&dn,
sizeof(dnbuffer) );
int rc = radiusov_generalized_database_fetch(radius_info->radius_db,
radius_info->lud_simple_test->lud_dn,
radius_info->lud_simple_test->lud_scope,
achSearchString,
radius_info->lud_simple_test->lud_attrs[0],
dnbuffer,
sizeof(dnbuffer) );
dn.bv_len = strlen(dnbuffer);
if( rc == 0 )
{
......@@ -358,29 +368,32 @@ radiusov_verify_username_password( RADIUS_INFO *radius_info,
int
radiusov_get_password_from_uid( RADIUS_INFO *radius_info,
search_descriptor *sd,
char *pszUsername,
char *password,
size_t len)
size_t password_len)
{
char filter[1024];
sprintf(filter,"(uid=%s)",pszUsername);
int rc = radiusov_generalized_database_fetch(
radius_info->radius_db,
sd->search_base,
sd->search_scope,
filter,
"userPassword",
password,
len);
int rc;
char achSearchString[256];
convert_search_string( achSearchString,
sizeof(achSearchString),
radius_info->lud_radius_user->lud_filter,
pszUsername);
rc = radiusov_generalized_database_fetch(
radius_info->radius_db,
radius_info->lud_radius_user->lud_dn,
radius_info->lud_radius_user->lud_scope,
achSearchString,
radius_info->lud_radius_user->lud_attrs[0],
password,
password_len);
return rc;
}
static int
radiusov_test_and_development( void *ctx,
RADIUS_INFO *radius_info,
radiusov_test_and_development( RADIUS_INFO *radius_info,
search_descriptor *sd,
uint8_t *pszUsernamePassword_)
{
......@@ -539,42 +552,59 @@ radiusov_acceptconn(void *ctx, void *arg)
getsockname(radius_info->radius_udp_socket, (struct sockaddr *)&us, &len);
int our_port = ntohs(us.sin_port);
// Find our search_descriptor from the client_ipa and the our_port
// TODO: Ultimately this should be a map, not a linear search.
search_descriptor *sd = search_descriptors;
while( sd->client_ipa )
{
if( radius_info->radius_port_number == our_port && strcmp(sd->client_ipa, client_ipa) == 0 )
{
// We have a match on our port number and the client's IP address
break;
}
sd += 1;
}
if( !sd->client_ipa )
Debug( LDAP_DEBUG_ARGS,
"Incoming RADIUS client is %s on %d\n",
client_ipa,
our_port);
// We now search the directory tree for a RADIUS client device with
// this ip address and our port:
char achOurPort[12];
char achSearchString[256];
char achSharedSecret[256];
sprintf(achOurPort,"%d",our_port);
convert_search_string( achSearchString,
sizeof(achSearchString),
radius_info->lud_radius_client->lud_filter,
client_ipa,
achOurPort);
rc = radiusov_generalized_database_fetch(radius_info->radius_db,
radius_info->lud_radius_client->lud_dn,
radius_info->lud_radius_client->lud_scope,
achSearchString,
radius_info->lud_radius_client->lud_attrs[0],
achSharedSecret,
sizeof(achSharedSecret) );
if( rc )
{
Debug( LDAP_DEBUG_ANY,
"radiusov: There is no search descriptor for %s and port %d\n",
client_ipa,
our_port) ;
Debug( LDAP_DEBUG_ARGS,
"We couldn't find that IP Address / Port pair in the DIT\n");
return NULL;
}
// We have a good search_descriptor. At this point, we
// dispatch based on the search_method:
search_descriptor sd_;
search_descriptor *sd = &sd_;
sd->shared_secret = achSharedSecret;
switch( sd->search_method )
int search_method = RADIUS_PROTOCOL;
if( strcmp( achSharedSecret, "SpecialLocalTest" ) == 0 )
{
search_method = TEST_AND_DEVELOPMENT;
}
switch( search_method )
{
case TEST_AND_DEVELOPMENT:
rc = radiusov_test_and_development( ctx,
radius_info, sd,
rc = radiusov_test_and_development( radius_info,
sd,
incoming_request);
break;
case RADIUS_PROTOCOL:
rc = radiusov_protocol( ctx,
radius_info,
rc = radiusov_protocol( radius_info,
radius_info->radius_udp_socket,
&client_addr,
sd,
......@@ -583,16 +613,6 @@ radiusov_acceptconn(void *ctx, void *arg)
// In general, that routine returns NO_RESPONSE_NECESSARY,
// because it will have handled the response itself.
break;
default:
Debug( LDAP_DEBUG_ANY,
"radiusov: The search descriptor for %s and "
"port %d has invalid search_method %d\n",
client_ipa,
our_port,
sd->search_method ) ;
return NULL;
break;
}
switch( rc )
......@@ -724,6 +744,7 @@ enum
RADIUS_PORT = 1,
RADIUS_HOST,
RADIUS_CLIENT_URI,
RADIUS_USER_URI,
RADIUS_TEST,
};
......@@ -771,13 +792,27 @@ static ConfigTable radiuscfg[] =
NULL, NULL
},
{
"radiususeruri",
"Search URI for a user's password",
2, 2, 0,
ARG_MAGIC|RADIUS_USER_URI,
radius_config_driver,
"( OLcfgOvAt:" OVERLAY_OID ".4 NAME 'olcRadiusUserUri' "
"DESC 'URL for searching for a users password' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
")",
NULL, NULL
},
{
"radiustest",
"Search URI for simple testing",
2, 2, 0,
ARG_MAGIC|RADIUS_TEST,
radius_config_driver,
"( OLcfgOvAt:" OVERLAY_OID ".4 NAME 'olcRadiusTest' "
"( OLcfgOvAt:" OVERLAY_OID ".5 NAME 'olcRadiusTest' "
"DESC 'URL for simple searches in the test environment' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
......@@ -830,6 +865,16 @@ radius_config_driver(ConfigArgs *config_args)
" radiusport is %d\n",
atoi(config_args->argv[1]));
radius_info->radius_port_number = atoi(config_args->argv[1]);
if( radius_info->radius_port_number <= 0
|| radius_info->radius_port_number > 65535 )
{
Debug( LDAP_DEBUG_ANY,
"The RADIUS port number is %d, which makes no "
"sense; it has to be a 16-bit number\n",
radius_info->radius_port_number);
return 1;
}
}
break;
......@@ -860,6 +905,20 @@ radius_config_driver(ConfigArgs *config_args)
}
break;
case RADIUS_USER_URI:
if( config_args->argc > 1 )
{
if( ldap_url_parse( config_args->argv[1],
&radius_info->lud_radius_user) )
{
Debug( LDAP_DEBUG_ANY,
"ldap_url_parse FAILED on %s\n",
config_args->argv[1]);
rc = 1;
}
}
break;
case RADIUS_TEST:
if( config_args->argc > 1 )
{
......@@ -940,6 +999,7 @@ radiusov_db_destroy(BackendDB *be, ConfigReply *cr )
ch_free(radius_info->openssl_configuration);
ldap_free_urldesc( radius_info->lud_simple_test );
ldap_free_urldesc( radius_info->lud_radius_client );
ldap_free_urldesc( radius_info->lud_radius_user );
ch_free(radius_info);
......@@ -958,17 +1018,6 @@ radiusov_db_open(BackendDB *be, ConfigReply *cr)
slap_overinst *radiusov = (slap_overinst *)be->bd_info;
RADIUS_INFO *radius_info = radiusov->on_bi.bi_private;
if( radius_info->radius_port_number <= 0
|| radius_info->radius_port_number > 65535 )
{
Debug( LDAP_DEBUG_ANY,
"%s(): The first search_descriptor specifies RADIUS "
"port %d, which makes no sense\n",
__func__,
radius_info->radius_port_number);
return 1;
}
if ( slapMode & SLAP_SERVER_MODE )
{
rc = radiusov_create_udp_port( be,
......
......@@ -60,13 +60,12 @@
typedef struct _STATE_VOLATILES
{
void *ctx;
struct _RADIUS_INFO *radius_info;
int udp_socket;
struct sockaddr_in *client_addr;
struct _search_descriptor *sd;
struct _RADIUS_PACKET *request;
struct _EAP_MESSAGE *eap_message;
int udp_socket;
struct sockaddr_in *client_addr;
struct _search_descriptor *sd;
struct _RADIUS_PACKET *request;
struct _EAP_MESSAGE *eap_message;
} STATE_VOLATILES;
typedef struct _STATE
......@@ -114,7 +113,8 @@ typedef struct _RADIUS_INFO
int radius_port_number; // From slapd.conf
char radius_port_host[256]; // From slapd.conf. Usually 127.0.0.1, but
// // we leave room for a fully qualified domain name
LDAPURLDesc *lud_radius_client; // From slapd.conf. The parsed search URI for RADIUS client shared secrete
LDAPURLDesc *lud_radius_client; // From slapd.conf. The parsed search URI for RADIUS client shared secret
LDAPURLDesc *lud_radius_user; // From slapd.conf. The parsed search URI for RADIUS user password
LDAPURLDesc *lud_simple_test; // From slapd.conf. The parsed search URI for simple testing
int radius_udp_socket;
......@@ -127,23 +127,16 @@ typedef struct _RADIUS_INFO
typedef enum _search_methods
{
INVALID_SEARCH_METHOD,
TEST_AND_DEVELOPMENT, // Expects a simple <username>,<password> in the input packet
RADIUS_PROTOCOL, // This is a formal RADIUS protocol implementation
} search_methods;
typedef struct _search_descriptor
{
char *client_ipa;
search_methods search_method;
int search_scope;
char *search_filter_template;
char *search_base;
char *shared_secret;
} search_descriptor;
int radiusov_protocol( void *ctx,
RADIUS_INFO *radius_info,
int radiusov_protocol( RADIUS_INFO *radius_info,
int udp_socket,
struct sockaddr_in *client_addr,
search_descriptor *sd,
......@@ -190,7 +183,6 @@ void hmac_md5_final( MD5_CTX *context,
uint8_t *digest);
int radiusov_get_password_from_uid( RADIUS_INFO *radius_info,
search_descriptor *sd,
char *pszUsername,
char *password,
size_t len);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment