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