Imported Upstream version 4.84
[hcoop/debian/exim4.git] / src / auths / call_radius.c
CommitLineData
420a0d19
CE
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
5/* Copyright (c) University of Cambridge 1995 - 2009 */
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. Then use a mutually-recursive pair as gcc is just getting stupid. */
24
25#ifndef RADIUS_CONFIG_FILE
26static void dummy(int x);
27static void dummy2(int x) { dummy(x-1); }
28static void dummy(int x) { dummy2(x-1); }
29#else /* RADIUS_CONFIG_FILE */
30
31
32/* Two different Radius libraries are supported. The default is radiusclient,
33using its original API. At release 0.4.0 the API changed. */
34
35#ifdef RADIUS_LIB_RADLIB
36 #include <radlib.h>
37#else
38 #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
39 #define RADIUS_LIB_RADIUSCLIENT
40 #endif
41 #include <radiusclient.h>
42#endif
43
44
45
46/*************************************************
47* Perform RADIUS authentication *
48*************************************************/
49
50/* This function calls the Radius authentication mechanism, passing over one or
51more data strings.
52
53Arguments:
54 s a colon-separated list of strings
55 errptr where to point an error message
56
57Returns: OK if authentication succeeded
58 FAIL if authentication failed
59 ERROR some other error condition
60*/
61
62int
63auth_call_radius(uschar *s, uschar **errptr)
64{
65uschar *user;
66uschar *radius_args = s;
67int result;
68int sep = 0;
69
70#ifdef RADIUS_LIB_RADLIB
71 struct rad_handle *h;
72#else
73 #ifdef RADIUS_LIB_RADIUSCLIENTNEW
74 rc_handle *h;
75 #endif
76 VALUE_PAIR *send = NULL;
77 VALUE_PAIR *received;
78 unsigned int service = PW_AUTHENTICATE_ONLY;
79 char msg[4096];
80#endif
81
82
83user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
84if (user == NULL) user = US"";
85
86DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
87 "and \"%s\"\n", user, radius_args);
88
89*errptr = NULL;
90
91
92/* Authenticate using the radiusclient library */
93
94#ifndef RADIUS_LIB_RADLIB
95
96rc_openlog("exim");
97
98#ifdef RADIUS_LIB_RADIUSCLIENT
99if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
100 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
101
102else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
103 *errptr = string_sprintf("RADIUS: can't read dictionary");
104
105else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL)
106 *errptr = string_sprintf("RADIUS: add user name failed\n");
107
108else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL)
109 *errptr = string_sprintf("RADIUS: add password failed\n");
110
111else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
112 *errptr = string_sprintf("RADIUS: add service type failed\n");
113
114#else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
115
116if ((h = rc_read_config(RADIUS_CONFIG_FILE)) == NULL)
117 *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
118
119else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
120 *errptr = string_sprintf("RADIUS: can't read dictionary");
121
122else if (rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0) == NULL)
123 *errptr = string_sprintf("RADIUS: add user name failed\n");
124
125else if (rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
126 Ustrlen(radius_args), 0) == NULL)
127 *errptr = string_sprintf("RADIUS: add password failed\n");
128
129else if (rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0) == NULL)
130 *errptr = string_sprintf("RADIUS: add service type failed\n");
131
132#endif /* RADIUS_LIB_RADIUSCLIENT */
133
134if (*errptr != NULL)
135 {
136 DEBUG(D_auth) debug_printf("%s\n", *errptr);
137 return ERROR;
138 }
139
140#ifdef RADIUS_LIB_RADIUSCLIENT
141result = rc_auth(0, send, &received, msg);
142#else
143result = rc_auth(h, 0, send, &received, msg);
144#endif
145
146DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
147
148switch (result)
149 {
150 case OK_RC:
151 return OK;
152
153 case ERROR_RC:
154 return FAIL;
155
156 case TIMEOUT_RC:
157 *errptr = US"RADIUS: timed out";
158 return ERROR;
159
160 default:
161 case BADRESP_RC:
162 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
163 return ERROR;
164 }
165
166#else /* RADIUS_LIB_RADLIB is set */
167
168/* Authenticate using the libradius library */
169
170h = rad_auth_open();
171if (h == NULL)
172 {
173 *errptr = string_sprintf("RADIUS: can't initialise libradius");
174 return ERROR;
175 }
176if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
177 rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
178 rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
179 rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
180 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
181 rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 0)
182 {
183 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
184 result = ERROR;
185 }
186else
187 {
188 result = rad_send_request(h);
189
190 switch(result)
191 {
192 case RAD_ACCESS_ACCEPT:
193 result = OK;
194 break;
195
196 case RAD_ACCESS_REJECT:
197 result = FAIL;
198 break;
199
200 case -1:
201 *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
202 result = ERROR;
203 break;
204
205 default:
206 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
207 result= ERROR;
208 break;
209 }
210 }
211
212if (*errptr != NULL) DEBUG(D_auth) debug_printf("%s\n", *errptr);
213rad_close(h);
214return result;
215
216#endif /* RADIUS_LIB_RADLIB */
217}
218
219#endif /* RADIUS_CONFIG_FILE */
220
221/* End of call_radius.c */