Add support for libradiusclient version 0.4.0 onwards, where they have
[exim.git] / src / src / auths / call_radius.c
1 /* $Cambridge: exim/src/src/auths/call_radius.c,v 1.3 2005/03/29 14:19:21 ph10 Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2005 */
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
11 from Alex Kiernan. */
12
13 #include "../exim.h"
14
15 /* This module contains functions that call the Radius authentication
16 mechanism.
17
18 We can't just compile this code and allow the library mechanism to omit the
19 functions if they are not wanted, because we need to have the Radius headers
20 available for compiling. Therefore, compile these functions only if
21 RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
22 empty modules, so keep them happy with a dummy when skipping the rest. Make it
23 reference itself to stop picky compilers complaining that it is unused, and put
24 in a dummy argument to stop even pickier compilers complaining about infinite
25 loops. */
26
27 #ifndef RADIUS_CONFIG_FILE
28 static void dummy(int x) { dummy(x-1); }
29 #else  /* RADIUS_CONFIG_FILE */
30
31
32 /* Two different Radius libraries are supported. The default is radiusclient,
33 using 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
51 more data strings.
52
53 Arguments:
54   s        a colon-separated list of strings
55   errptr   where to point an error message
56
57 Returns:   OK if authentication succeeded
58            FAIL if authentication failed
59            ERROR some other error condition
60 */
61
62 int
63 auth_call_radius(uschar *s, uschar **errptr)
64 {
65 uschar *user;
66 uschar *radius_args = s;
67 int result;
68 int 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
83 user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
84 if (user == NULL) user = US"";
85
86 DEBUG(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
96 rc_openlog("exim");
97
98 #ifdef RADIUS_LIB_RADIUSCLIENT
99 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
100   *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
101
102 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
103   *errptr = string_sprintf("RADIUS: can't read dictionary");
104
105 else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL)
106   *errptr = string_sprintf("RADIUS: add user name failed\n");
107
108 else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL)
109   *errptr = string_sprintf("RADIUS: add password failed\n");
110
111 else 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
116 if ((h = rc_read_config(RADIUS_CONFIG_FILE)) != 0)
117   *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
118
119 else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
120   *errptr = string_sprintf("RADIUS: can't read dictionary");
121
122 else if (rc_avpair_add(h, &send, PW_USER_NAME, user, 0, 0) == NULL)
123   *errptr = string_sprintf("RADIUS: add user name failed\n");
124
125 else 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
128 else 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
133 if (*errptr != NULL)
134   {
135   DEBUG(D_auth) debug_printf("%s\n", *errptr);
136   return ERROR;
137   }
138
139 #ifdef RADIUS_LIB_RADIUSCLIENT
140 result = rc_auth(0, send, &received, msg);
141 #else
142 result = rc_auth(h, 0, send, &received, msg);
143 #endif
144
145 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
146
147 switch (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
165 #else  /* RADIUS_LIB_RADLIB is set */
166
167 /* Authenticate using the libradius library */
168
169 h = rad_auth_open();
170 if (h == NULL)
171   {
172   *errptr = string_sprintf("RADIUS: can't initialise libradius");
173   return ERROR;
174   }
175 if (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   }
184 else
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
210 if (*errptr != NULL) DEBUG(D_auth) debug_printf("%s\n", *errptr);
211 rad_close(h);
212 return result;
213
214 #endif  /* RADIUS_LIB_RADLIB */
215 }
216
217 #endif  /* RADIUS_CONFIG_FILE */
218
219 /* End of call_radius.c */