Remove obsolete $Cambridge$ CVS revision strings.
[exim.git] / src / src / auths / call_radius.c
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
9 from Alex Kiernan. */
10
11 #include "../exim.h"
12
13 /* This module contains functions that call the Radius authentication
14 mechanism.
15
16 We can't just compile this code and allow the library mechanism to omit the
17 functions if they are not wanted, because we need to have the Radius headers
18 available for compiling. Therefore, compile these functions only if
19 RADIUS_CONFIG_FILE is defined. However, some compilers don't like compiling
20 empty modules, so keep them happy with a dummy when skipping the rest. Make it
21 reference itself to stop picky compilers complaining that it is unused, and put
22 in a dummy argument to stop even pickier compilers complaining about infinite
23 loops. */
24
25 #ifndef RADIUS_CONFIG_FILE
26 static void dummy(int x) { dummy(x-1); }
27 #else  /* RADIUS_CONFIG_FILE */
28
29
30 /* Two different Radius libraries are supported. The default is radiusclient,
31 using its original API. At release 0.4.0 the API changed. */
32
33 #ifdef RADIUS_LIB_RADLIB
34   #include <radlib.h>
35 #else
36   #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
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
49 more data strings.
50
51 Arguments:
52   s        a colon-separated list of strings
53   errptr   where to point an error message
54
55 Returns:   OK if authentication succeeded
56            FAIL if authentication failed
57            ERROR some other error condition
58 */
59
60 int
61 auth_call_radius(uschar *s, uschar **errptr)
62 {
63 uschar *user;
64 uschar *radius_args = s;
65 int result;
66 int sep = 0;
67
68 #ifdef RADIUS_LIB_RADLIB
69   struct rad_handle *h;
70 #else
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];
78 #endif
79
80
81 user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
82 if (user == NULL) user = US"";
83
84 DEBUG(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
92 #ifndef RADIUS_LIB_RADLIB
93
94 rc_openlog("exim");
95
96 #ifdef RADIUS_LIB_RADIUSCLIENT
97 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
98   *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
99
100 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
101   *errptr = string_sprintf("RADIUS: can't read dictionary");
102
103 else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL)
104   *errptr = string_sprintf("RADIUS: add user name failed\n");
105
106 else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL)
107   *errptr = string_sprintf("RADIUS: add password failed\n");
108
109 else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
110   *errptr = string_sprintf("RADIUS: add service type failed\n");
111
112 #else  /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */
113
114 if ((h = rc_read_config(RADIUS_CONFIG_FILE)) == NULL)
115   *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
116
117 else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0)
118   *errptr = string_sprintf("RADIUS: can't read dictionary");
119
120 else if (rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0) == NULL)
121   *errptr = string_sprintf("RADIUS: add user name failed\n");
122
123 else if (rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args,
124     Ustrlen(radius_args), 0) == NULL)
125   *errptr = string_sprintf("RADIUS: add password failed\n");
126
127 else 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
132 if (*errptr != NULL)
133   {
134   DEBUG(D_auth) debug_printf("%s\n", *errptr);
135   return ERROR;
136   }
137
138 #ifdef RADIUS_LIB_RADIUSCLIENT
139 result = rc_auth(0, send, &received, msg);
140 #else
141 result = rc_auth(h, 0, send, &received, msg);
142 #endif
143
144 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
145
146 switch (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
164 #else  /* RADIUS_LIB_RADLIB is set */
165
166 /* Authenticate using the libradius library */
167
168 h = rad_auth_open();
169 if (h == NULL)
170   {
171   *errptr = string_sprintf("RADIUS: can't initialise libradius");
172   return ERROR;
173   }
174 if (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 ||
178     rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0 ||
179     rad_put_string(h, RAD_NAS_IDENTIFIER, CS primary_hostname) != 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 */