(1) Typo in redirect router; (2) Update version number; (3) Update
[exim.git] / src / src / auths / call_radius.c
1 /* $Cambridge: exim/src/src/auths/call_radius.c,v 1.2 2005/01/04 10:00:43 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
34 #ifdef RADIUS_LIB_RADLIB
35   #include <radlib.h>
36 #else
37   #ifndef RADIUS_LIB_RADIUSCLIENT
38   #define RADIUS_LIB_RADIUSCLIENT
39   #endif
40   #include <radiusclient.h>
41 #endif
42
43
44
45 /*************************************************
46 *              Perform RADIUS authentication     *
47 *************************************************/
48
49 /* This function calls the Radius authentication mechanism, passing over one or
50 more data strings.
51
52 Arguments:
53   s        a colon-separated list of strings
54   errptr   where to point an error message
55
56 Returns:   OK if authentication succeeded
57            FAIL if authentication failed
58            ERROR some other error condition
59 */
60
61 int
62 auth_call_radius(uschar *s, uschar **errptr)
63 {
64 uschar *user;
65 uschar *radius_args = s;
66 int result;
67 int sep = 0;
68
69 #ifdef RADIUS_LIB_RADLIB
70 struct rad_handle *h;
71 #else
72 VALUE_PAIR *send = NULL;
73 VALUE_PAIR *received;
74 unsigned int service = PW_AUTHENTICATE_ONLY;
75 char msg[4096];
76 #endif
77
78
79 user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
80 if (user == NULL) user = US"";
81
82 DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
83                "and \"%s\"\n", user, radius_args);
84
85 *errptr = NULL;
86
87
88 /* Authenticate using the radiusclient library */
89
90 #ifdef RADIUS_LIB_RADIUSCLIENT
91
92 rc_openlog("exim");
93
94 if (rc_read_config(RADIUS_CONFIG_FILE) != 0)
95   *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE);
96
97 else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
98   *errptr = string_sprintf("RADIUS: can't read dictionary");
99
100 else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL)
101   *errptr = string_sprintf("RADIUS: add user name failed\n");
102
103 else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL)
104   *errptr = string_sprintf("RADIUS: add password failed\n");
105
106 else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
107   *errptr = string_sprintf("RADIUS: add service type failed\n");
108
109 if (*errptr != NULL)
110   {
111   DEBUG(D_auth) debug_printf("%s\n", *errptr);
112   return ERROR;
113   }
114
115 result = rc_auth(0, send, &received, msg);
116 DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result);
117
118 switch (result)
119   {
120   case OK_RC:
121   return OK;
122
123   case ERROR_RC:
124   return FAIL;
125
126   case TIMEOUT_RC:
127   *errptr = US"RADIUS: timed out";
128   return ERROR;
129
130   default:
131   case BADRESP_RC:
132   *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
133   return ERROR;
134   }
135
136 #else  /* RADIUS_LIB_RADIUSCLIENT not set => RADIUS_LIB_RADLIB is set */
137
138 /* Authenticate using the libradius library */
139
140 h = rad_auth_open();
141 if (h == NULL)
142   {
143   *errptr = string_sprintf("RADIUS: can't initialise libradius");
144   return ERROR;
145   }
146 if (rad_config(h, RADIUS_CONFIG_FILE) != 0 ||
147     rad_create_request(h, RAD_ACCESS_REQUEST) != 0 ||
148     rad_put_string(h, RAD_USER_NAME, CS user) != 0 ||
149     rad_put_string(h, RAD_USER_PASSWORD, CS radius_args) != 0 ||
150     rad_put_int(h, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) != 0)
151   {
152   *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
153   result = ERROR;
154   }
155 else
156   {
157   result = rad_send_request(h);
158
159   switch(result)
160     {
161     case RAD_ACCESS_ACCEPT:
162     result = OK;
163     break;
164
165     case RAD_ACCESS_REJECT:
166     result = FAIL;
167     break;
168
169     case -1:
170     *errptr = string_sprintf("RADIUS: %s", rad_strerror(h));
171     result = ERROR;
172     break;
173
174     default:
175     *errptr = string_sprintf("RADIUS: unexpected response (%d)", result);
176     result= ERROR;
177     break;
178     }
179   }
180
181 if (*errptr != NULL) DEBUG(D_auth) debug_printf("%s\n", *errptr);
182 rad_close(h);
183 return result;
184
185 #endif  /* RADIUS_LIB_RADLIB */
186 }
187
188 #endif  /* RADIUS_CONFIG_FILE */
189
190 /* End of call_radius.c */