1 |
/* This file is part of GNU RADIUS. |
/* This file is part of GNU Radius. |
2 |
Copyright (C) 2000, Sergey Poznyakoff |
Copyright (C) 2000, 2002, 2003, Sergey Poznyakoff |
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
GNU Radius is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2 of the License, or |
the Free Software Foundation; either version 2 of the License, or |
7 |
(at your option) any later version. |
(at your option) any later version. |
8 |
|
|
9 |
This program is distributed in the hope that it will be useful, |
GNU Radius is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
GNU General Public License for more details. |
13 |
|
|
14 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
15 |
along with this program; if not, write to the Free Software Foundation, |
along with GNU Radius; if not, write to the Free Software Foundation, |
16 |
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
17 |
|
|
18 |
#define RADIUS_MODULE_RADIUS_C |
#define RADIUS_MODULE_RADIUS_C |
37 |
is used instead of the supplied arguments. */ |
is used instead of the supplied arguments. */ |
38 |
|
|
39 |
void |
void |
40 |
rad_send_reply(code, radreq, reply_pairs, msg, fd) |
radius_send_reply(int code, RADIUS_REQ *radreq, |
41 |
int code; |
VALUE_PAIR *reply_pairs, char *msg, int fd) |
|
RADIUS_REQ *radreq; |
|
|
VALUE_PAIR *reply_pairs; |
|
|
char *msg; |
|
|
int fd; |
|
42 |
{ |
{ |
43 |
if (radreq->reply_code == 0) { |
if (radreq->reply_code == 0) { |
44 |
VALUE_PAIR *reply; |
VALUE_PAIR *reply; |
77 |
state -- Value of the State attribute. |
state -- Value of the State attribute. |
78 |
fd -- Socket descriptor. */ |
fd -- Socket descriptor. */ |
79 |
void |
void |
80 |
send_challenge(radreq, msg, state, fd) |
radius_send_challenge(RADIUS_REQ *radreq, char *msg, char *state, int fd) |
|
RADIUS_REQ *radreq; |
|
|
char *msg; |
|
|
char *state; |
|
|
int fd; |
|
81 |
{ |
{ |
82 |
radreq->reply_pairs = NULL; |
radreq->reply_pairs = NULL; |
83 |
avl_move_attr(&radreq->reply_pairs, &radreq->request, DA_PROXY_STATE); |
avl_move_attr(&radreq->reply_pairs, &radreq->request, DA_PROXY_STATE); |
87 |
#endif |
#endif |
88 |
|
|
89 |
/* Validates the requesting client NAS. */ |
/* Validates the requesting client NAS. */ |
90 |
int |
static int |
91 |
validate_client(radreq) |
validate_client(RADIUS_REQ *radreq) |
|
RADIUS_REQ *radreq; |
|
92 |
{ |
{ |
93 |
CLIENT *cl; |
CLIENT *cl; |
94 |
|
|
105 |
|
|
106 |
/* Validates the requesting NAS */ |
/* Validates the requesting NAS */ |
107 |
int |
int |
108 |
calc_acctdigest(radreq) |
radius_verify_digest(REQUEST *req) |
|
RADIUS_REQ *radreq; |
|
109 |
{ |
{ |
110 |
int secretlen; |
RADIUS_REQ *radreq = req->data; |
111 |
|
size_t len = req->rawsize; |
112 |
|
int secretlen; |
113 |
char zero[AUTH_VECTOR_LEN]; |
char zero[AUTH_VECTOR_LEN]; |
114 |
u_char *recvbuf; |
u_char *recvbuf; |
|
int len = radreq->data_len; |
|
115 |
u_char digest[AUTH_VECTOR_LEN]; |
u_char digest[AUTH_VECTOR_LEN]; |
116 |
|
|
117 |
secretlen = strlen(radreq->secret); |
secretlen = strlen(radreq->secret); |
118 |
|
|
119 |
recvbuf = emalloc(len + secretlen); |
recvbuf = emalloc(len + secretlen); |
120 |
memcpy(recvbuf, radreq->data, len + secretlen); |
memcpy(recvbuf, req->rawdata, len + secretlen); |
121 |
|
|
122 |
/* Older clients have the authentication vector set to |
/* Older clients have the authentication vector set to |
123 |
all zeros. Return `1' in that case. */ |
all zeros. Return `1' in that case. */ |
138 |
REQ_AUTH_BAD : REQ_AUTH_OK; |
REQ_AUTH_BAD : REQ_AUTH_OK; |
139 |
} |
} |
140 |
|
|
141 |
|
|
142 |
|
/* *********************** Radius Protocol Support ************************* */ |
143 |
|
|
144 |
|
int |
145 |
|
radius_req_decode(struct sockaddr_in *sa, |
146 |
|
void *input, size_t inputsize, void **output) |
147 |
|
{ |
148 |
|
RADIUS_REQ *radreq; |
149 |
|
|
150 |
|
radreq = rad_decode_pdu(ntohl(sa->sin_addr.s_addr), |
151 |
|
ntohs(sa->sin_port), |
152 |
|
input, |
153 |
|
inputsize); |
154 |
|
if (!radreq) |
155 |
|
return 1; |
156 |
|
*output = radreq; |
157 |
|
return 0; |
158 |
|
} |
159 |
|
|
160 |
|
static VALUE_PAIR * |
161 |
|
_extract_pairs(RADIUS_REQ *req, int prop) |
162 |
|
{ |
163 |
|
static int attrlist[] = { DA_USER_PASSWORD, DA_CHAP_PASSWORD }; |
164 |
|
int i; |
165 |
|
VALUE_PAIR *newlist = NULL; |
166 |
|
VALUE_PAIR *pair; |
167 |
|
char password[AUTH_STRING_LEN+1]; |
168 |
|
|
169 |
|
for (pair = req->request; pair; pair = pair->next) |
170 |
|
for (i = 0; i < NITEMS(attrlist); i++) { |
171 |
|
if (pair->attribute == attrlist[i] |
172 |
|
&& (pair->prop & prop)) |
173 |
|
break; |
174 |
|
} |
175 |
|
|
176 |
|
if (!pair) |
177 |
|
return NULL; |
178 |
|
|
179 |
|
newlist = avl_dup(req->request); |
180 |
|
for (pair = newlist; pair; pair = pair->next) |
181 |
|
for (i = 0; i < NITEMS(attrlist); i++) { |
182 |
|
if (pair->attribute == attrlist[i] |
183 |
|
&& (pair->prop & prop)) { |
184 |
|
req_decrypt_password(password, req, pair); |
185 |
|
string_free(pair->avp_strvalue); |
186 |
|
pair->avp_strvalue = string_create(password); |
187 |
|
pair->avp_strlength = strlen(pair->avp_strvalue); |
188 |
|
} |
189 |
|
} |
190 |
|
return newlist; |
191 |
|
} |
192 |
|
|
193 |
|
int |
194 |
|
radius_req_cmp(void *adata, void *bdata) |
195 |
|
{ |
196 |
|
RADIUS_REQ *a = adata; |
197 |
|
RADIUS_REQ *b = bdata; |
198 |
|
int prop = 0; |
199 |
|
VALUE_PAIR *alist = NULL, *blist = NULL, *ap, *bp; |
200 |
|
int rc; |
201 |
|
NAS *nas; |
202 |
|
|
203 |
|
if (a->ipaddr != b->ipaddr || a->code != b->code) |
204 |
|
return 1; |
205 |
|
|
206 |
|
if (a->id == b->id |
207 |
|
&& memcmp(a->vector, b->vector, sizeof(a->vector)) == 0) |
208 |
|
return 0; |
209 |
|
|
210 |
|
if (nas = nas_request_to_nas(a)) |
211 |
|
prop = envar_lookup_int(nas->args, "compare-atribute-flag", 0); |
212 |
|
|
213 |
|
if (!prop) { |
214 |
|
switch (a->code) { |
215 |
|
case RT_AUTHENTICATION_REQUEST: |
216 |
|
case RT_AUTHENTICATION_ACK: |
217 |
|
case RT_AUTHENTICATION_REJECT: |
218 |
|
case RT_ACCESS_CHALLENGE: |
219 |
|
prop = auth_comp_flag; |
220 |
|
break; |
221 |
|
|
222 |
|
case RT_ACCOUNTING_REQUEST: |
223 |
|
case RT_ACCOUNTING_RESPONSE: |
224 |
|
case RT_ACCOUNTING_STATUS: |
225 |
|
case RT_ACCOUNTING_MESSAGE: |
226 |
|
prop = acct_comp_flag; |
227 |
|
break; |
228 |
|
} |
229 |
|
} |
230 |
|
|
231 |
|
if (prop == 0) |
232 |
|
return 1; |
233 |
|
|
234 |
|
prop |= AP_REQ_CMP; |
235 |
|
alist = _extract_pairs(a, prop); |
236 |
|
blist = _extract_pairs(b, prop); |
237 |
|
|
238 |
|
ap = alist ? alist : a->request; |
239 |
|
bp = blist ? blist : b->request; |
240 |
|
|
241 |
|
rc = avl_cmp(ap, bp, prop) || avl_cmp(bp, ap, prop); |
242 |
|
|
243 |
|
avl_free(alist); |
244 |
|
avl_free(blist); |
245 |
|
return rc; |
246 |
|
} |
247 |
|
|
248 |
|
void |
249 |
|
radius_req_free(void *req) |
250 |
|
{ |
251 |
|
debug(1,("enter: %p",req)); |
252 |
|
radreq_free((RADIUS_REQ *)req); |
253 |
|
debug(1,("exit")); |
254 |
|
} |
255 |
|
|
256 |
|
/*ARGSUSED*/ |
257 |
|
void |
258 |
|
radius_req_drop(int type, void *data, void *orig_data, |
259 |
|
int fd, char *status_str) |
260 |
|
{ |
261 |
|
RADIUS_REQ *radreq = data ? data : orig_data; |
262 |
|
RADIUS_REQ *origreq = orig_data; |
263 |
|
char buf[MAX_LONGNAME]; |
264 |
|
|
265 |
|
radlog_req(L_NOTICE, radreq, |
266 |
|
"%s: %s", _("Dropping packet"), status_str); |
267 |
|
|
268 |
|
switch (type) { |
269 |
|
case R_AUTH: |
270 |
|
stat_inc(auth, radreq->ipaddr, num_dropped); |
271 |
|
break; |
272 |
|
case R_ACCT: |
273 |
|
stat_inc(acct, radreq->ipaddr, num_dropped); |
274 |
|
} |
275 |
|
} |
276 |
|
|
277 |
|
void |
278 |
|
radius_req_xmit(REQUEST *request) |
279 |
|
{ |
280 |
|
RADIUS_REQ *req = request->data; |
281 |
|
|
282 |
|
if (request->code == 0) { |
283 |
|
radius_send_reply(0, req, NULL, NULL, request->fd); |
284 |
|
radlog_req(L_NOTICE, req, _("Retransmitting %s reply"), |
285 |
|
request_class[request->type].name); |
286 |
|
} else { |
287 |
|
radius_req_drop(request->type, NULL, req, request->fd, |
288 |
|
_("request failed")); |
289 |
|
} |
290 |
|
} |
291 |
|
|
292 |
|
int |
293 |
|
radius_req_failure(int type, struct sockaddr_in *addr) |
294 |
|
{ |
295 |
|
/*FIXME: should do: |
296 |
|
stat_inc(acct or auth, ntohl(addr->sin_addr.s_addr), num_bad_req);*/ |
297 |
|
return 0; |
298 |
|
} |
299 |
|
|
300 |
|
int |
301 |
|
radius_respond(REQUEST *req) |
302 |
|
{ |
303 |
|
int rc; |
304 |
|
RADIUS_REQ *radreq = req->data; |
305 |
|
|
306 |
|
if (suspend_flag) |
307 |
|
return 1; |
308 |
|
|
309 |
|
if (validate_client(radreq)) { |
310 |
|
/*FIXME: update stats */ |
311 |
|
return -1; |
312 |
|
} |
313 |
|
|
314 |
|
/* Check if we support this request */ |
315 |
|
switch (radreq->code) { |
316 |
|
case RT_AUTHENTICATION_REQUEST: |
317 |
|
stat_inc(auth, radreq->ipaddr, num_access_req); |
318 |
|
if (rad_auth_init(radreq, req->fd) < 0) |
319 |
|
return 1; |
320 |
|
/*FALLTHRU*/ |
321 |
|
case RT_ACCOUNTING_REQUEST: |
322 |
|
if (avl_find(radreq->request, DA_USER_NAME) == NULL) |
323 |
|
break; |
324 |
|
if (proxy_send(radreq, req->fd) != 0) { |
325 |
|
req->type = R_PROXY; |
326 |
|
return 0; |
327 |
|
} |
328 |
|
break; |
329 |
|
|
330 |
|
case RT_AUTHENTICATION_ACK: |
331 |
|
case RT_AUTHENTICATION_REJECT: |
332 |
|
case RT_ACCOUNTING_RESPONSE: |
333 |
|
case RT_ACCESS_CHALLENGE: |
334 |
|
if (proxy_receive(radreq, req->fd) < 0) { |
335 |
|
return 1; |
336 |
|
} |
337 |
|
break; |
338 |
|
} |
339 |
|
|
340 |
|
switch (radreq->code) { |
341 |
|
case RT_AUTHENTICATION_REQUEST: |
342 |
|
rad_authenticate(radreq, req->fd); |
343 |
|
break; |
344 |
|
|
345 |
|
case RT_ACCOUNTING_REQUEST: |
346 |
|
/* Check the request authenticator. */ |
347 |
|
rc = radius_verify_digest(req); |
348 |
|
if (rc == REQ_AUTH_BAD) |
349 |
|
stat_inc(acct, radreq->ipaddr, num_bad_sign); |
350 |
|
rad_accounting(radreq, req->fd, rc); |
351 |
|
break; |
352 |
|
|
353 |
|
default: |
354 |
|
stat_inc(acct, radreq->ipaddr, num_unknowntypes); |
355 |
|
radlog_req(L_NOTICE, radreq, _("unknown request code %d"), |
356 |
|
radreq->code); |
357 |
|
return -1; |
358 |
|
} |
359 |
|
return 0; |
360 |
|
} |