45 |
|
|
46 |
static PROXY_ID *proxy_id; |
static PROXY_ID *proxy_id; |
47 |
|
|
48 |
void proxy_addrequest(RADIUS_REQ *radreq); |
/* ************************************************************************* */ |
49 |
static void passwd_recode(VALUE_PAIR *pair, |
/* Functions local to this module */ |
50 |
char *new_secret, char *new_vector, RADIUS_REQ *req); |
|
51 |
static int proxy_send_request(int fd, RADIUS_REQ *radreq); |
static UINT4 |
52 |
static UINT4 get_socket_addr(int fd); |
get_socket_addr(int fd) |
53 |
|
{ |
54 |
|
struct sockaddr_in sin; |
55 |
|
int len = sizeof(sin); |
56 |
|
UINT4 ip = 0; |
57 |
|
|
58 |
|
if (getsockname(fd, (struct sockaddr*)&sin, &len) == 0) |
59 |
|
ip = sin.sin_addr.s_addr; |
60 |
|
|
61 |
|
if (ip == INADDR_ANY) |
62 |
|
ip = ref_ip; |
63 |
|
return ip; |
64 |
|
} |
65 |
|
|
66 |
|
|
67 |
|
/* |
68 |
|
* Decode a password and encode it again. |
69 |
|
*/ |
70 |
|
static void |
71 |
|
passwd_recode(VALUE_PAIR *pass_pair, char *new_secret, char *new_vector, |
72 |
|
RADIUS_REQ *req) |
73 |
|
{ |
74 |
|
char password[AUTH_STRING_LEN+1]; |
75 |
|
req_decrypt_password(password, req, pass_pair); |
76 |
|
string_free(pass_pair->avp_strvalue); |
77 |
|
encrypt_password(pass_pair, password, new_vector, new_secret); |
78 |
|
/* Don't let the cleantext hang around */ |
79 |
|
memset(password, 0, AUTH_STRING_LEN); |
80 |
|
} |
81 |
|
|
82 |
|
/* ************************************************************************* */ |
83 |
|
/* Functions for finding the matching request in the list of outstanding ones. |
84 |
|
* There appear to be two cases: i) when the remote server retains the |
85 |
|
* Proxy-State A/V pair, which seems to correspond to RFC 2865, |
86 |
|
* and ii) when the remote server drops the Proxy-State pair. |
87 |
|
*/ |
88 |
|
|
89 |
|
int |
90 |
|
proxy_cmp(RADIUS_REQ *qr, RADIUS_REQ *r) |
91 |
|
{ |
92 |
|
VALUE_PAIR *p, *proxy_state_pair = NULL; |
93 |
|
PROXY_STATE *state; |
94 |
|
|
95 |
|
if (!qr->server) { |
96 |
|
debug(100,("no proxy server")); |
97 |
|
return 1; |
98 |
|
} |
99 |
|
/* Find the last PROXY_STATE attribute. */ |
100 |
|
for (p = r->request; p; p = p->next) { |
101 |
|
if (p->attribute == DA_PROXY_STATE) |
102 |
|
proxy_state_pair = p; |
103 |
|
} |
104 |
|
|
105 |
|
state = proxy_state_pair ? |
106 |
|
(PROXY_STATE *)proxy_state_pair->avp_strvalue : NULL; |
107 |
|
|
108 |
|
if (state) { |
109 |
|
debug(1, |
110 |
|
("state: ipaddr %08x, id %u, proxy_id %u, rem_ipaddr %08x", |
111 |
|
state->ipaddr, |
112 |
|
state->id, |
113 |
|
state->proxy_id, |
114 |
|
state->rem_ipaddr)); |
115 |
|
|
116 |
|
if (state->proxy_id == r->id |
117 |
|
&& state->rem_ipaddr == r->ipaddr) { |
118 |
|
debug(10, ("(old=data) id %d %d, ipaddr %#8x %#8x, proxy_id %d %d, server_addr %#8x %#8x", |
119 |
|
qr->id, state->id, |
120 |
|
qr->ipaddr, state->ipaddr, |
121 |
|
qr->server_id, state->proxy_id, |
122 |
|
qr->server->addr, state->rem_ipaddr)); |
123 |
|
|
124 |
|
if (state->ipaddr == qr->ipaddr |
125 |
|
&& state->id == qr->id |
126 |
|
&& state->proxy_id == qr->server_id |
127 |
|
&& state->rem_ipaddr == qr->server->addr) { |
128 |
|
debug(1,("EQUAL!!!")); |
129 |
|
return 0; |
130 |
|
} |
131 |
|
} |
132 |
|
} else if (qr->server_id) { |
133 |
|
debug(10, ("(old=data) id %d %d, ipaddr %#8x %#8x", |
134 |
|
qr->server_id, |
135 |
|
r->id, |
136 |
|
qr->server->addr, |
137 |
|
r->ipaddr)); |
138 |
|
|
139 |
|
if (r->ipaddr == qr->server->addr |
140 |
|
&& r->id == qr->server_id) |
141 |
|
return 0; |
142 |
|
} |
143 |
|
return 1; |
144 |
|
} |
145 |
|
|
146 |
/* ************************************************************************* */ |
/* ************************************************************************* */ |
147 |
/* Proxy-Id functions */ |
/* Proxy-Id functions */ |
162 |
* If we don't have one, create it and initialize to zero. |
* If we don't have one, create it and initialize to zero. |
163 |
*/ |
*/ |
164 |
u_char |
u_char |
165 |
next_proxy_id(ipaddr) |
next_proxy_id(UINT4 ipaddr) |
|
UINT4 ipaddr; |
|
166 |
{ |
{ |
167 |
PROXY_ID *p; |
PROXY_ID *p; |
168 |
|
|
169 |
for (p = proxy_id; p; p = p->next) |
for (p = proxy_id; p; p = p->next) |
170 |
if (p->ipaddr == ipaddr) |
if (p->ipaddr == ipaddr) |
171 |
break; |
break; |
201 |
} |
} |
202 |
|
|
203 |
/* ************************************************************************* */ |
/* ************************************************************************* */ |
|
/* Request-queue functions */ |
|
|
|
|
|
/* rad_proxy(): Called right after the request has been added to the request |
|
|
* list. The function just creates a dynamic copy of raw request data and |
|
|
* attaches it to the request. |
|
|
*/ |
|
|
/*ARGSUSED*/ |
|
|
int |
|
|
rad_proxy(REQUEST *req ARG_UNUSED) |
|
|
{ |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
/* ************************************************************************* */ |
|
204 |
/* Reply functions. Possibly these should go to libclient? */ |
/* Reply functions. Possibly these should go to libclient? */ |
205 |
|
|
206 |
int |
int |
207 |
proxy_send_request(fd, radreq) |
proxy_send_request(int fd, RADIUS_REQ *radreq) |
|
int fd; |
|
|
RADIUS_REQ *radreq; |
|
208 |
{ |
{ |
209 |
VALUE_PAIR *plist, *p; |
VALUE_PAIR *plist, *p; |
210 |
PROXY_STATE *proxy_state; |
PROXY_STATE *proxy_state; |
251 |
|
|
252 |
proxy_state = (PROXY_STATE *)p->avp_strvalue; |
proxy_state = (PROXY_STATE *)p->avp_strvalue; |
253 |
|
|
254 |
proxy_state->ipaddr = get_socket_addr(fd); |
proxy_state->ipaddr = radreq->ipaddr; /*FIXME: get_socket_addr(fd);*/ |
255 |
proxy_state->id = radreq->id; |
proxy_state->id = radreq->id; |
256 |
proxy_state->proxy_id = radreq->server_id; |
proxy_state->proxy_id = radreq->server_id; |
257 |
proxy_state->rem_ipaddr = server->addr; |
proxy_state->rem_ipaddr = server->addr; |
276 |
sin.sin_port = htons( |
sin.sin_port = htons( |
277 |
(radreq->code == RT_AUTHENTICATION_REQUEST) ? |
(radreq->code == RT_AUTHENTICATION_REQUEST) ? |
278 |
server->port[PORT_AUTH] : server->port[PORT_ACCT]); |
server->port[PORT_AUTH] : server->port[PORT_ACCT]); |
279 |
|
|
280 |
|
debug(1, ("Proxying id %d to %lx", |
281 |
|
radreq->id, (u_long)server->addr)); |
282 |
|
|
283 |
sendto(fd, pdu, size, 0, (struct sockaddr *)&sin, sizeof(sin)); |
sendto(fd, pdu, size, 0, (struct sockaddr *)&sin, sizeof(sin)); |
284 |
} |
} |
285 |
return size; |
return size; |
286 |
} |
} |
287 |
|
|
288 |
/* ************************************************************************* */ |
/* ************************************************************************* */ |
|
/* Functions local to this module */ |
|
|
|
|
|
static UINT4 |
|
|
get_socket_addr(fd) |
|
|
int fd; |
|
|
{ |
|
|
struct sockaddr_in sin; |
|
|
int len = sizeof(sin); |
|
|
UINT4 ip = 0; |
|
|
|
|
|
/* FIXME: if fd was bound to INADDR_ANY, there is not much sense |
|
|
in doing this. The possible solution will be to use if_nameindex |
|
|
(or SIOCGIFCONF) to get the IP of the first available interface */ |
|
|
|
|
|
if (getsockname(fd, (struct sockaddr*)&sin, &len) == 0) |
|
|
ip = sin.sin_addr.s_addr; |
|
|
|
|
|
if (ip == INADDR_ANY) |
|
|
ip = ref_ip; |
|
|
return ip; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* Decode a password and encode it again. |
|
|
*/ |
|
|
static void |
|
|
passwd_recode(pass_pair, new_secret, new_vector, req) |
|
|
VALUE_PAIR *pass_pair; |
|
|
char *new_secret; |
|
|
char *new_vector; |
|
|
RADIUS_REQ *req; |
|
|
{ |
|
|
char password[AUTH_STRING_LEN+1]; |
|
|
req_decrypt_password(password, req, pass_pair); |
|
|
string_free(pass_pair->avp_strvalue); |
|
|
encrypt_password(pass_pair, password, new_vector, new_secret); |
|
|
/* Don't let the cleantext hang around */ |
|
|
memset(password, 0, AUTH_STRING_LEN); |
|
|
} |
|
|
|
|
|
/* ************************************************************************* */ |
|
289 |
/* Interface functions */ |
/* Interface functions */ |
290 |
|
|
291 |
/* Relay the request to a remote server |
/* Relay the request to a remote server |
294 |
-1 fail (we don't reply, caller returns without replying) */ |
-1 fail (we don't reply, caller returns without replying) */ |
295 |
|
|
296 |
int |
int |
297 |
proxy_send(radreq, activefd) |
proxy_send(REQUEST *req) |
|
RADIUS_REQ *radreq; |
|
|
int activefd; |
|
298 |
{ |
{ |
299 |
|
RADIUS_REQ *radreq = req->data; |
300 |
int rc; |
int rc; |
301 |
char *saved_username; |
char *saved_username; |
302 |
char *username; |
char *username; |
305 |
char *realmname; |
char *realmname; |
306 |
REALM *realm; |
REALM *realm; |
307 |
char *what; |
char *what; |
308 |
|
RADIUS_UPDATE *upd; |
309 |
|
|
310 |
/* Look up name. */ |
/* Look up name. */ |
311 |
namepair = avl_find(radreq->request, DA_USER_NAME); |
namepair = avl_find(radreq->request, DA_USER_NAME); |
312 |
if (namepair == NULL) |
if (namepair == NULL) |
355 |
radreq->attempt_no = 0; |
radreq->attempt_no = 0; |
356 |
radreq->server_id = next_proxy_id(radreq->server->addr); |
radreq->server_id = next_proxy_id(radreq->server->addr); |
357 |
radreq->remote_user = string_create(username); |
radreq->remote_user = string_create(username); |
358 |
|
|
359 |
|
req->update_size = sizeof(*upd) + strlen(realm->realm); |
360 |
|
upd = emalloc(req->update_size); |
361 |
|
upd->proxy_id = radreq->server_id; |
362 |
|
upd->server_no = 0; |
363 |
|
strcpy(upd->realmname, realm->realm); |
364 |
|
req->update = upd; |
365 |
|
|
366 |
/* If there is no DA_CHAP_CHALLENGE attribute but there |
/* If there is no DA_CHAP_CHALLENGE attribute but there |
367 |
is a DA_CHAP_PASSWORD we need to add it since we can't |
is a DA_CHAP_PASSWORD we need to add it since we can't |
381 |
avl_add_pair(&radreq->request, vp); |
avl_add_pair(&radreq->request, vp); |
382 |
} |
} |
383 |
|
|
|
/* Now build a new request and send it to the remote radiusd. */ |
|
|
proxy_send_request(activefd, radreq); |
|
|
|
|
|
#if 1 |
|
|
/* And restore username. */ |
|
|
string_replace(&namepair->avp_strvalue, saved_username); |
|
|
namepair->avp_strlength = strlen(namepair->avp_strvalue); |
|
|
#endif |
|
384 |
efree(saved_username); |
efree(saved_username); |
385 |
|
|
386 |
|
proxy_send_request(req->fd, radreq); |
387 |
|
|
388 |
return 1; |
return 1; |
389 |
} |
} |
390 |
|
|
391 |
|
/* FIXME: Unused */ |
392 |
void |
void |
393 |
proxy_retry(int type, void *data, void *orig_data, |
proxy_retry(int type, void *data, void *orig_data, |
394 |
int fd, char *status_str) |
int fd, char *status_str) |
421 |
namepair->avp_strlength = strlen(namepair->avp_strvalue); |
namepair->avp_strlength = strlen(namepair->avp_strvalue); |
422 |
} |
} |
423 |
|
|
|
/* ************************************************************************* */ |
|
|
/* Functions for finding the matching request in the list of outstanding ones. |
|
|
* There appear to be two cases: i) when the remote server retains the |
|
|
* Proxy-State A/V pair, which seems to correspond to RFC 2865, |
|
|
* and ii) when the remote server drops the Proxy-State pair. |
|
|
*/ |
|
|
|
|
|
struct proxy_data { |
|
|
UINT4 ipaddr; |
|
|
PROXY_STATE *state; |
|
|
RADIUS_REQ *radreq; |
|
|
}; |
|
|
|
|
|
/* proxy_compare_request(): Find matching request based on the information |
|
|
preserved in the Proxy-State pair. */ |
|
|
int |
|
|
proxy_compare_request(void *item, void *datap) |
|
|
{ |
|
|
RADIUS_REQ *oldreq = item; |
|
|
struct proxy_data *data = datap; |
|
|
|
|
|
debug(10, ("(old=data) id %d %d, ipaddr %#8x %#8x, proxy_id %d %d, server_addr %#8x %#8x", |
|
|
oldreq->id, data->state->id, |
|
|
data->ipaddr, data->state->ipaddr, |
|
|
oldreq->server_id, data->state->proxy_id, |
|
|
oldreq->server->addr, data->state->rem_ipaddr)); |
|
|
|
|
|
if (data->state->ipaddr == data->ipaddr |
|
|
&& data->state->id == oldreq->id |
|
|
&& data->state->proxy_id == oldreq->server_id |
|
|
&& data->state->rem_ipaddr == oldreq->server->addr) |
|
|
return 0; |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
/* proxy_compare_request_no_state(): Find matching outstanding request if the |
|
|
server did not retain the Proxy-State pair. |
|
|
miquels@cistron.nl says: |
|
|
Some servers drop the proxy pair. So |
|
|
compare in another way if needed. |
|
|
FIXME: hmmm, perhaps we don't even need Proxy-State |
|
|
after all! */ |
|
|
int |
|
|
proxy_compare_request_no_state(void *item, void *datap) |
|
|
{ |
|
|
RADIUS_REQ *oldreq = item; |
|
|
struct proxy_data *data = datap; |
|
|
|
|
|
debug(10, ("(old=data) id %d %d, ipaddr %#8x %#8x", |
|
|
oldreq->server_id, |
|
|
data->radreq->id, |
|
|
oldreq->server->addr, |
|
|
data->radreq->ipaddr)); |
|
|
|
|
|
if (data->radreq->ipaddr == oldreq->server->addr && |
|
|
data->radreq->id == oldreq->server_id) |
|
|
return 0; |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
424 |
|
|
425 |
int |
int |
426 |
select_allowed(unused, pair) |
select_allowed(void *null ARG_UNUSED, VALUE_PAIR *pair) |
|
void *unused; |
|
|
VALUE_PAIR *pair; |
|
427 |
{ |
{ |
428 |
return pair->prop & AP_PROPAGATE; |
return pair->prop & AP_PROPAGATE; |
429 |
} |
} |
434 |
Return: 0 proxy found |
Return: 0 proxy found |
435 |
-1 error don't reply */ |
-1 error don't reply */ |
436 |
int |
int |
437 |
proxy_receive(radreq, activefd) |
proxy_receive(RADIUS_REQ *radreq, RADIUS_REQ *oldreq, int fd) |
|
RADIUS_REQ *radreq; |
|
|
int activefd; |
|
438 |
{ |
{ |
439 |
VALUE_PAIR *vp, *proxy_state_pair, *prev, *x; |
VALUE_PAIR *vp, *proxy_state_pair, *prev, *x; |
440 |
VALUE_PAIR *allowed_pairs; |
VALUE_PAIR *allowed_pairs; |
441 |
RADIUS_REQ *oldreq; |
PROXY_STATE *state; |
|
PROXY_STATE *state; |
|
|
struct proxy_data data; |
|
442 |
|
|
443 |
/* Find the last PROXY_STATE attribute. */ |
/* Remove the last proxy pair from the list. */ |
444 |
|
/* FIXME: Should be done by proxy_cmp ? */ |
|
oldreq = NULL; |
|
445 |
proxy_state_pair = x = prev = NULL; |
proxy_state_pair = x = prev = NULL; |
446 |
|
|
447 |
for (vp = radreq->request; vp; vp = vp->next) { |
for (vp = radreq->request; vp; vp = vp->next) { |
452 |
x = vp; |
x = vp; |
453 |
} |
} |
454 |
|
|
|
state = proxy_state_pair ? |
|
|
(PROXY_STATE *)proxy_state_pair->avp_strvalue : NULL; |
|
|
|
|
|
if (state) |
|
|
debug(1, ("state: ipaddr %08x, id %u, proxy_id %u, rem_ipaddr %08x", |
|
|
state->ipaddr, |
|
|
state->id, |
|
|
state->proxy_id, |
|
|
state->rem_ipaddr)); |
|
|
|
|
|
/* Find matching request in the list of outstanding requests. */ |
|
|
data.ipaddr = get_socket_addr(activefd); |
|
|
data.state = state; |
|
|
data.radreq = radreq; |
|
|
|
|
|
debug(1, ("Compare: myip %08x, radreq->id %d, radreq->ipaddr %08x", |
|
|
data.ipaddr, radreq->id, radreq->ipaddr)); |
|
|
|
|
|
if (state) { |
|
|
if (state->proxy_id == radreq->id && |
|
|
state->rem_ipaddr == radreq->ipaddr) { |
|
|
oldreq = request_scan_list(R_PROXY, |
|
|
proxy_compare_request, |
|
|
&data); |
|
|
} else { |
|
|
oldreq = NULL; |
|
|
} |
|
|
} else { |
|
|
oldreq = request_scan_list(R_PROXY, |
|
|
proxy_compare_request_no_state, |
|
|
&data); |
|
|
} |
|
|
|
|
|
if (oldreq == NULL) { |
|
|
char buf[MAX_LONGNAME]; |
|
|
radlog_req(L_PROXY|L_ERR, radreq, |
|
|
_("Unrecognized proxy reply from server %s, proxy ID %d"), |
|
|
client_lookup_name(radreq->ipaddr, buf, sizeof buf), |
|
|
radreq->id); |
|
|
return -1; |
|
|
} |
|
|
|
|
|
/* Remove proxy pair from the list. */ |
|
455 |
if (proxy_state_pair) { |
if (proxy_state_pair) { |
456 |
if (prev) |
if (prev) |
457 |
prev->next = proxy_state_pair->next; |
prev->next = proxy_state_pair->next; |