1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 */
6 /* Copyright (c) University of Cambridge 1995 - 2016 */
7 /* See the file NOTICE for conditions of use and distribution. */
9 /* This file was originally supplied by Ian Kirk. The libradius support came
12 /* ugly hack to work around redefinition of ENV by radiusclient.h and
13 * db.h: define _DB_H_ so the db.h include thinks it's already included,
14 * we can get away with it like this, since this file doesn't use any db
18 # define _DB_EXT_PROT_IN_ 1
24 /* This module contains functions that call the Radius authentication
27 We can't just compile this code and allow the library mechanism to omit the
28 functions if they are not wanted, because we need to have the Radius headers
29 available for compiling. Therefore, compile these functions only if
30 RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
31 empty modules, so keep them happy with a dummy when skipping the rest. Make it
32 reference itself to stop picky compilers complaining that it is unused, and put
33 in a dummy argument to stop even pickier compilers complaining about infinite
34 loops. Then use a mutually-recursive pair as gcc is just getting stupid. */
36 #ifndef RADIUS_CONFIG_FILE
37 static void dummy(int x);
38 static void dummy2(int x) { dummy(x-1); }
39 static void dummy(int x) { dummy2(x-1); }
40 #else /* RADIUS_CONFIG_FILE */
43 /* Two different Radius libraries are supported. The default is radiusclient,
44 using its original API. At release 0.4.0 the API changed. */
46 #ifdef RADIUS_LIB_RADLIB
49 #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
50 # define RADIUS_LIB_RADIUSCLIENT
53 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
54 # include <freeradius-client.h>
56 # include <radiusclient.h>
62 /*************************************************
63 * Perform RADIUS authentication *
64 *************************************************/
66 /* This function calls the Radius authentication mechanism, passing over one or
70 s a colon-separated list of strings
71 errptr where to point an error message
73 Returns: OK if authentication succeeded
74 FAIL if authentication failed
75 ERROR some other error condition
79 auth_call_radius(const uschar *s, uschar **errptr)
82 const uschar *radius_args = s;
86 #ifdef RADIUS_LIB_RADLIB
89 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
92 VALUE_PAIR *send = NULL;
94 unsigned int service = PW_AUTHENTICATE_ONLY;
99 if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) 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 = US"RADIUS: can't read dictionary";
120 else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0))
121 *errptr = US"RADIUS: add user name failed";
123 else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0))
124 *errptr = US"RADIUS: add password failed");
126 else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0))
127 *errptr = US"RADIUS: add service type failed";
129 #else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
131 if (!(h = rc_read_config(RADIUS_CONFIG_FILE)))
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 = US"RADIUS: can't read dictionary";
137 else if (!rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0))
138 *errptr = US"RADIUS: add user name failed";
140 else if (!rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
141 Ustrlen(radius_args), 0))
142 *errptr = US"RADIUS: add password failed";
144 else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0))
145 *errptr = US"RADIUS: add service type failed";
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 */
186 if (!(h = rad_auth_open()))
188 *errptr = string_sprintf("RADIUS: can't initialise libradius");
191 if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
192 rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
193 rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
194 rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
195 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
196 rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 0)
198 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
202 switch (result = rad_send_request(h))
204 case RAD_ACCESS_ACCEPT:
208 case RAD_ACCESS_REJECT:
213 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
218 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
223 if (*errptr) DEBUG(D_auth) debug_printf("%s\n", *errptr);
227 #endif /* RADIUS_LIB_RADLIB */
230 #endif /* RADIUS_CONFIG_FILE */
232 /* End of call_radius.c */