7 static const char rcsid[] = "$Id$";
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
30 static uint32_t proxy_id = 1;
32 static const int allowed[] = {
37 PW_FRAMED_COMPRESSION,
46 static const int trusted_allowed[] = {
51 PW_FRAMED_COMPRESSION,
65 * We received a response from a remote radius server.
66 * Find the original request, then return.
67 * Returns: 1 replication don't reply
69 * -1 error don't reply
71 int proxy_receive(REQUEST *request)
73 VALUE_PAIR *allowed_pairs;
75 VALUE_PAIR *proxypair;
76 VALUE_PAIR *replicatepair;
77 VALUE_PAIR *realmpair;
83 * FIXME: calculate md5 checksum!
86 proxypair = pairfind(request->config_items, PW_PROXY_TO_REALM);
87 replicatepair = pairfind(request->config_items, PW_REPLICATE_TO_REALM);
91 } else if(replicatepair) {
92 realmpair=replicatepair;
95 log(L_PROXY, "Proxy reply to packet with no Realm");
99 realmname=(char *)realmpair->strvalue;
100 realm = realm_find(realmname);
101 allowed_pairs = NULL;
103 /* FIXME - do we want to use the trusted/allowed filters on replicate
104 * replies, which are not going to be used for anything except maybe
106 if (realm->trusted) {
108 * Only allow some attributes to be propagated from
109 * the remote server back to the NAS, for security.
111 allowed_pairs = NULL;
112 for(i = 0; trusted_allowed[i]; i++)
113 pairmove2(&allowed_pairs, &(request->proxy_reply->vps), trusted_allowed[i]);
116 * Only allow some attributes to be propagated from
117 * the remote server back to the NAS, for security.
119 allowed_pairs = NULL;
120 for(i = 0; allowed[i]; i++)
121 pairmove2(&allowed_pairs, &(request->proxy_reply->vps), allowed[i]);
125 * Delete the left-over attributes, and move the
128 pairfree(request->proxy_reply->vps);
129 request->proxy_reply->vps = allowed_pairs;
131 return replicating?1:0;
135 * Add a proxy-pair to the end of the request.
137 static void proxy_addinfo(REQUEST *request)
139 VALUE_PAIR *proxy_pair;
141 proxy_pair = paircreate(PW_PROXY_STATE, PW_TYPE_STRING);
142 if (proxy_pair == NULL) {
143 log(L_ERR|L_CONS, "no memory");
146 sprintf((char *)proxy_pair->strvalue, "%d", request->packet->id);
147 proxy_pair->length = strlen((char *)proxy_pair->strvalue);
149 pairadd(&request->proxy->vps, proxy_pair);
153 * Relay the request to a remote server.
154 * Returns: 2 success (we replicate, caller replies normally)
155 * 1 success (we reply, caller returns without replying)
156 * 0 fail (caller falls through to normal processing)
157 * -1 fail (we don't reply, caller returns without replying)
159 int proxy_send(REQUEST *request)
161 VALUE_PAIR *proxypair;
162 VALUE_PAIR *replicatepair;
163 VALUE_PAIR *realmpair;
164 VALUE_PAIR *namepair;
165 VALUE_PAIR *strippednamepair;
166 VALUE_PAIR *delaypair;
167 VALUE_PAIR *vp, *vps;
172 #if 0 /* This looks bad to me... the timestamp is used below to figure the
173 * next_try. The request needs to "hang around" until either the
174 * other server sends a reply or the retry count has been exceeded.
175 * Until then, it should not be eligible for the time-based cleanup.
178 * Ensure that the request hangs around for a little
181 * FIXME: This is a hack... it should be more intelligent.
183 request->timestamp += 5;
186 /* Look for proxy/replicate signs */
187 /* FIXME - What to do if multiple Proxy-To/Replicate-To attrs are
188 * set... Log an error? Actually replicate to multiple places? That
189 * would be cool. For now though, I'll just take the first one and
190 * ignore the rest. */
191 proxypair = pairfind(request->config_items, PW_PROXY_TO_REALM);
192 replicatepair = pairfind(request->config_items, PW_REPLICATE_TO_REALM);
194 realmpair = proxypair;
196 } else if (replicatepair) {
197 realmpair = replicatepair;
201 * Neither proxy or replicate attributes are set,
202 * so we can exit from the proxy code.
207 realmname = (char *)realmpair->strvalue;
210 * Look for the realm, letting realm_find take care
211 * of the "NULL" realm.
213 * If there is no such realm, then exit.
214 * Maybe we should log an error?
216 realm = realm_find(realmname);
222 * Copy the request, then look up
223 * name and plain-text password in the copy.
225 * Note that the User-Name attribute is the *original*
226 * as sent over by the client. The Stripped-User-Name
227 * attribute is the one hacked through the 'hints' file.
229 vps = paircopy(request->packet->vps);
230 namepair = pairfind(vps, PW_USER_NAME);
231 strippednamepair = pairfind(vps, PW_STRIPPED_USER_NAME);
234 * If there's a Stripped-User-Name attribute in the
235 * request, then use THAT as the User-Name for the
236 * proxied request, instead of the original name.
238 * This is done by making a copy of the Stripped-User-Name
239 * attribute, turning it into a User-Name attribute,
240 * deleting the Stripped-User-Name and User-Name attributes
241 * from the vps list, and making the new User-Name
242 * the head of the vps list.
244 if (strippednamepair) {
245 vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
247 log(L_ERR|L_CONS, "no memory");
250 memcpy(vp->strvalue, strippednamepair->strvalue,
251 sizeof(vp->strvalue));
252 vp->length = strippednamepair->length;
253 pairdelete(&vps, PW_USER_NAME);
254 pairdelete(&vps, PW_STRIPPED_USER_NAME);
261 * Remember that we sent the request to a Realm.
263 pairadd(&request->packet->vps,
264 pairmake("Realm", realm->realm, T_OP_EQ));
267 * Now build a new RADIUS_PACKET and send it.
269 * FIXME: it could be that the id wraps around too fast if
270 * we have a lot of requests, it might be better to keep
271 * a seperate ID value per remote server.
273 * OTOH the remote radius server should be smart enough to
274 * compare _both_ ID and vector. Right ?
276 if ((request->proxy = rad_alloc(TRUE)) == NULL) {
277 log(L_ERR|L_CONS, "no memory");
282 * Proxied requests get sent out the proxy FD ONLY.
284 request->proxy->sockfd = proxyfd;
286 request->proxy->code = request->packet->code;
287 request->proxy->dst_ipaddr = realm->ipaddr;
288 if (request->packet->code == PW_AUTHENTICATION_REQUEST)
289 request->proxy->dst_port = realm->auth_port;
291 request->proxy->dst_port = realm->acct_port;
292 assert(request->proxy->vps == NULL);
293 request->proxy->vps = vps;
296 * Add the request to the list of outstanding requests.
297 * Note that request->proxy->id is a 16 bits value,
298 * while rad_send sends only the 8 least significant
299 * bits of that same value.
301 request->proxy->id = (proxy_id++) & 0xff;
305 * Add PROXY_STATE attribute.
307 proxy_addinfo(request);
310 * If there is no PW_CHAP_CHALLENGE attribute but there
311 * is a PW_CHAP_PASSWORD we need to add it since we can't
312 * use the request authenticator anymore - we changed it.
314 if (pairfind(vps, PW_CHAP_PASSWORD) &&
315 pairfind(vps, PW_CHAP_CHALLENGE) == NULL) {
316 vp = paircreate(PW_CHAP_CHALLENGE, PW_TYPE_STRING);
318 log(L_ERR|L_CONS, "no memory");
321 vp->length = AUTH_VECTOR_LEN;
322 memcpy(vp->strvalue, request->packet->vector, AUTH_VECTOR_LEN);
329 rad_send(request->proxy, (char *)realm->secret);
330 memcpy(request->proxysecret, realm->secret, sizeof(request->proxysecret));
331 request->proxy_is_replicate = replicating;
332 request->proxy_try_count = proxy_retry_count - 1;
333 request->proxy_next_try = request->timestamp + proxy_retry_delay;
334 delaypair = pairfind(vps, PW_ACCT_DELAY_TIME);
335 request->proxy->timestamp = request->timestamp - (delaypair ? delaypair->lvalue : 0);
337 #if 0 /* You can't do this - the pairs are needed for the retries! --Pac. */
339 * We can free proxy->vps now, not needed anymore.
341 pairfree(request->proxy->vps);
342 request->proxy->vps = NULL;
345 return replicating?2:1;