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 user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
100 if (!user) user = US"";
102 DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
103 "and \"%s\"\n", user, radius_args);
108 /* Authenticate using the radiusclient library */
110 #ifndef RADIUS_LIB_RADLIB
114 #ifdef RADIUS_LIB_RADIUSCLIENT
115 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
116 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
118 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
119 *errptr = US"RADIUS: can't read dictionary";
121 else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0))
122 *errptr = US"RADIUS: add user name failed";
124 else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0))
125 *errptr = US"RADIUS: add password failed");
127 else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0))
128 *errptr = US"RADIUS: add service type failed";
130 #else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
132 if (!(h = rc_read_config(RADIUS_CONFIG_FILE)))
133 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
135 else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
136 *errptr = US"RADIUS: can't read dictionary";
138 else if (!rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0))
139 *errptr = US"RADIUS: add user name failed";
141 else if (!rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
142 Ustrlen(radius_args), 0))
143 *errptr = US"RADIUS: add password failed";
145 else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0))
146 *errptr = US"RADIUS: add service type failed";
148 #endif /* RADIUS_LIB_RADIUSCLIENT */
152 DEBUG(D_auth) debug_printf("%s\n", *errptr);
156 #ifdef RADIUS_LIB_RADIUSCLIENT
157 result = rc_auth(0, send, &received, msg);
159 result = rc_auth(h, 0, send, &received, msg);
162 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
174 *errptr = US"RADIUS: timed out";
179 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
183 #else /* RADIUS_LIB_RADLIB is set */
185 /* Authenticate using the libradius library */
187 if (!(h = rad_auth_open()))
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));
203 switch (result = rad_send_request(h))
205 case RAD_ACCESS_ACCEPT:
209 case RAD_ACCESS_REJECT:
214 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
219 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
224 if (*errptr) DEBUG(D_auth) debug_printf("%s\n", *errptr);
228 #endif /* RADIUS_LIB_RADLIB */
231 #endif /* RADIUS_CONFIG_FILE */
233 /* End of call_radius.c */