1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2016 */
6 /* See the file NOTICE for conditions of use and distribution. */
8 /* This file was originally supplied by Ian Kirk. The libradius support came
11 /* ugly hack to work around redefinition of ENV by radiusclient.h and
12 * db.h: define _DB_H_ so the db.h include thinks it's already included,
13 * we can get away with it like this, since this file doesn't use any db
17 # define _DB_EXT_PROT_IN_ 1
23 /* This module contains functions that call the Radius authentication
26 We can't just compile this code and allow the library mechanism to omit the
27 functions if they are not wanted, because we need to have the Radius headers
28 available for compiling. Therefore, compile these functions only if
29 RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
30 empty modules, so keep them happy with a dummy when skipping the rest. Make it
31 reference itself to stop picky compilers complaining that it is unused, and put
32 in a dummy argument to stop even pickier compilers complaining about infinite
33 loops. Then use a mutually-recursive pair as gcc is just getting stupid. */
35 #ifndef RADIUS_CONFIG_FILE
36 static void dummy(int x);
37 static void dummy2(int x) { dummy(x-1); }
38 static void dummy(int x) { dummy2(x-1); }
39 #else /* RADIUS_CONFIG_FILE */
42 /* Two different Radius libraries are supported. The default is radiusclient,
43 using its original API. At release 0.4.0 the API changed. */
45 #ifdef RADIUS_LIB_RADLIB
48 #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
49 # define RADIUS_LIB_RADIUSCLIENT
52 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
53 # include <freeradius-client.h>
55 # include <radiusclient.h>
61 /*************************************************
62 * Perform RADIUS authentication *
63 *************************************************/
65 /* This function calls the Radius authentication mechanism, passing over one or
69 s a colon-separated list of strings
70 errptr where to point an error message
72 Returns: OK if authentication succeeded
73 FAIL if authentication failed
74 ERROR some other error condition
78 auth_call_radius(const uschar *s, uschar **errptr)
81 const uschar *radius_args = s;
85 #ifdef RADIUS_LIB_RADLIB
88 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
91 VALUE_PAIR *send = NULL;
93 unsigned int service = PW_AUTHENTICATE_ONLY;
98 user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
99 if (user == NULL) user = US"";
101 DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
102 "and \"%s\"\n", user, radius_args);
107 /* Authenticate using the radiusclient library */
109 #ifndef RADIUS_LIB_RADLIB
113 #ifdef RADIUS_LIB_RADIUSCLIENT
114 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
115 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
117 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
118 *errptr = string_sprintf("RADIUS: can't read dictionary");
120 else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL)
121 *errptr = string_sprintf("RADIUS: add user name failed\n");
123 else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL)
124 *errptr = string_sprintf("RADIUS: add password failed\n");
126 else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
127 *errptr = string_sprintf("RADIUS: add service type failed\n");
129 #else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
131 if ((h = rc_read_config(RADIUS_CONFIG_FILE)) == NULL)
132 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
134 else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
135 *errptr = string_sprintf("RADIUS: can't read dictionary");
137 else if (rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0) == NULL)
138 *errptr = string_sprintf("RADIUS: add user name failed\n");
140 else if (rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
141 Ustrlen(radius_args), 0) == NULL)
142 *errptr = string_sprintf("RADIUS: add password failed\n");
144 else if (rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0) == NULL)
145 *errptr = string_sprintf("RADIUS: add service type failed\n");
147 #endif /* RADIUS_LIB_RADIUSCLIENT */
151 DEBUG(D_auth) debug_printf("%s\n", *errptr);
155 #ifdef RADIUS_LIB_RADIUSCLIENT
156 result = rc_auth(0, send, &received, msg);
158 result = rc_auth(h, 0, send, &received, msg);
161 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
173 *errptr = US"RADIUS: timed out";
178 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
182 #else /* RADIUS_LIB_RADLIB is set */
184 /* Authenticate using the libradius library */
189 *errptr = string_sprintf("RADIUS: can't initialise libradius");
192 if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
193 rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
194 rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
195 rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
196 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
197 rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 0)
199 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
204 result = rad_send_request(h);
208 case RAD_ACCESS_ACCEPT:
212 case RAD_ACCESS_REJECT:
217 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
222 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
228 if (*errptr != NULL) DEBUG(D_auth) debug_printf("%s\n", *errptr);
232 #endif /* RADIUS_LIB_RADLIB */
235 #endif /* RADIUS_CONFIG_FILE */
237 /* End of call_radius.c */