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