Debug: quieten DSN
[exim.git] / src / src / auths / call_radius.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
8ca559c8 5/* Copyright (c) The Exim Maintainers 2020 */
80fea873 6/* Copyright (c) University of Cambridge 1995 - 2016 */
0756eb3c
PH
7/* See the file NOTICE for conditions of use and distribution. */
8
9/* This file was originally supplied by Ian Kirk. The libradius support came
10from Alex Kiernan. */
11
27d93664
JH
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
15 * functions. */
16#ifndef _DB_H_
17# define _DB_H_ 1
18# define _DB_EXT_PROT_IN_ 1
19# define DB void
20#endif
21
0756eb3c
PH
22#include "../exim.h"
23
24/* This module contains functions that call the Radius authentication
25mechanism.
26
27We can't just compile this code and allow the library mechanism to omit the
28functions if they are not wanted, because we need to have the Radius headers
29available for compiling. Therefore, compile these functions only if
30RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
31empty modules, so keep them happy with a dummy when skipping the rest. Make it
32reference itself to stop picky compilers complaining that it is unused, and put
33in a dummy argument to stop even pickier compilers complaining about infinite
e1d15f5e 34loops. Then use a mutually-recursive pair as gcc is just getting stupid. */
0756eb3c
PH
35
36#ifndef RADIUS_CONFIG_FILE
e1d15f5e
JH
37static void dummy(int x);
38static void dummy2(int x) { dummy(x-1); }
39static void dummy(int x) { dummy2(x-1); }
0756eb3c
PH
40#else /* RADIUS_CONFIG_FILE */
41
42
7766a4f0
PH
43/* Two different Radius libraries are supported. The default is radiusclient,
44using its original API. At release 0.4.0 the API changed. */
0756eb3c
PH
45
46#ifdef RADIUS_LIB_RADLIB
47 #include <radlib.h>
48#else
7766a4f0 49 #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
27d93664
JH
50 # define RADIUS_LIB_RADIUSCLIENT
51 #endif
52
53 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
54 # include <freeradius-client.h>
55 #else
56 # include <radiusclient.h>
0756eb3c 57 #endif
0756eb3c
PH
58#endif
59
60
61
62/*************************************************
63* Perform RADIUS authentication *
64*************************************************/
65
66/* This function calls the Radius authentication mechanism, passing over one or
67more data strings.
68
69Arguments:
70 s a colon-separated list of strings
71 errptr where to point an error message
72
73Returns: OK if authentication succeeded
74 FAIL if authentication failed
75 ERROR some other error condition
76*/
77
78int
1b2adaee 79auth_call_radius(const uschar *s, uschar **errptr)
0756eb3c
PH
80{
81uschar *user;
1b2adaee 82const uschar *radius_args = s;
0756eb3c
PH
83int result;
84int sep = 0;
85
86#ifdef RADIUS_LIB_RADLIB
7766a4f0 87 struct rad_handle *h;
0756eb3c 88#else
7766a4f0
PH
89 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
90 rc_handle *h;
91 #endif
92 VALUE_PAIR *send = NULL;
93 VALUE_PAIR *received;
94 unsigned int service = PW_AUTHENTICATE_ONLY;
95 char msg[4096];
0756eb3c
PH
96#endif
97
98
99user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
8ca559c8 100if (!user) user = US"";
0756eb3c
PH
101
102DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
103 "and \"%s\"\n", user, radius_args);
104
105*errptr = NULL;
106
107
108/* Authenticate using the radiusclient library */
109
7766a4f0 110#ifndef RADIUS_LIB_RADLIB
0756eb3c
PH
111
112rc_openlog("exim");
113
7766a4f0 114#ifdef RADIUS_LIB_RADIUSCLIENT
0756eb3c
PH
115if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
116 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
117
118else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
8ca559c8 119 *errptr = US"RADIUS: can't read dictionary";
0756eb3c 120
8ca559c8
FG
121else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0))
122 *errptr = US"RADIUS: add user name failed";
0756eb3c 123
8ca559c8
FG
124else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0))
125 *errptr = US"RADIUS: add password failed");
0756eb3c 126
8ca559c8
FG
127else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0))
128 *errptr = US"RADIUS: add service type failed";
0756eb3c 129
7766a4f0
PH
130#else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
131
8ca559c8 132if (!(h = rc_read_config(RADIUS_CONFIG_FILE)))
7766a4f0
PH
133 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
134
135else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
8ca559c8 136 *errptr = US"RADIUS: can't read dictionary";
7766a4f0 137
8ca559c8
FG
138else if (!rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0))
139 *errptr = US"RADIUS: add user name failed";
7766a4f0 140
8ca559c8
FG
141else if (!rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
142 Ustrlen(radius_args), 0))
143 *errptr = US"RADIUS: add password failed";
7766a4f0 144
8ca559c8
FG
145else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0))
146 *errptr = US"RADIUS: add service type failed";
7766a4f0
PH
147
148#endif /* RADIUS_LIB_RADIUSCLIENT */
149
8ca559c8 150if (*errptr)
0756eb3c
PH
151 {
152 DEBUG(D_auth) debug_printf("%s\n", *errptr);
153 return ERROR;
154 }
155
7766a4f0 156#ifdef RADIUS_LIB_RADIUSCLIENT
0756eb3c 157result = rc_auth(0, send, &received, msg);
7766a4f0
PH
158#else
159result = rc_auth(h, 0, send, &received, msg);
160#endif
161
0756eb3c
PH
162DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
163
164switch (result)
165 {
166 case OK_RC:
8ca559c8 167 return OK;
0756eb3c 168
860cdda2 169 case REJECT_RC:
0756eb3c 170 case ERROR_RC:
8ca559c8 171 return FAIL;
0756eb3c
PH
172
173 case TIMEOUT_RC:
8ca559c8
FG
174 *errptr = US"RADIUS: timed out";
175 return ERROR;
0756eb3c 176
0756eb3c 177 case BADRESP_RC:
8ca559c8
FG
178 default:
179 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
180 return ERROR;
0756eb3c
PH
181 }
182
7766a4f0 183#else /* RADIUS_LIB_RADLIB is set */
0756eb3c
PH
184
185/* Authenticate using the libradius library */
186
8ca559c8 187if (!(h = rad_auth_open()))
0756eb3c
PH
188 {
189 *errptr = string_sprintf("RADIUS: can't initialise libradius");
190 return ERROR;
191 }
192if (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 ||
b4a9bda2
PH
196 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
197 rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 0)
0756eb3c
PH
198 {
199 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
200 result = ERROR;
201 }
202else
8ca559c8 203 switch (result = rad_send_request(h))
0756eb3c
PH
204 {
205 case RAD_ACCESS_ACCEPT:
8ca559c8
FG
206 result = OK;
207 break;
0756eb3c
PH
208
209 case RAD_ACCESS_REJECT:
8ca559c8
FG
210 result = FAIL;
211 break;
0756eb3c
PH
212
213 case -1:
8ca559c8
FG
214 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
215 result = ERROR;
216 break;
0756eb3c
PH
217
218 default:
8ca559c8
FG
219 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
220 result= ERROR;
221 break;
0756eb3c 222 }
0756eb3c 223
8ca559c8 224if (*errptr) DEBUG(D_auth) debug_printf("%s\n", *errptr);
0756eb3c
PH
225rad_close(h);
226return result;
227
228#endif /* RADIUS_LIB_RADLIB */
229}
230
231#endif /* RADIUS_CONFIG_FILE */
232
233/* End of call_radius.c */