4.53 TK/04
[exim.git] / src / src / auths / call_radius.c
CommitLineData
7766a4f0 1/* $Cambridge: exim/src/src/auths/call_radius.c,v 1.3 2005/03/29 14:19:21 ph10 Exp $ */
0756eb3c
PH
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
6
c988f1f4 7/* Copyright (c) University of Cambridge 1995 - 2005 */
0756eb3c
PH
8/* See the file NOTICE for conditions of use and distribution. */
9
10/* This file was originally supplied by Ian Kirk. The libradius support came
11from Alex Kiernan. */
12
13#include "../exim.h"
14
15/* This module contains functions that call the Radius authentication
16mechanism.
17
18We can't just compile this code and allow the library mechanism to omit the
19functions if they are not wanted, because we need to have the Radius headers
20available for compiling. Therefore, compile these functions only if
21RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
22empty modules, so keep them happy with a dummy when skipping the rest. Make it
23reference itself to stop picky compilers complaining that it is unused, and put
24in a dummy argument to stop even pickier compilers complaining about infinite
25loops. */
26
27#ifndef RADIUS_CONFIG_FILE
28static void dummy(int x) { dummy(x-1); }
29#else /* RADIUS_CONFIG_FILE */
30
31
7766a4f0
PH
32/* Two different Radius libraries are supported. The default is radiusclient,
33using its original API. At release 0.4.0 the API changed. */
0756eb3c
PH
34
35#ifdef RADIUS_LIB_RADLIB
36 #include <radlib.h>
37#else
7766a4f0 38 #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
0756eb3c
PH
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
7766a4f0 71 struct rad_handle *h;
0756eb3c 72#else
7766a4f0
PH
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];
0756eb3c
PH
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
7766a4f0 94#ifndef RADIUS_LIB_RADLIB
0756eb3c
PH
95
96rc_openlog("exim");
97
7766a4f0 98#ifdef RADIUS_LIB_RADIUSCLIENT
0756eb3c
PH
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
7766a4f0
PH
114#else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
115
116if ((h = rc_read_config(RADIUS_CONFIG_FILE)) != 0)
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, 0, 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, 0, 0) == NULL)
126 *errptr = string_sprintf("RADIUS: add password failed\n");
127
128else if (rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0) == NULL)
129 *errptr = string_sprintf("RADIUS: add service type failed\n");
130
131#endif /* RADIUS_LIB_RADIUSCLIENT */
132
0756eb3c
PH
133if (*errptr != NULL)
134 {
135 DEBUG(D_auth) debug_printf("%s\n", *errptr);
136 return ERROR;
137 }
138
7766a4f0 139#ifdef RADIUS_LIB_RADIUSCLIENT
0756eb3c 140result = rc_auth(0, send, &received, msg);
7766a4f0
PH
141#else
142result = rc_auth(h, 0, send, &received, msg);
143#endif
144
0756eb3c
PH
145DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
146
147switch (result)
148 {
149 case OK_RC:
150 return OK;
151
152 case ERROR_RC:
153 return FAIL;
154
155 case TIMEOUT_RC:
156 *errptr = US"RADIUS: timed out";
157 return ERROR;
158
159 default:
160 case BADRESP_RC:
161 *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
162 return ERROR;
163 }
164
7766a4f0 165#else /* RADIUS_LIB_RADLIB is set */
0756eb3c
PH
166
167/* Authenticate using the libradius library */
168
169h = rad_auth_open();
170if (h == NULL)
171 {
172 *errptr = string_sprintf("RADIUS: can't initialise libradius");
173 return ERROR;
174 }
175if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
176 rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
177 rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
178 rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
179 rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0)
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 */