1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15
16#include "portable.h"
17
18#include <stdio.h>
19
20#include <lber.h>
21#include <lber_pvt.h>	/* BER_BVC definition */
22#include "lutil.h"
23#include <ldap_pvt_thread.h>
24#include <ac/string.h>
25#include <ac/unistd.h>
26
27#include <radlib.h>
28
29static LUTIL_PASSWD_CHK_FUNC chk_radius;
30static const struct berval scheme = BER_BVC("{RADIUS}");
31static char *config_filename;
32static ldap_pvt_thread_mutex_t libradius_mutex;
33
34static int
35chk_radius(
36	const struct berval	*sc,
37	const struct berval	*passwd,
38	const struct berval	*cred,
39	const char		**text )
40{
41	unsigned int		i;
42	int			rc = LUTIL_PASSWD_ERR;
43
44	struct rad_handle	*h = NULL;
45
46	for ( i = 0; i < cred->bv_len; i++ ) {
47		if ( cred->bv_val[ i ] == '\0' ) {
48			return LUTIL_PASSWD_ERR;	/* NUL character in cred */
49		}
50	}
51
52	if ( cred->bv_val[ i ] != '\0' ) {
53		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
54	}
55
56	for ( i = 0; i < passwd->bv_len; i++ ) {
57		if ( passwd->bv_val[ i ] == '\0' ) {
58			return LUTIL_PASSWD_ERR;	/* NUL character in password */
59		}
60	}
61
62	if ( passwd->bv_val[ i ] != '\0' ) {
63		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
64	}
65
66	ldap_pvt_thread_mutex_lock( &libradius_mutex );
67
68	h = rad_auth_open();
69	if ( h == NULL ) {
70		ldap_pvt_thread_mutex_unlock( &libradius_mutex );
71		return LUTIL_PASSWD_ERR;
72	}
73
74	if ( rad_config( h, config_filename ) != 0 ) {
75		goto done;
76	}
77
78	if ( rad_create_request( h, RAD_ACCESS_REQUEST ) ) {
79		goto done;
80	}
81
82	if ( rad_put_string( h, RAD_USER_NAME, passwd->bv_val ) != 0 ) {
83		goto done;
84	}
85
86	if ( rad_put_string( h, RAD_USER_PASSWORD, cred->bv_val ) != 0 ) {
87		goto done;
88	}
89
90	switch ( rad_send_request( h ) ) {
91	case RAD_ACCESS_ACCEPT:
92		rc = LUTIL_PASSWD_OK;
93		break;
94
95	case RAD_ACCESS_REJECT:
96		rc = LUTIL_PASSWD_ERR;
97		break;
98
99	case RAD_ACCESS_CHALLENGE:
100		rc = LUTIL_PASSWD_ERR;
101		break;
102
103	case -1:
104		/* no valid response is received */
105		break;
106	}
107
108done:;
109	rad_close( h );
110
111	ldap_pvt_thread_mutex_unlock( &libradius_mutex );
112	return rc;
113}
114
115int
116term_module()
117{
118	return ldap_pvt_thread_mutex_destroy( &libradius_mutex );
119}
120
121int
122init_module( int argc, char *argv[] )
123{
124	int	i;
125
126	for ( i = 0; i < argc; i++ ) {
127		if ( strncasecmp( argv[ i ], "config=", STRLENOF( "config=" ) ) == 0 ) {
128			/* FIXME: what if multiple loads of same module?
129			 * does it make sense (e.g. override an existing one)? */
130			if ( config_filename == NULL ) {
131				config_filename = ber_strdup( &argv[ i ][ STRLENOF( "config=" ) ] );
132			}
133
134		} else {
135			fprintf( stderr, "init_module(radius): unknown arg#%d=\"%s\".\n",
136				i, argv[ i ] );
137			return 1;
138		}
139	}
140
141	ldap_pvt_thread_mutex_init( &libradius_mutex );
142
143	return lutil_passwd_add( (struct berval *)&scheme, chk_radius, NULL );
144}
145