1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2021 */
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
14 /* This module contains functions that call the Radius authentication
17 We can't just compile this code and allow the library mechanism to omit the
18 functions if they are not wanted, because we need to have the Radius headers
19 available for compiling. Therefore, compile these functions only if
20 RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
21 empty modules, so keep them happy with a dummy when skipping the rest. Make it
22 reference itself to stop picky compilers complaining that it is unused, and put
23 in a dummy argument to stop even pickier compilers complaining about infinite
24 loops. Then use a mutually-recursive pair as gcc is just getting stupid. */
26 #ifndef RADIUS_CONFIG_FILE
27 static void dummy(int x);
28 static void dummy2(int x) { dummy(x-1); }
29 static void dummy(int x) { dummy2(x-1); }
30 #else /* RADIUS_CONFIG_FILE */
33 /* Two different Radius libraries are supported. The default is radiusclient,
34 using its original API. At release 0.4.0 the API changed. */
36 #ifdef RADIUS_LIB_RADLIB
39 # if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
40 # define RADIUS_LIB_RADIUSCLIENT
43 # ifdef RADIUS_LIB_RADIUSCLIENTNEW
44 # define ENV FREERADIUSCLIENT_ENV /* Avoid clash with Berkeley DB */
45 # include <freeradius-client.h>
47 # include <radiusclient.h>
53 /*************************************************
54 * Perform RADIUS authentication *
55 *************************************************/
57 /* This function calls the Radius authentication mechanism, passing over one or
61 s a colon-separated list of strings
62 errptr where to point an error message
64 Returns: OK if authentication succeeded
65 FAIL if authentication failed
66 ERROR some other error condition
70 auth_call_radius(const uschar *s, uschar **errptr)
73 const uschar *radius_args = s;
77 #ifdef RADIUS_LIB_RADLIB
80 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
83 VALUE_PAIR *send = NULL;
85 unsigned int service = PW_AUTHENTICATE_ONLY;
90 if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) user = US"";
92 DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
93 "and \"%s\"\n", user, radius_args);
98 /* Authenticate using the radiusclient library */
100 #ifndef RADIUS_LIB_RADLIB
104 #ifdef RADIUS_LIB_RADIUSCLIENT
105 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
106 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
108 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
109 *errptr = US"RADIUS: can't read dictionary";
111 else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0))
112 *errptr = US"RADIUS: add user name failed";
114 else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0))
115 *errptr = US"RADIUS: add password failed");
117 else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0))
118 *errptr = US"RADIUS: add service type failed";
120 #else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
122 if (!(h = rc_read_config(RADIUS_CONFIG_FILE)))
123 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
125 else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
126 *errptr = US"RADIUS: can't read dictionary";
128 else if (!rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0))
129 *errptr = US"RADIUS: add user name failed";
131 else if (!rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
132 Ustrlen(radius_args), 0))
133 *errptr = US"RADIUS: add password failed";
135 else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0))
136 *errptr = US"RADIUS: add service type failed";
138 #endif /* RADIUS_LIB_RADIUSCLIENT */
142 DEBUG(D_auth) debug_printf("%s\n", *errptr);
146 #ifdef RADIUS_LIB_RADIUSCLIENT
147 result = rc_auth(0, send, &received, msg);
149 result = rc_auth(h, 0, send, &received, msg);
152 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
164 *errptr = US"RADIUS: timed out";
169 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
173 #else /* RADIUS_LIB_RADLIB is set */
175 /* Authenticate using the libradius library */
177 if (!(h = rad_auth_open()))
179 *errptr = string_sprintf("RADIUS: can't initialise libradius");
182 if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
183 rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
184 rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
185 rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
186 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
187 rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 0)
189 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
193 switch (result = rad_send_request(h))
195 case RAD_ACCESS_ACCEPT:
199 case RAD_ACCESS_REJECT:
204 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
209 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
214 if (*errptr) DEBUG(D_auth) debug_printf("%s\n", *errptr);
218 #endif /* RADIUS_LIB_RADLIB */
221 #endif /* RADIUS_CONFIG_FILE */
223 /* End of call_radius.c */