~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/main/event.c

  • Committer: Bazaar Package Importer
  • Author(s): Josip Rodin
  • Date: 2009-11-23 03:57:37 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20091123035737-zsgtzhfych8hir68
Tags: 2.1.7+dfsg-1
* Adopting the package, closes: #536623.
* New upstream version, closes: #513484.
  + Fixes the blooper in unlang evaluation logic, closes: #526175.
* Used quilt (and added README.source), and moved upstream file patching
  into debian/patches/. The source is no longer in collab-maint git
  (to make it simpler for me to finally get this out the door), but
  kept the .gitignore should we need that again.
* Dropped the dialup_admin/bin/backup_radacct patch (integrated upstream).
* Dropped the raddb/Makefile patch (problem no longer exists upstream).
* Dropped the lib/packet.c lib/radius.c main/listen.c patches (was from
  upstream 2.0.5 anyway).
* Dropped references to otp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Dropped references to snmp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Ship /etc/freeradius/modules/* in the freeradius package.
* Stop shipping sites-enabled symlinks in the package and instead create
  them only on initial install, thanks to Matej Vela, closes: #533396.
* Add export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" to the init script
  at the request of John Morrissey, closes: #550143.
* Stop installing /var/run/freeradius in the package to silence Lintian.
  The init script already recreates it at will.
* Remove executable bit from example.pl to silence Lintian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * event.c      Server event handling
3
3
 *
4
 
 * Version:     $Id: event.c,v 1.100 2008/04/20 15:00:06 aland Exp $
 
4
 * Version:     $Id$
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
7
7
 *   it under the terms of the GNU General Public License as published by
22
22
 */
23
23
 
24
24
#include <freeradius-devel/ident.h>
25
 
RCSID("$Id: event.c,v 1.100 2008/04/20 15:00:06 aland Exp $")
 
25
RCSID("$Id$")
26
26
 
27
27
#include <freeradius-devel/radiusd.h>
28
28
#include <freeradius-devel/modules.h>
29
29
#include <freeradius-devel/event.h>
30
30
#include <freeradius-devel/detail.h>
31
 
#include <freeradius-devel/radius_snmp.h>
32
31
 
33
32
#include <freeradius-devel/rad_assert.h>
34
33
 
45
44
extern int dont_fork;
46
45
extern int check_config;
47
46
extern void force_log_reopen(void);
 
47
extern char *debug_condition;
48
48
 
49
49
/*
50
50
 *      Ridiculous amounts of local state.
53
53
static fr_packet_list_t *pl = NULL;
54
54
static int                      request_num_counter = 0;
55
55
static struct timeval           now;
56
 
static time_t                   start_time;
 
56
time_t                          fr_start_time;
57
57
static int                      have_children;
58
 
static int                      has_detail_listener = FALSE;
59
 
static int                      just_started = FALSE;
 
58
static int                      just_started = TRUE;
60
59
 
61
60
#ifndef __MINGW32__
 
61
#ifdef HAVE_PTHREAD_H
 
62
#define WITH_SELF_PIPE (1)
 
63
#endif
 
64
#endif
 
65
 
 
66
#ifdef WITH_SELF_PIPE
62
67
static int self_pipe[2];
63
68
#endif
64
69
 
65
70
#ifdef HAVE_PTHREAD_H
 
71
#ifdef WITH_PROXY
66
72
static pthread_mutex_t  proxy_mutex;
 
73
#endif
67
74
 
68
75
#define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
69
76
#define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
 
77
 
 
78
static pthread_t NO_SUCH_CHILD_PID;
70
79
#else
71
80
/*
72
81
 *      This is easier than ifdef's throughout the code.
73
82
 */
74
83
#define PTHREAD_MUTEX_LOCK(_x)
75
84
#define PTHREAD_MUTEX_UNLOCK(_x)
 
85
int thread_pool_addrequest(REQUEST *request, RAD_REQUEST_FUNP fun)
 
86
{
 
87
        radius_handle_request(request, fun);
 
88
        return 1;
 
89
}
76
90
#endif
77
91
 
78
92
#define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
79
93
 
 
94
#ifdef WITH_PROXY
80
95
static fr_packet_list_t *proxy_list = NULL;
81
96
 
82
97
/*
85
100
 */
86
101
static int              proxy_fds[32];
87
102
static rad_listen_t     *proxy_listeners[32];
 
103
#else
 
104
#define remove_from_proxy_hash(foo)
 
105
#endif
88
106
 
89
107
static void request_post_handler(REQUEST *request);
90
108
static void wait_a_bit(void *ctx);
91
109
static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, void *ctx);
 
110
#ifdef WITH_DETAIL
 
111
static void event_poll_detail(void *ctx);
 
112
#endif
92
113
 
93
114
static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,
94
115
                                    const char *msg)
114
135
        }
115
136
}
116
137
 
117
 
#ifdef WITH_SNMP
118
 
static void snmp_inc_counters(REQUEST *request)
119
 
{
120
 
        if (!request->root->do_snmp) return;
121
 
 
122
 
        if (request->master_state == REQUEST_COUNTED) return;
123
 
 
124
 
        if ((request->listener->type != RAD_LISTEN_AUTH) &&
125
 
            (request->listener->type != RAD_LISTEN_ACCT)) return;
126
 
 
127
 
        /*
128
 
         *      Update the SNMP statistics.
129
 
         *
130
 
         *      Note that we do NOT do this in a child thread.
131
 
         *      Instead, we update the stats when a request is
132
 
         *      deleted, because only the main server thread calls
133
 
         *      this function, which makes it thread-safe.
134
 
         */
135
 
        switch (request->reply->code) {
136
 
        case PW_AUTHENTICATION_ACK:
137
 
                rad_snmp.auth.total_responses++;
138
 
                rad_snmp.auth.total_access_accepts++;
139
 
                if (request->client && request->client->auth) {
140
 
                        request->client->auth->accepts++;
141
 
                }
142
 
                break;
143
 
 
144
 
        case PW_AUTHENTICATION_REJECT:
145
 
                rad_snmp.auth.total_responses++;
146
 
                rad_snmp.auth.total_access_rejects++;
147
 
                if (request->client && request->client->auth) {
148
 
                        request->client->auth->rejects++;
149
 
                }
150
 
                break;
151
 
 
152
 
        case PW_ACCESS_CHALLENGE:
153
 
                rad_snmp.auth.total_responses++;
154
 
                rad_snmp.auth.total_access_challenges++;
155
 
                if (request->client && request->client->auth) {
156
 
                        request->client->auth->challenges++;
157
 
                }
158
 
                break;
159
 
 
160
 
        case PW_ACCOUNTING_RESPONSE:
161
 
                rad_snmp.acct.total_responses++;
162
 
                if (request->client && request->client->acct) {
163
 
                        request->client->acct->responses++;
164
 
                }
165
 
                break;
166
 
 
167
 
                /*
168
 
                 *      No response, it must have been a bad
169
 
                 *      authenticator.
170
 
                 */
171
 
        case 0:
172
 
                if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
173
 
                        rad_snmp.auth.total_bad_authenticators++;
174
 
                        if (request->client && request->client->auth) {
175
 
                                request->client->auth->bad_authenticators++;
176
 
                        }
177
 
                }
178
 
                break;
179
 
 
180
 
        default:
181
 
                break;
182
 
        }
183
 
 
184
 
        request->master_state = REQUEST_COUNTED;
185
 
}
186
 
#else
187
 
#define snmp_inc_counters(_x)
188
 
#endif
189
 
 
190
 
 
191
138
static void remove_from_request_hash(REQUEST *request)
192
139
{
193
140
        if (!request->in_request_hash) return;
195
142
        fr_packet_list_yank(pl, request->packet);
196
143
        request->in_request_hash = FALSE;
197
144
 
198
 
        snmp_inc_counters(request);
 
145
        request_stats_final(request);
199
146
}
200
147
 
201
148
 
 
149
#ifdef WITH_PROXY
202
150
static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
203
151
{
204
152
        RADIUS_PACKET **proxy_p;
238
186
         *      responded at all.
239
187
         */
240
188
        if (!request->proxy_reply &&
 
189
            request->home_server &&
241
190
            request->home_server->currently_outstanding) {
242
191
                request->home_server->currently_outstanding--;
243
192
        }
250
199
 
251
200
static void remove_from_proxy_hash(REQUEST *request)
252
201
{
 
202
        /*
 
203
         *      Check this without grabbing the mutex because it's a
 
204
         *      lot faster that way.
 
205
         */
253
206
        if (!request->in_proxy_hash) return;
254
207
 
 
208
        /*
 
209
         *      The "not in hash" flag is definitive.  However, if the
 
210
         *      flag says that it IS in the hash, there might still be
 
211
         *      a race condition where it isn't.
 
212
         */
255
213
        PTHREAD_MUTEX_LOCK(&proxy_mutex);
 
214
 
 
215
        if (!request->in_proxy_hash) {
 
216
                PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
 
217
                return;
 
218
        }
 
219
 
256
220
        fr_packet_list_yank(proxy_list, request->proxy);
257
221
        fr_packet_list_id_free(proxy_list, request->proxy);
258
222
 
262
226
         *      home server.
263
227
         */
264
228
        if (!request->proxy_reply &&
 
229
            request->home_server &&
265
230
            request->home_server->currently_outstanding) {
266
231
                request->home_server->currently_outstanding--;
267
232
        }
268
233
 
 
234
        /*
 
235
         *      Got from YES in hash, to NO, not in hash while we hold
 
236
         *      the mutex.  This guarantees that when another thread
 
237
         *      grans the mutex, the "not in hash" flag is correct.
 
238
         */
 
239
        request->in_proxy_hash = FALSE;
 
240
 
269
241
        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
270
 
 
271
 
        request->in_proxy_hash = FALSE;
272
 
}
273
 
 
274
 
 
275
 
static int insert_into_proxy_hash(REQUEST *request)
 
242
}
 
243
 
 
244
static void ev_request_free(REQUEST **prequest)
 
245
{
 
246
        REQUEST *request;
 
247
        
 
248
        if (!prequest || !*prequest) return;
 
249
 
 
250
        request = *prequest;
 
251
 
 
252
#ifdef WITH_COA
 
253
        if (request->coa) {
 
254
                /*
 
255
                 *      Divorce the child from the parent first,
 
256
                 *      then clean up the child.
 
257
                 */
 
258
                request->coa->parent = NULL;
 
259
                ev_request_free(&request->coa);
 
260
        }
 
261
 
 
262
        /*
 
263
         *      Divorce the parent from the child, and leave the
 
264
         *      parent still alive.
 
265
         */
 
266
        if (request->parent && (request->parent->coa == request)) {
 
267
                request->parent->coa = NULL;
 
268
        }
 
269
#endif
 
270
 
 
271
        if (request->ev) fr_event_delete(el, &request->ev);
 
272
        if (request->in_proxy_hash) remove_from_proxy_hash(request);
 
273
        if (request->in_request_hash) remove_from_request_hash(request);
 
274
 
 
275
        request_free(prequest);
 
276
}
 
277
 
 
278
static int proxy_id_alloc(REQUEST *request, RADIUS_PACKET *packet)
 
279
{
 
280
        int i, proxy, found;
 
281
        rad_listen_t *proxy_listener;
 
282
 
 
283
        if (fr_packet_list_id_alloc(proxy_list, packet)) return 1;
 
284
 
 
285
        /*
 
286
         *      Allocate a new proxy fd.  This function adds
 
287
         *      it to the tail of the list of listeners.  With
 
288
         *      some care, this can be thread-safe.
 
289
         */
 
290
        proxy_listener = proxy_new_listener(&packet->src_ipaddr, FALSE);
 
291
        if (!proxy_listener) {
 
292
                RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
 
293
                return 0;
 
294
        }
 
295
        
 
296
        /*
 
297
         *      Cache it locally.
 
298
         */
 
299
        found = -1;
 
300
        proxy = proxy_listener->fd;
 
301
        for (i = 0; i < 32; i++) {
 
302
                /*
 
303
                 *      Found a free entry.  Save the socket,
 
304
                 *      and remember where we saved it.
 
305
                 */
 
306
                if (proxy_fds[(proxy + i) & 0x1f] == -1) {
 
307
                        found = (proxy + i) & 0x1f;
 
308
                        proxy_fds[found] = proxy;
 
309
                        proxy_listeners[found] = proxy_listener;
 
310
                        break;
 
311
                }
 
312
        }
 
313
        rad_assert(found >= 0);
 
314
        
 
315
        if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
 
316
                        RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
 
317
                return 0;
 
318
                
 
319
        }
 
320
        
 
321
        if (!fr_packet_list_id_alloc(proxy_list, packet)) {
 
322
                        RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
 
323
                return 0;
 
324
        }
 
325
        
 
326
        /*
 
327
         *      Signal the main thread to add the new FD to the list
 
328
         *      of listening FD's.
 
329
         */
 
330
        radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
 
331
        return 1;
 
332
}
 
333
 
 
334
 
 
335
static int insert_into_proxy_hash(REQUEST *request, int retransmit)
276
336
{
277
337
        int i, proxy;
278
338
        char buf[128];
280
340
        rad_assert(request->proxy != NULL);
281
341
        rad_assert(proxy_list != NULL);
282
342
 
283
 
        request->proxy->sockfd = -1;
284
 
 
285
343
        PTHREAD_MUTEX_LOCK(&proxy_mutex);
286
344
 
287
 
        request->home_server->currently_outstanding++;
288
 
        request->home_server->total_requests_sent++;
289
 
 
290
345
        /*
291
 
         *      On overflow, back up to ~0.
 
346
         *      Keep track of maximum outstanding requests to a
 
347
         *      particular home server.  'max_outstanding' is
 
348
         *      enforced in home_server_ldb(), in realms.c.
292
349
         */
293
 
        if (!request->home_server->total_requests_sent) {
294
 
                request->home_server->total_requests_sent--;
295
 
        }
296
 
 
297
 
        if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
298
 
                int found;
299
 
                rad_listen_t *proxy_listener;
300
 
 
301
 
                /*
302
 
                 *      Allocate a new proxy fd.  This function adds
303
 
                 *      it to the tail of the list of listeners.  With
304
 
                 *      some care, this can be thread-safe.
305
 
                 */
306
 
                proxy_listener = proxy_new_listener();
307
 
                if (!proxy_listener) {
308
 
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
309
 
                        DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
310
 
                        return 0;
311
 
                }
312
 
 
313
 
                /*
314
 
                 *      Cache it locally.
315
 
                 */
316
 
                found = -1;
317
 
                proxy = proxy_listener->fd;
318
 
                for (i = 0; i < 32; i++) {
319
 
                        /*
320
 
                         *      Found a free entry.  Save the socket,
321
 
                         *      and remember where we saved it.
322
 
                         */
323
 
                        if (proxy_fds[(proxy + i) & 0x1f] == -1) {
324
 
                                found = (proxy + i) & 0x1f;
325
 
                                proxy_fds[found] = proxy;
326
 
                                proxy_listeners[found] = proxy_listener;
327
 
                                break;
328
 
                        }
329
 
                }
330
 
                rad_assert(found >= 0);
331
 
 
332
 
                if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
333
 
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
334
 
                        DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
335
 
                        return 0;
336
 
 
337
 
                }
338
 
 
339
 
                if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
340
 
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
341
 
                        DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
342
 
                        return 0;
343
 
                }
344
 
 
345
 
                /*
346
 
                 *      Signal the main thread to add the new FD to the list
347
 
                 *      of listening FD's.
348
 
                 */
349
 
                radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
350
 
        }
 
350
        if (request->home_server) {
 
351
                request->home_server->currently_outstanding++;
 
352
        }
 
353
 
 
354
        if (retransmit) {
 
355
                RADIUS_PACKET packet;
 
356
 
 
357
                packet = *request->proxy;
 
358
 
 
359
                if (!proxy_id_alloc(request, &packet)) {
 
360
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
 
361
                        return 0;
 
362
                }
 
363
 
 
364
                /*
 
365
                 *      Yank the request, free the old Id, and
 
366
                 *      remember the new Id.
 
367
                 */
 
368
                fr_packet_list_yank(proxy_list, request->proxy);
 
369
                fr_packet_list_id_free(proxy_list, request->proxy);
 
370
                *request->proxy = packet;
 
371
 
 
372
        } else if (!proxy_id_alloc(request, request->proxy)) {
 
373
                PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
 
374
                return 0;
 
375
        }
 
376
 
351
377
        rad_assert(request->proxy->sockfd >= 0);
352
378
 
353
379
        /*
364
390
 
365
391
        if (proxy < 0) {
366
392
                PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
367
 
                DEBUG2("ERROR: All sockets are full.");
 
393
                RDEBUG2("ERROR: All sockets are full.");
368
394
                return 0;
369
395
        }
370
396
 
375
401
        if (!fr_packet_list_insert(proxy_list, &request->proxy)) {
376
402
                fr_packet_list_id_free(proxy_list, request->proxy);
377
403
                PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
378
 
                DEBUG2("ERROR: Failed to insert entry into proxy list");
 
404
                RDEBUG2("ERROR: Failed to insert entry into proxy list");
379
405
                return 0;
380
406
        }
381
407
 
 
408
        request->in_proxy_hash = TRUE;
 
409
 
382
410
        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
383
411
 
384
 
        DEBUG3(" proxy: allocating destination %s port %d - Id %d",
 
412
        RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
385
413
               inet_ntop(request->proxy->dst_ipaddr.af,
386
414
                         &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
387
415
               request->proxy->dst_port,
388
416
               request->proxy->id);
389
417
 
390
 
        request->in_proxy_hash = TRUE;
391
 
 
392
418
        return 1;
393
419
}
394
420
 
399
425
static void wait_for_proxy_id_to_expire(void *ctx)
400
426
{
401
427
        REQUEST *request = ctx;
402
 
        home_server *home = request->home_server;
403
428
 
404
429
        rad_assert(request->magic == REQUEST_MAGIC);
405
430
        rad_assert(request->proxy != NULL);
406
431
 
407
432
        if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
408
433
        request->when = request->proxy_when;
409
 
        request->when.tv_sec += home->response_window;
 
434
 
 
435
#ifdef WITH_COA
 
436
        if (((request->proxy->code == PW_COA_REQUEST) ||
 
437
             (request->proxy->code == PW_DISCONNECT_REQUEST)) &&
 
438
            (request->packet->code != request->proxy->code)) {
 
439
                request->when.tv_sec += request->home_server->coa_mrd;
 
440
        } else
 
441
#endif
 
442
        request->when.tv_sec += request->home_server->response_window;
410
443
 
411
444
        if ((request->num_proxied_requests == request->num_proxied_responses) ||
412
445
            timercmp(&now, &request->when, >)) {
413
446
                if (request->packet) {
414
 
                        DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
 
447
                        RDEBUG2("Cleaning up request %d ID %d with timestamp +%d",
415
448
                               request->number, request->packet->id,
416
 
                               (unsigned int) (request->timestamp - start_time));
 
449
                               (unsigned int) (request->timestamp - fr_start_time));
417
450
                } else {
418
 
                        DEBUG2("Cleaning up request %d with timestamp +%d",
 
451
                        RDEBUG2("Cleaning up request %d with timestamp +%d",
419
452
                               request->number,
420
 
                               (unsigned int) (request->timestamp - start_time));
 
453
                               (unsigned int) (request->timestamp - fr_start_time));
421
454
                }
422
 
                fr_event_delete(el, &request->ev);
423
 
                remove_from_proxy_hash(request);
424
 
                remove_from_request_hash(request);
425
 
                request_free(&request);
 
455
 
 
456
                ev_request_free(&request);
426
457
                return;
427
458
        }
428
459
 
429
460
        INSERT_EVENT(wait_for_proxy_id_to_expire, request);
430
461
}
431
 
 
432
 
 
 
462
#endif
 
463
 
 
464
#ifdef HAVE_PTHREAD_H
433
465
static void wait_for_child_to_die(void *ctx)
434
466
{
435
467
        REQUEST *request = ctx;
441
473
                request->delay += (request->delay >> 1);
442
474
                tv_add(&request->when, request->delay);
443
475
 
444
 
                DEBUG2("Child is still stuck for request %d", request->number);
 
476
                RDEBUG2("Child is still stuck for request %d", request->number);
445
477
 
446
478
                INSERT_EVENT(wait_for_child_to_die, request);
447
479
                return;
448
480
        }
449
481
 
450
 
        DEBUG2("Child is finally responsive for request %d", request->number);
 
482
        RDEBUG2("Child is finally responsive for request %d", request->number);
451
483
        remove_from_request_hash(request);
452
484
 
 
485
#ifdef WITH_PROXY
453
486
        if (request->proxy) {
454
487
                wait_for_proxy_id_to_expire(request);
455
488
                return;
456
489
        }
 
490
#endif
457
491
 
458
 
        request_free(&request);
 
492
        ev_request_free(&request);
459
493
}
460
 
 
 
494
#endif
461
495
 
462
496
static void cleanup_delay(void *ctx)
463
497
{
469
503
 
470
504
        remove_from_request_hash(request);
471
505
 
 
506
#ifdef WITH_PROXY
472
507
        if (request->proxy && request->in_proxy_hash) {
473
508
                wait_for_proxy_id_to_expire(request);
474
509
                return;
475
510
        }
 
511
#endif
476
512
 
477
 
        DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
 
513
        RDEBUG2("Cleaning up request %d ID %d with timestamp +%d",
478
514
               request->number, request->packet->id,
479
 
               (unsigned int) (request->timestamp - start_time));
480
 
 
481
 
        fr_event_delete(el, &request->ev);
482
 
        request_free(&request);
483
 
}
484
 
 
 
515
               (unsigned int) (request->timestamp - fr_start_time));
 
516
 
 
517
        ev_request_free(&request);
 
518
}
 
519
 
 
520
 
 
521
/*
 
522
 *      In daemon mode, AND this request has debug flags set.
 
523
 */
 
524
#define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
 
525
 
 
526
static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
 
527
{
 
528
        VALUE_PAIR *vp;
 
529
        char buffer[1024];
 
530
        const char *received, *from;
 
531
        const fr_ipaddr_t *ip;
 
532
        int port;
 
533
 
 
534
        if (!packet) return;
 
535
 
 
536
        rad_assert(request->radlog != NULL);
 
537
 
 
538
        if (direction == 0) {
 
539
                received = "Received";
 
540
                from = "from";  /* what else? */
 
541
                ip = &packet->src_ipaddr;
 
542
                port = packet->src_port;
 
543
 
 
544
        } else {
 
545
                received = "Sending";
 
546
                from = "to";    /* hah! */
 
547
                ip = &packet->dst_ipaddr;
 
548
                port = packet->dst_port;
 
549
        }
 
550
        
 
551
        /*
 
552
         *      Client-specific debugging re-prints the input
 
553
         *      packet into the client log.
 
554
         *
 
555
         *      This really belongs in a utility library
 
556
         */
 
557
        if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
 
558
                RDEBUG("%s %s packet %s host %s port %d, id=%d, length=%d",
 
559
                       received, fr_packet_codes[packet->code], from,
 
560
                       inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
 
561
                       port, packet->id, packet->data_len);
 
562
        } else {
 
563
                RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%d",
 
564
                       received, from,
 
565
                       inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
 
566
                       port,
 
567
                       packet->code, packet->id, packet->data_len);
 
568
        }
 
569
 
 
570
        for (vp = packet->vps; vp != NULL; vp = vp->next) {
 
571
                vp_prints(buffer, sizeof(buffer), vp);
 
572
                request->radlog(L_DBG, 0, request, "\t%s", buffer);
 
573
        }
 
574
}
485
575
 
486
576
static void reject_delay(void *ctx)
487
577
{
490
580
        rad_assert(request->magic == REQUEST_MAGIC);
491
581
        rad_assert(request->child_state == REQUEST_REJECT_DELAY);
492
582
 
493
 
        DEBUG2("Sending delayed reject for request %d", request->number);
 
583
        RDEBUG2("Sending delayed reject for request %d", request->number);
 
584
 
 
585
        DEBUG_PACKET(request, request->reply, 1);
494
586
 
495
587
        request->listener->send(request->listener, request);
496
588
 
501
593
}
502
594
 
503
595
 
504
 
static void revive_home_server(void *ctx)
 
596
#ifdef WITH_PROXY
 
597
void revive_home_server(void *ctx)
505
598
{
506
599
        home_server *home = ctx;
 
600
        char buffer[128];
507
601
 
508
602
        home->state = HOME_STATE_ALIVE;
509
 
        DEBUG2("Marking home server alive again... we have no idea if it really is alive or not.");
510
603
        home->currently_outstanding = 0;
 
604
        home->revive_time = now;
 
605
 
 
606
        /*
 
607
         *      Delete any outstanding events.
 
608
         */
 
609
        if (home->ev) fr_event_delete(el, &home->ev);
 
610
 
 
611
        radlog(L_INFO, "PROXY: Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
 
612
               inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
 
613
                         buffer, sizeof(buffer)),
 
614
               home->port);
 
615
 
511
616
}
512
617
 
513
618
 
514
619
static void no_response_to_ping(void *ctx)
515
620
{
516
621
        REQUEST *request = ctx;
517
 
        home_server *home = request->home_server;
 
622
        home_server *home;
518
623
        char buffer[128];
519
624
 
 
625
        rad_assert(request->home_server != NULL);
 
626
 
 
627
        home = request->home_server;
520
628
        home->num_received_pings = 0;
521
629
 
522
 
        DEBUG2("No response to status check %d from home server %s port %d",
 
630
        RDEBUG2("No response to status check %d from home server %s port %d",
523
631
               request->number,
524
632
               inet_ntop(request->proxy->dst_ipaddr.af,
525
633
                         &request->proxy->dst_ipaddr.ipaddr,
532
640
 
533
641
static void received_response_to_ping(REQUEST *request)
534
642
{
535
 
        home_server *home = request->home_server;
 
643
        home_server *home;
536
644
        char buffer[128];
537
645
 
 
646
        rad_assert(request->home_server != NULL);
 
647
 
 
648
        home = request->home_server;
538
649
        home->num_received_pings++;
539
650
 
540
 
        DEBUG2("Received response to status check %d (%d in current sequence)",
 
651
        RDEBUG2("Received response to status check %d (%d in current sequence)",
541
652
               request->number, home->num_received_pings);
542
653
 
 
654
        /*
 
655
         *      Remove the request from any hashes
 
656
         */
 
657
        fr_event_delete(el, &request->ev);
 
658
        remove_from_proxy_hash(request);
 
659
        rad_assert(request->in_request_hash == FALSE);
 
660
 
 
661
        /*
 
662
         *      The control socket may have marked the home server as
 
663
         *      alive.  OR, it may have suddenly started responding to
 
664
         *      requests again.  If so, don't re-do the "make alive"
 
665
         *      work.
 
666
         */
 
667
        if (home->state == HOME_STATE_ALIVE) return;
 
668
 
 
669
        /*
 
670
         *      We haven't received enough ping responses to mark it
 
671
         *      "alive".  Wait a bit.
 
672
         */
543
673
        if (home->num_received_pings < home->num_pings_to_alive) {
544
 
                wait_for_proxy_id_to_expire(request);
545
674
                return;
546
675
        }
547
676
 
548
 
        DEBUG2("Marking home server %s port %d alive",
549
 
               inet_ntop(request->proxy->dst_ipaddr.af,
550
 
                         &request->proxy->dst_ipaddr.ipaddr,
551
 
                         buffer, sizeof(buffer)),
552
 
               request->proxy->dst_port);
 
677
        home->state = HOME_STATE_ALIVE;
 
678
        home->currently_outstanding = 0;
 
679
        home->revive_time = now;
553
680
 
554
681
        if (!fr_event_delete(el, &home->ev)) {
555
 
                DEBUG2("Hmm... no event for home server, WTF?");
556
 
        }
557
 
 
558
 
        if (!fr_event_delete(el, &request->ev)) {
559
 
                DEBUG2("Hmm... no event for request, WTF?");
560
 
        }
561
 
 
562
 
        wait_for_proxy_id_to_expire(request);
563
 
 
564
 
        home->state = HOME_STATE_ALIVE;
565
 
        home->currently_outstanding = 0;
 
682
                RDEBUG2("Hmm... no event for home server.  Oh well.");
 
683
        }
 
684
 
 
685
        radlog(L_INFO, "PROXY: Marking home server %s port %d alive",
 
686
               inet_ntop(request->proxy->dst_ipaddr.af,
 
687
                         &request->proxy->dst_ipaddr.ipaddr,
 
688
                         buffer, sizeof(buffer)),
 
689
               request->proxy->dst_port);
566
690
}
567
691
 
568
692
 
 
693
/*
 
694
 *      Called from start of zombie period, OR after control socket
 
695
 *      marks the home server dead.
 
696
 */
569
697
static void ping_home_server(void *ctx)
570
698
{
571
699
        uint32_t jitter;
573
701
        REQUEST *request;
574
702
        VALUE_PAIR *vp;
575
703
 
576
 
        if (home->state == HOME_STATE_ALIVE) {
577
 
                radlog(L_INFO, "Suspicious proxy state... continuing");
 
704
        if ((home->state == HOME_STATE_ALIVE) ||
 
705
            (home->ping_check == HOME_PING_CHECK_NONE) ||
 
706
            (home->ev != NULL)) {
578
707
                return;
579
708
        }
580
709
 
606
735
                                "Message-Authenticator", "0x00", T_OP_SET);
607
736
 
608
737
        } else {
 
738
#ifdef WITH_ACCOUNTING
609
739
                request->proxy->code = PW_ACCOUNTING_REQUEST;
610
740
                
611
741
                radius_pairmake(request, &request->proxy->vps,
617
747
                vp = radius_pairmake(request, &request->proxy->vps,
618
748
                                     "Event-Timestamp", "0", T_OP_SET);
619
749
                vp->vp_date = now.tv_sec;
 
750
#else
 
751
                rad_assert("Internal sanity check failed");
 
752
#endif
620
753
        }
621
754
 
622
755
        radius_pairmake(request, &request->proxy->vps,
629
762
 
630
763
        rad_assert(request->proxy_listener == NULL);
631
764
 
632
 
        if (!insert_into_proxy_hash(request)) {
633
 
                DEBUG2("ERROR: Failed inserting status check %d into proxy hash.  Discarding it.",
 
765
        if (!insert_into_proxy_hash(request, FALSE)) {
 
766
                RDEBUG2("ERROR: Failed inserting status check %d into proxy hash.  Discarding it.",
634
767
                       request->number);
635
 
                request_free(&request);
 
768
                ev_request_free(&request);
636
769
                return;
637
770
        }
638
771
        rad_assert(request->proxy_listener != NULL);
657
790
 
658
791
        tv_add(&home->when, jitter);
659
792
 
660
 
 
661
793
        INSERT_EVENT(ping_home_server, home);
662
794
}
663
795
 
664
796
 
 
797
void mark_home_server_dead(home_server *home, struct timeval *when)
 
798
{
 
799
        int previous_state = home->state;
 
800
        char buffer[128];
 
801
 
 
802
        radlog(L_INFO, "PROXY: Marking home server %s port %d as dead.",
 
803
               inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
 
804
                         buffer, sizeof(buffer)),
 
805
               home->port);
 
806
 
 
807
        home->state = HOME_STATE_IS_DEAD;
 
808
        home->num_received_pings = 0;
 
809
 
 
810
        if (home->ping_check != HOME_PING_CHECK_NONE) {
 
811
                /*
 
812
                 *      If the control socket marks us dead, start
 
813
                 *      pinging.  Otherwise, we already started
 
814
                 *      pinging when it was marked "zombie".
 
815
                 */
 
816
                if (previous_state == HOME_STATE_ALIVE) {
 
817
                        ping_home_server(home);
 
818
                }
 
819
 
 
820
        } else {
 
821
                /*
 
822
                 *      Revive it after a fixed period of time.  This
 
823
                 *      is very, very, bad.
 
824
                 */
 
825
                home->when = *when;
 
826
                home->when.tv_sec += home->revive_interval;
 
827
 
 
828
                INSERT_EVENT(revive_home_server, home);
 
829
        }
 
830
}
 
831
 
665
832
static void check_for_zombie_home_server(REQUEST *request)
666
833
{
667
834
        home_server *home;
668
835
        struct timeval when;
669
 
        char buffer[128];
670
836
 
671
837
        home = request->home_server;
672
838
 
680
846
                return;
681
847
        }
682
848
 
683
 
        /*
684
 
         *      It's been a zombie for too long, mark it as
685
 
         *      dead.
686
 
         */
687
 
        DEBUG2("FAILURE: Marking home server %s port %d as dead.",
688
 
               inet_ntop(request->proxy->dst_ipaddr.af,
689
 
                         &request->proxy->dst_ipaddr.ipaddr,
690
 
                         buffer, sizeof(buffer)),
691
 
               request->proxy->dst_port);
692
 
        home->state = HOME_STATE_IS_DEAD;
693
 
        home->num_received_pings = 0;
694
 
        home->when = request->when;
695
 
 
696
 
        if (home->ping_check != HOME_PING_CHECK_NONE) {
697
 
                rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||
698
 
                           (home->ping_user_name != NULL));
699
 
                home->when.tv_sec += home->ping_interval;
700
 
 
701
 
                INSERT_EVENT(ping_home_server, home);
702
 
        } else {
703
 
                home->when.tv_sec += home->revive_interval;
704
 
 
705
 
                INSERT_EVENT(revive_home_server, home);
 
849
        mark_home_server_dead(home, &request->when);
 
850
}
 
851
 
 
852
static int proxy_to_virtual_server(REQUEST *request);
 
853
 
 
854
static int virtual_server_handler(UNUSED REQUEST *request)
 
855
{
 
856
        proxy_to_virtual_server(request);
 
857
        return 0;
 
858
}
 
859
 
 
860
static void proxy_fallback_handler(REQUEST *request)
 
861
{
 
862
        /*
 
863
         *      A proper time is required for wait_a_bit.
 
864
         */
 
865
        request->delay = USEC / 10;
 
866
        gettimeofday(&now, NULL);
 
867
        request->next_when = now;
 
868
        tv_add(&request->next_when, request->delay);
 
869
        request->next_callback = wait_a_bit;
 
870
 
 
871
        /*
 
872
         *      Re-queue the request.
 
873
         */
 
874
        request->child_state = REQUEST_QUEUED;
 
875
        
 
876
        rad_assert(request->proxy != NULL);
 
877
        if (!thread_pool_addrequest(request, virtual_server_handler)) {
 
878
                request->child_state = REQUEST_DONE;
706
879
        }
 
880
 
 
881
#ifdef HAVE_PTHREAD_H
 
882
        /*
 
883
         *      MAY free the request if we're over max_request_time,
 
884
         *      AND we're not in threaded mode!
 
885
         *
 
886
         *      Note that we call this ONLY if we're threaded, as
 
887
         *      if we're NOT threaded, request_post_handler() calls
 
888
         *      wait_a_bit(), which means that "request" may not
 
889
         *      exist any more...
 
890
         */
 
891
        if (have_children) wait_a_bit(request);
 
892
#endif
707
893
}
708
894
 
709
895
 
712
898
        DICT_VALUE *dval = NULL;
713
899
        VALUE_PAIR *vp;
714
900
 
 
901
        request->child_state = REQUEST_RUNNING;
 
902
 
715
903
        if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
716
904
                dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication");
717
905
 
718
906
        } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
719
907
                dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting");
720
908
 
 
909
#ifdef WITH_COA
 
910
                /*
 
911
                 *      See no_response_to_coa_request
 
912
                 */
 
913
        } else if (((request->packet->code >> 8) & 0xff) == PW_COA_REQUEST) {
 
914
                request->packet->code &= 0xff; /* restore it */
 
915
 
 
916
                if (request->proxy->code == PW_COA_REQUEST) {
 
917
                        dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-CoA");
 
918
 
 
919
                } else if (request->proxy->code == PW_DISCONNECT_REQUEST) {
 
920
                        dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Disconnect");
 
921
                } else {
 
922
                        return 0;
 
923
                }
 
924
 
 
925
#endif
721
926
        } else {
722
927
                return 0;
723
928
        }
760
965
         *      to do next.
761
966
         */
762
967
        if (!setup_post_proxy_fail(request)) {
763
 
                request->child_state = REQUEST_RUNNING;
764
968
                request_post_handler(request);
765
969
 
766
970
        } else {
784
988
                request->priority = 0;
785
989
                rad_assert(request->proxy != NULL);
786
990
                thread_pool_addrequest(request, null_handler);
787
 
 
788
991
        }
789
992
 
790
993
        /*
810
1013
        rad_assert(request->magic == REQUEST_MAGIC);
811
1014
        rad_assert(request->child_state == REQUEST_PROXIED);
812
1015
 
813
 
        radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
814
 
               request->number,
815
 
               inet_ntop(request->proxy->dst_ipaddr.af,
816
 
                         &request->proxy->dst_ipaddr.ipaddr,
817
 
                         buffer, sizeof(buffer)),
818
 
               request->proxy->dst_port);
 
1016
        /*
 
1017
         *      If we've failed over to an internal home server,
 
1018
         *      replace the callback with the correct one.  This
 
1019
         *      is due to locking issues with child threads...
 
1020
         */
 
1021
        if (request->home_server->server) {
 
1022
                wait_a_bit(request);
 
1023
                return;
 
1024
        }
819
1025
 
820
1026
        check_for_zombie_home_server(request);
821
1027
 
822
1028
        home = request->home_server;
823
1029
 
824
 
        post_proxy_fail_handler(request);
 
1030
        /*
 
1031
         *      The default as of 2.1.7 is to allow requests to
 
1032
         *      fail-over to a backup home server when this one does
 
1033
         *      not respond.  The old behavior can be configured as
 
1034
         *      well.
 
1035
         */
 
1036
        if (home->no_response_fail) {
 
1037
                radlog(L_ERR, "Rejecting request %d (proxy Id %d) due to lack of any response from home server %s port %d",
 
1038
                       request->number, request->proxy->id,
 
1039
                       inet_ntop(request->proxy->dst_ipaddr.af,
 
1040
                                 &request->proxy->dst_ipaddr.ipaddr,
 
1041
                                 buffer, sizeof(buffer)),
 
1042
                       request->proxy->dst_port);
 
1043
 
 
1044
                post_proxy_fail_handler(request);
 
1045
        }
825
1046
 
826
1047
        /*
827
1048
         *      Don't touch request due to race conditions
833
1054
 
834
1055
        /*
835
1056
         *      Enable the zombie period when we notice that the home
836
 
         *      server hasn't responded.  We also back-date the start
837
 
         *      of the zombie period to when the proxied request was
838
 
         *      sent.
 
1057
         *      server hasn't responded.  We do NOT back-date the start
 
1058
         *      of the zombie period.
839
1059
         */
840
1060
        if (home->state == HOME_STATE_ALIVE) {
841
 
                DEBUG2("WARNING: Marking home server %s port %d as zombie (it looks like it is dead).",
 
1061
                home->state = HOME_STATE_ZOMBIE;
 
1062
                home->zombie_period_start = now;        
 
1063
 
 
1064
                radlog(L_ERR, "PROXY: Marking home server %s port %d as zombie (it looks like it is dead).",
842
1065
                       inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
843
1066
                                 buffer, sizeof(buffer)),
844
1067
                       home->port);
845
 
                home->state = HOME_STATE_ZOMBIE;
846
 
                home->zombie_period_start = now;
847
 
                home->zombie_period_start.tv_sec -= home->response_window;
848
 
                return;
 
1068
 
 
1069
                /*
 
1070
                 *      Start pinging the home server.
 
1071
                 */
 
1072
                ping_home_server(home);
849
1073
        }
850
1074
}
851
 
 
 
1075
#endif
852
1076
 
853
1077
static void wait_a_bit(void *ctx)
854
1078
{
858
1082
 
859
1083
        rad_assert(request->magic == REQUEST_MAGIC);
860
1084
 
 
1085
#ifdef WITH_COA
 
1086
        /*
 
1087
         *      The CoA request is a new (internally generated)
 
1088
         *      request, created in a child thread.  We therefore need
 
1089
         *      some way to tie its events back into the main event
 
1090
         *      handler.
 
1091
         */
 
1092
        if (request->coa && !request->coa->proxy_reply &&
 
1093
            request->coa->next_callback) {
 
1094
                request->coa->when = request->coa->next_when;
 
1095
                INSERT_EVENT(request->coa->next_callback, request->coa);
 
1096
                request->coa->next_callback = NULL;
 
1097
                request->coa->parent = NULL;
 
1098
                request->coa = NULL;
 
1099
        }
 
1100
#endif
 
1101
 
861
1102
        switch (request->child_state) {
862
1103
        case REQUEST_QUEUED:
863
1104
        case REQUEST_RUNNING:
885
1126
                        }
886
1127
                        request->delay += request->delay >> 1;
887
1128
 
 
1129
#ifdef WITH_DETAIL
888
1130
                        /*
889
1131
                         *      Cap wait at some sane value for detail
890
1132
                         *      files.
893
1135
                            (request->delay > (request->root->max_request_time * USEC))) {
894
1136
                                request->delay = request->root->max_request_time * USEC;
895
1137
                        }
 
1138
#endif
896
1139
 
897
1140
                        request->when = now;
898
1141
                        tv_add(&request->when, request->delay);
900
1143
                        break;
901
1144
                }
902
1145
 
 
1146
#if defined(HAVE_PTHREAD_H) || defined(WITH_PROXY)
903
1147
                /*
904
1148
                 *      A child thread MAY still be running on the
905
1149
                 *      request.  Ask the thread to stop working on
916
1160
                         *      conditions on this check.  But it's
917
1161
                         *      just an error message, so that's OK.
918
1162
                         */
919
 
                        if (request->child_pid != NO_SUCH_CHILD_PID) {
920
 
                                radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",
921
 
                               (unsigned long)request->child_pid, request->number,
 
1163
                        if (!pthread_equal(request->child_pid, NO_SUCH_CHILD_PID)) {
 
1164
                                radlog(L_ERR, "WARNING: Unresponsive child for request %d, in module %s component %s",
 
1165
                                       request->number,
922
1166
                                       request->module ? request->module : "<server core>",
923
1167
                                       request->component ? request->component : "<server core>");
924
1168
                        }
930
1174
                        callback = wait_for_child_to_die;
931
1175
                        break;
932
1176
                }
 
1177
#endif
933
1178
 
934
1179
                /*
935
1180
                 *      Else there are no child threads.  We probably
947
1192
                 *      and clean it up.
948
1193
                 */
949
1194
        case REQUEST_DONE:
 
1195
#ifdef HAVE_PTHREAD_H
950
1196
                request->child_pid = NO_SUCH_CHILD_PID;
951
 
                snmp_inc_counters(request);
 
1197
#endif
 
1198
 
 
1199
#ifdef WTH_COA
 
1200
                /*
 
1201
                 *      This is a CoA request.  It's been divorced
 
1202
                 *      from everything else, so we clean it up now.
 
1203
                 */
 
1204
                if (!request->in_request_hash &&
 
1205
                    request->proxy &&
 
1206
                    (request->packet->code != request->proxy->code) &&
 
1207
                    ((request->proxy->code == PW_COA_REQUEST) ||
 
1208
                     (request->proxy->code == PW_DISCONNECT_REQUEST))) {
 
1209
                        /*
 
1210
                         *      FIXME: Do CoA MIBs
 
1211
                         */
 
1212
                        ev_request_free(&request);
 
1213
                        return;
 
1214
                }
 
1215
#endif
 
1216
                request_stats_final(request);
952
1217
                cleanup_delay(request);
953
1218
                return;
954
1219
 
955
1220
        case REQUEST_REJECT_DELAY:
956
1221
        case REQUEST_CLEANUP_DELAY:
 
1222
#ifdef HAVE_PTHREAD_H
957
1223
                request->child_pid = NO_SUCH_CHILD_PID;
958
 
                snmp_inc_counters(request);
 
1224
#endif
 
1225
                request_stats_final(request);
959
1226
 
960
1227
        case REQUEST_PROXIED:
961
1228
                rad_assert(request->next_callback != NULL);
982
1249
         *      mode, with no threads...
983
1250
         */
984
1251
        if (!callback) {
985
 
                DEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);
986
 
                fr_event_delete(el, &request->ev);
987
 
                remove_from_proxy_hash(request);
988
 
                remove_from_request_hash(request);
989
 
                request_free(&request);
 
1252
                RDEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);
 
1253
                ev_request_free(&request);
990
1254
                return;
991
1255
        }
992
1256
 
993
1257
        INSERT_EVENT(callback, request);
994
1258
}
995
1259
 
 
1260
#ifdef WITH_COA
 
1261
static void no_response_to_coa_request(void *ctx)
 
1262
{
 
1263
        REQUEST *request = ctx;
 
1264
        char buffer[128];
 
1265
 
 
1266
        rad_assert(request->magic == REQUEST_MAGIC);
 
1267
        rad_assert(request->child_state == REQUEST_PROXIED);
 
1268
        rad_assert(request->home_server != NULL);
 
1269
        rad_assert(!request->in_request_hash);
 
1270
 
 
1271
        radlog(L_ERR, "No response to CoA request sent to %s",
 
1272
               inet_ntop(request->proxy->dst_ipaddr.af,
 
1273
                         &request->proxy->dst_ipaddr.ipaddr,
 
1274
                         buffer, sizeof(buffer)));
 
1275
 
 
1276
        /*
 
1277
         *      Hack.
 
1278
         */
 
1279
        request->packet->code |= (PW_COA_REQUEST << 8);
 
1280
        post_proxy_fail_handler(request);
 
1281
}
 
1282
 
 
1283
 
 
1284
static int update_event_timestamp(RADIUS_PACKET *packet, time_t when)
 
1285
{
 
1286
        VALUE_PAIR *vp;
 
1287
 
 
1288
        vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP);
 
1289
        if (!vp) return 0;
 
1290
 
 
1291
        vp->vp_date = when;
 
1292
 
 
1293
        if (packet->data) {
 
1294
                free(packet->data);
 
1295
                packet->data = NULL;
 
1296
                packet->data_len = 0;
 
1297
        }
 
1298
 
 
1299
        return 1;               /* time stamp updated */
 
1300
}
 
1301
 
 
1302
 
 
1303
/*
 
1304
 *      Called when we haven't received a response to a CoA request.
 
1305
 */
 
1306
static void retransmit_coa_request(void *ctx)
 
1307
{
 
1308
        int delay, frac;
 
1309
        struct timeval mrd;
 
1310
        REQUEST *request = ctx;
 
1311
 
 
1312
        rad_assert(request->magic == REQUEST_MAGIC);
 
1313
        rad_assert(request->child_state == REQUEST_PROXIED);
 
1314
        rad_assert(request->home_server != NULL);
 
1315
        rad_assert(!request->in_request_hash);
 
1316
        rad_assert(request->parent == NULL);
 
1317
        
 
1318
        fr_event_now(el, &now);
 
1319
 
 
1320
        /*
 
1321
         *      Cap count at MRC, if it is non-zero.
 
1322
         */
 
1323
        if (request->home_server->coa_mrc &&
 
1324
            (request->num_coa_requests >= request->home_server->coa_mrc)) {
 
1325
                no_response_to_coa_request(request);
 
1326
                return;
 
1327
        }
 
1328
 
 
1329
        /*
 
1330
         *      RFC 5080 Section 2.2.1
 
1331
         *
 
1332
         *      RT = 2*RTprev + RAND*RTprev
 
1333
         *         = 1.9 * RTprev + rand(0,.2) * RTprev
 
1334
         *         = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
 
1335
         */
 
1336
        delay = fr_rand();
 
1337
        delay ^= (delay >> 16);
 
1338
        delay &= 0xffff;
 
1339
        frac = request->delay / 5;
 
1340
        delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
 
1341
 
 
1342
        delay += (2 * request->delay) - (request->delay / 10);
 
1343
 
 
1344
        /*
 
1345
         *      Cap delay at MRT, if MRT is non-zero.
 
1346
         */
 
1347
        if (request->home_server->coa_mrt &&
 
1348
            (delay > (request->home_server->coa_mrt * USEC))) {
 
1349
                int mrt_usec = request->home_server->coa_mrt * USEC;
 
1350
 
 
1351
                /*
 
1352
                 *      delay = MRT + RAND * MRT
 
1353
                 *            = 0.9 MRT + rand(0,.2)  * MRT
 
1354
                 */
 
1355
                delay = fr_rand();
 
1356
                delay ^= (delay >> 15);
 
1357
                delay &= 0x1ffff;
 
1358
                delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
 
1359
                delay += mrt_usec - (mrt_usec / 10);
 
1360
        }
 
1361
 
 
1362
        request->delay = delay;
 
1363
        request->when = now;
 
1364
        tv_add(&request->when, request->delay);
 
1365
        mrd = request->proxy_when;
 
1366
        mrd.tv_sec += request->home_server->coa_mrd;
 
1367
 
 
1368
        /*
 
1369
         *      Cap duration at MRD.
 
1370
         */
 
1371
        if (timercmp(&mrd, &request->when, <)) {
 
1372
                request->when = mrd;
 
1373
                INSERT_EVENT(no_response_to_coa_request, request);
 
1374
 
 
1375
        } else {
 
1376
                INSERT_EVENT(retransmit_coa_request, request);
 
1377
        }
 
1378
        
 
1379
        if (update_event_timestamp(request->proxy, now.tv_sec)) {
 
1380
                if (!insert_into_proxy_hash(request, TRUE)) {
 
1381
                        DEBUG("ERROR: Failed re-inserting CoA request into proxy hash.");
 
1382
                        return;
 
1383
                }
 
1384
 
 
1385
                request->num_proxied_requests = 0;
 
1386
                request->num_proxied_responses = 0;
 
1387
        }
 
1388
 
 
1389
        request->num_proxied_requests++;
 
1390
        request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
 
1391
 
 
1392
        request->proxy_listener->send(request->proxy_listener,
 
1393
                                      request);
 
1394
}
 
1395
 
 
1396
 
 
1397
/*
 
1398
 *      The original request is either DONE, or in CLEANUP_DELAY.
 
1399
 */
 
1400
static int originated_coa_request(REQUEST *request)
 
1401
{
 
1402
        int delay, rcode, pre_proxy_type = 0;
 
1403
        VALUE_PAIR *vp;
 
1404
        REQUEST *coa;
 
1405
        fr_ipaddr_t ipaddr;
 
1406
        char buffer[256];
 
1407
 
 
1408
        rad_assert(request->proxy == NULL);
 
1409
        rad_assert(!request->in_proxy_hash);
 
1410
        rad_assert(request->proxy_reply == NULL);
 
1411
 
 
1412
        vp = pairfind(request->config_items, PW_SEND_COA_REQUEST);
 
1413
        if (!vp && request->coa) vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST);
 
1414
        if (vp) {
 
1415
                if (vp->vp_integer == 0) {
 
1416
                        ev_request_free(&request->coa);
 
1417
                        return 1;       /* success */
 
1418
                }
 
1419
 
 
1420
                if (!request->coa) request_alloc_coa(request);
 
1421
                if (!request->coa) return 0;
 
1422
        }
 
1423
 
 
1424
        coa = request->coa;
 
1425
 
 
1426
        /*
 
1427
         *      src_ipaddr will be set up in proxy_encode.
 
1428
         */
 
1429
        memset(&ipaddr, 0, sizeof(ipaddr));
 
1430
        vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS);
 
1431
        if (vp) {
 
1432
                ipaddr.af = AF_INET;
 
1433
                ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
 
1434
 
 
1435
        } else if ((vp = pairfind(coa->proxy->vps,
 
1436
                                  PW_PACKET_DST_IPV6_ADDRESS)) != NULL) {
 
1437
                ipaddr.af = AF_INET6;
 
1438
                ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
 
1439
                
 
1440
        } else if ((vp = pairfind(coa->proxy->vps,
 
1441
                                  PW_HOME_SERVER_POOL)) != NULL) {
 
1442
                coa->home_pool = home_pool_byname(vp->vp_strvalue,
 
1443
                                                  HOME_TYPE_COA);
 
1444
                if (!coa->home_pool) {
 
1445
                        RDEBUG2("WARNING: No such home_server_pool %s",
 
1446
                               vp->vp_strvalue);
 
1447
        fail:
 
1448
                        ev_request_free(&request->coa);
 
1449
                        return 0;
 
1450
                }
 
1451
 
 
1452
                /*
 
1453
                 *      Prefer
 
1454
                 */
 
1455
        } else if (request->client->coa_pool) {
 
1456
                coa->home_pool = request->client->coa_pool;
 
1457
 
 
1458
        } else if (request->client->coa_server) {
 
1459
                coa->home_server = request->client->coa_server;
 
1460
 
 
1461
        } else {
 
1462
                /*
 
1463
                 *      If all else fails, send it to the client that
 
1464
                 *      originated this request.
 
1465
                 */
 
1466
                memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
 
1467
        }
 
1468
 
 
1469
        /*
 
1470
         *      Use the pool, if it exists.
 
1471
         */
 
1472
        if (coa->home_pool) {
 
1473
                coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
 
1474
                if (!coa->home_server) {
 
1475
                        RDEBUG("WARNING: No live home server for home_server_pool %s", vp->vp_strvalue);
 
1476
                        goto fail;
 
1477
                }
 
1478
 
 
1479
        } else if (!coa->home_server) {
 
1480
                int port = PW_COA_UDP_PORT;
 
1481
 
 
1482
                vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT);
 
1483
                if (vp) port = vp->vp_integer;
 
1484
 
 
1485
                coa->home_server = home_server_find(&ipaddr, port);
 
1486
                if (!coa->home_server) {
 
1487
                        RDEBUG2("WARNING: Unknown destination %s:%d for CoA request.",
 
1488
                               inet_ntop(ipaddr.af, &ipaddr.ipaddr,
 
1489
                                         buffer, sizeof(buffer)), port);
 
1490
                        goto fail;
 
1491
                }
 
1492
        }
 
1493
 
 
1494
        vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE);
 
1495
        if (vp) {
 
1496
                switch (vp->vp_integer) {
 
1497
                case PW_COA_REQUEST:
 
1498
                case PW_DISCONNECT_REQUEST:
 
1499
                        coa->proxy->code = vp->vp_integer;
 
1500
                        break;
 
1501
                        
 
1502
                default:
 
1503
                        DEBUG("Cannot set CoA Packet-Type to code %d",
 
1504
                              vp->vp_integer);
 
1505
                        goto fail;
 
1506
                }
 
1507
        }
 
1508
 
 
1509
        if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
 
1510
 
 
1511
        /*
 
1512
         *      The rest of the server code assumes that
 
1513
         *      request->packet && request->reply exist.  Copy them
 
1514
         *      from the original request.
 
1515
         */
 
1516
        rad_assert(coa->packet != NULL);
 
1517
        rad_assert(coa->packet->vps == NULL);
 
1518
        memcpy(coa->packet, request->packet, sizeof(*request->packet));
 
1519
        coa->packet->vps = paircopy(request->packet->vps);
 
1520
        coa->packet->data = NULL;
 
1521
        rad_assert(coa->reply != NULL);
 
1522
        rad_assert(coa->reply->vps == NULL);
 
1523
        memcpy(coa->reply, request->reply, sizeof(*request->reply));
 
1524
        coa->reply->vps = paircopy(request->reply->vps);
 
1525
        coa->reply->data = NULL;
 
1526
        coa->config_items = paircopy(request->config_items);
 
1527
 
 
1528
        /*
 
1529
         *      Call the pre-proxy routines.
 
1530
         */
 
1531
        vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
 
1532
        if (vp) {
 
1533
                RDEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
 
1534
                pre_proxy_type = vp->vp_integer;
 
1535
        }
 
1536
 
 
1537
        if (coa->home_pool && coa->home_pool->virtual_server) {
 
1538
                const char *old_server = coa->server;
 
1539
                
 
1540
                coa->server = coa->home_pool->virtual_server;
 
1541
                RDEBUG2(" server %s {", coa->server);
 
1542
                rcode = module_pre_proxy(pre_proxy_type, coa);
 
1543
                RDEBUG2(" }");
 
1544
                coa->server = old_server;
 
1545
        } else {
 
1546
                rcode = module_pre_proxy(pre_proxy_type, coa);
 
1547
        }
 
1548
        switch (rcode) {
 
1549
        default:
 
1550
                goto fail;
 
1551
 
 
1552
        /*
 
1553
         *      Only send the CoA packet if the pre-proxy code succeeded.
 
1554
         */
 
1555
        case RLM_MODULE_NOOP:
 
1556
        case RLM_MODULE_OK:
 
1557
        case RLM_MODULE_UPDATED:
 
1558
                break;
 
1559
        }
 
1560
 
 
1561
        /*
 
1562
         *      Source IP / port is set when the proxy socket
 
1563
         *      is chosen.
 
1564
         */
 
1565
        coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
 
1566
        coa->proxy->dst_port = coa->home_server->port;
 
1567
 
 
1568
        if (!insert_into_proxy_hash(coa, FALSE)) {
 
1569
                DEBUG("ERROR: Failed inserting CoA request into proxy hash.");
 
1570
                goto fail;
 
1571
        }
 
1572
 
 
1573
        /*
 
1574
         *      We CANNOT divorce the CoA request from the parent
 
1575
         *      request.  This function is running in a child thread,
 
1576
         *      and we need access to the main event loop in order to
 
1577
         *      to add the timers for the CoA packet.  See
 
1578
         *      wait_a_bit().
 
1579
         */
 
1580
 
 
1581
        /*
 
1582
         *      Forget about the original request completely at this
 
1583
         *      point.
 
1584
         */
 
1585
        request = coa;
 
1586
 
 
1587
        gettimeofday(&request->proxy_when, NULL);       
 
1588
        request->received = request->next_when = request->proxy_when;
 
1589
        rad_assert(request->proxy_reply == NULL);
 
1590
 
 
1591
        /*
 
1592
         *      Implement re-transmit algorithm as per RFC 5080
 
1593
         *      Section 2.2.1.
 
1594
         *
 
1595
         *      We want IRT + RAND*IRT
 
1596
         *      or 0.9 IRT + rand(0,.2) IRT
 
1597
         *
 
1598
         *      2^20 ~ USEC, and we want 2.
 
1599
         *      rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
 
1600
         */
 
1601
        delay = (fr_rand() & ((1 << 22) - 1)) / 10;
 
1602
        request->delay = delay * request->home_server->coa_irt;
 
1603
        delay = request->home_server->coa_irt * USEC;
 
1604
        delay -= delay / 10;
 
1605
        delay += request->delay;
 
1606
     
 
1607
        request->delay = delay;
 
1608
        tv_add(&request->next_when, delay);
 
1609
        request->next_callback = retransmit_coa_request;
 
1610
        
 
1611
        /*
 
1612
         *      Note that we set proxied BEFORE sending the packet.
 
1613
         *
 
1614
         *      Once we send it, the request is tainted, as
 
1615
         *      another thread may have picked it up.  Don't
 
1616
         *      touch it!
 
1617
         */
 
1618
        request->num_proxied_requests = 1;
 
1619
        request->num_proxied_responses = 0;
 
1620
        request->child_pid = NO_SUCH_CHILD_PID;
 
1621
 
 
1622
        update_event_timestamp(request->proxy, request->proxy_when.tv_sec);
 
1623
 
 
1624
        request->child_state = REQUEST_PROXIED;
 
1625
 
 
1626
        DEBUG_PACKET(request, request->proxy, 1);
 
1627
 
 
1628
        request->proxy_listener->send(request->proxy_listener,
 
1629
                                      request);
 
1630
        return 1;
 
1631
}
 
1632
#endif  /* WITH_COA */
 
1633
 
 
1634
#ifdef WITH_PROXY
 
1635
static int process_proxy_reply(REQUEST *request)
 
1636
{
 
1637
        int rcode;
 
1638
        int post_proxy_type = 0;
 
1639
        VALUE_PAIR *vp;
 
1640
        
 
1641
        /*
 
1642
         *      Delete any reply we had accumulated until now.
 
1643
         */
 
1644
        pairfree(&request->reply->vps);
 
1645
        
 
1646
        /*
 
1647
         *      Run the packet through the post-proxy stage,
 
1648
         *      BEFORE playing games with the attributes.
 
1649
         */
 
1650
        vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
 
1651
        if (vp) {
 
1652
                RDEBUG2("  Found Post-Proxy-Type %s", vp->vp_strvalue);
 
1653
                post_proxy_type = vp->vp_integer;
 
1654
        }
 
1655
        
 
1656
        if (request->home_pool && request->home_pool->virtual_server) {
 
1657
                const char *old_server = request->server;
 
1658
                
 
1659
                request->server = request->home_pool->virtual_server;
 
1660
                RDEBUG2(" server %s {", request->server);
 
1661
                rcode = module_post_proxy(post_proxy_type, request);
 
1662
                RDEBUG2(" }");
 
1663
                request->server = old_server;
 
1664
        } else {
 
1665
                rcode = module_post_proxy(post_proxy_type, request);
 
1666
        }
 
1667
 
 
1668
#ifdef WITH_COA
 
1669
        if (request->packet->code == request->proxy->code)
 
1670
          /*
 
1671
           *    Don't run the next bit if we originated a CoA
 
1672
           *    packet, after receiving an Access-Request or
 
1673
           *    Accounting-Request.
 
1674
           */
 
1675
#endif
 
1676
        
 
1677
        /*
 
1678
         *      There may NOT be a proxy reply, as we may be
 
1679
         *      running Post-Proxy-Type = Fail.
 
1680
         */
 
1681
        if (request->proxy_reply) {
 
1682
                /*
 
1683
                 *      Delete the Proxy-State Attributes from
 
1684
                 *      the reply.  These include Proxy-State
 
1685
                 *      attributes from us and remote server.
 
1686
                 */
 
1687
                pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
 
1688
                
 
1689
                /*
 
1690
                 *      Add the attributes left in the proxy
 
1691
                 *      reply to the reply list.
 
1692
                 */
 
1693
                pairadd(&request->reply->vps, request->proxy_reply->vps);
 
1694
                request->proxy_reply->vps = NULL;
 
1695
                
 
1696
                /*
 
1697
                 *      Free proxy request pairs.
 
1698
                 */
 
1699
                pairfree(&request->proxy->vps);
 
1700
        }
 
1701
        
 
1702
        switch (rcode) {
 
1703
        default:  /* Don't do anything */
 
1704
                break;
 
1705
        case RLM_MODULE_FAIL:
 
1706
                /* FIXME: debug print stuff */
 
1707
                request->child_state = REQUEST_DONE;
 
1708
                return 0;
 
1709
                
 
1710
        case RLM_MODULE_HANDLED:
 
1711
                /* FIXME: debug print stuff */
 
1712
                request->child_state = REQUEST_DONE;
 
1713
                return 0;
 
1714
        }
 
1715
 
 
1716
        return 1;
 
1717
}
 
1718
#endif
996
1719
 
997
1720
static int request_pre_handler(REQUEST *request)
998
1721
{
1016
1739
                return 1;
1017
1740
        }
1018
1741
 
 
1742
#ifdef WITH_PROXY
1019
1743
        /*
1020
1744
         *      Put the decoded packet into it's proper place.
1021
1745
         */
1022
1746
        if (request->proxy_reply != NULL) {
1023
1747
                rcode = request->proxy_listener->decode(request->proxy_listener,
1024
1748
                                                        request);
1025
 
        } else if (request->packet->vps == NULL) {
 
1749
                DEBUG_PACKET(request, request->proxy_reply, 0);
 
1750
        } else
 
1751
#endif
 
1752
        if (request->packet->vps == NULL) {
1026
1753
                rcode = request->listener->decode(request->listener, request);
 
1754
                
 
1755
                if (debug_condition) {
 
1756
                        int result = FALSE;
 
1757
                        const char *my_debug = debug_condition;
1027
1758
 
 
1759
                        /*
 
1760
                         *      Ignore parse errors.
 
1761
                         */
 
1762
                        radius_evaluate_condition(request, RLM_MODULE_OK, 0,
 
1763
                                                  &my_debug, 1,
 
1764
                                                  &result);
 
1765
                        if (result) {
 
1766
                                request->options = 2;
 
1767
                                request->radlog = radlog_request;
 
1768
                        }
 
1769
                }
 
1770
                
 
1771
                DEBUG_PACKET(request, request->packet, 0);
1028
1772
        } else {
1029
1773
                rcode = 0;
1030
1774
        }
1031
1775
 
1032
1776
        if (rcode < 0) {
1033
 
                radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);
 
1777
                radlog(L_ERR, "%s Dropping packet without response.", fr_strerror());
1034
1778
                request->child_state = REQUEST_DONE;
1035
1779
                return 0;
1036
1780
        }
1037
1781
 
1038
 
        if (!request->proxy) {
 
1782
        if (!request->username) {
1039
1783
                request->username = pairfind(request->packet->vps,
1040
1784
                                             PW_USER_NAME);
1041
 
 
1042
 
        } else {
1043
 
                int post_proxy_type = 0;
1044
 
                VALUE_PAIR *vp;
1045
 
 
1046
 
                /*
1047
 
                 *      Delete any reply we had accumulated until now.
1048
 
                 */
1049
 
                pairfree(&request->reply->vps);
1050
 
 
1051
 
                /*
1052
 
                 *      Run the packet through the post-proxy stage,
1053
 
                 *      BEFORE playing games with the attributes.
1054
 
                 */
1055
 
                vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
1056
 
                if (vp) {
1057
 
                        DEBUG2("  Found Post-Proxy-Type %s", vp->vp_strvalue);
1058
 
                        post_proxy_type = vp->vp_integer;
1059
 
                }
1060
 
 
1061
 
                rad_assert(request->home_pool != NULL);
1062
 
 
1063
 
                if (request->home_pool->virtual_server) {
1064
 
                        const char *old_server = request->server;
1065
 
 
1066
 
                        request->server = request->home_pool->virtual_server;
1067
 
                        DEBUG2(" server %s {", request->server);
1068
 
                        rcode = module_post_proxy(post_proxy_type, request);
1069
 
                        DEBUG2(" }");
1070
 
                        request->server = old_server;
1071
 
                } else {
1072
 
                        rcode = module_post_proxy(post_proxy_type, request);
1073
 
                }
1074
 
 
1075
 
                /*
1076
 
                 *      There may NOT be a proxy reply, as we may be
1077
 
                 *      running Post-Proxy-Type = Fail.
1078
 
                 */
1079
 
                if (request->proxy_reply) {
1080
 
                        /*
1081
 
                         *      Delete the Proxy-State Attributes from
1082
 
                         *      the reply.  These include Proxy-State
1083
 
                         *      attributes from us and remote server.
1084
 
                         */
1085
 
                        pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
1086
 
 
1087
 
                        /*
1088
 
                         *      Add the attributes left in the proxy
1089
 
                         *      reply to the reply list.
1090
 
                         */
1091
 
                        pairadd(&request->reply->vps, request->proxy_reply->vps);
1092
 
                        request->proxy_reply->vps = NULL;
1093
 
 
1094
 
                        /*
1095
 
                         *      Free proxy request pairs.
1096
 
                         */
1097
 
                        pairfree(&request->proxy->vps);
1098
 
                }
1099
 
 
1100
 
                switch (rcode) {
1101
 
                default:  /* Don't do anything */
1102
 
                        break;
1103
 
                case RLM_MODULE_FAIL:
1104
 
                        /* FIXME: debug print stuff */
1105
 
                        request->child_state = REQUEST_DONE;
1106
 
                        return 0;
1107
 
 
1108
 
                case RLM_MODULE_HANDLED:
1109
 
                        /* FIXME: debug print stuff */
1110
 
                        request->child_state = REQUEST_DONE;
1111
 
                        return 0;
1112
 
                }
 
1785
        }
 
1786
 
 
1787
#ifdef WITH_PROXY
 
1788
        if (request->proxy) {
 
1789
                return process_proxy_reply(request);
 
1790
#endif
1113
1791
        }
1114
1792
 
1115
1793
        return 1;
1116
1794
}
1117
1795
 
1118
1796
 
 
1797
#ifdef WITH_PROXY
1119
1798
/*
1120
1799
 *      Do state handling when we proxy a request.
1121
1800
 */
1124
1803
        struct timeval when;
1125
1804
        char buffer[128];
1126
1805
 
1127
 
        if (!insert_into_proxy_hash(request)) {
1128
 
                DEBUG("ERROR: Failed inserting request into proxy hash.");
 
1806
        if (request->home_server->server) {
 
1807
                RDEBUG("ERROR: Cannot perform real proxying to a virtual server.");
 
1808
                return 0;
 
1809
        }
 
1810
 
 
1811
        if (!insert_into_proxy_hash(request, FALSE)) {
 
1812
                RDEBUG("ERROR: Failed inserting request into proxy hash.");
1129
1813
                return 0;
1130
1814
        }
1131
1815
 
1146
1830
        }
1147
1831
        request->next_callback = no_response_to_proxied_request;
1148
1832
 
1149
 
        DEBUG2("Proxying request %d to home server %s port %d",
 
1833
        RDEBUG2("Proxying request %d to home server %s port %d",
1150
1834
               request->number,
1151
1835
               inet_ntop(request->proxy->dst_ipaddr.af,
1152
1836
                         &request->proxy->dst_ipaddr.ipaddr,
1162
1846
         */
1163
1847
        request->num_proxied_requests = 1;
1164
1848
        request->num_proxied_responses = 0;
 
1849
#ifdef HAVE_PTHREAD_H
1165
1850
        request->child_pid = NO_SUCH_CHILD_PID;
 
1851
#endif
1166
1852
        request->child_state = REQUEST_PROXIED;
 
1853
 
 
1854
        DEBUG_PACKET(request, request->proxy, 1);
 
1855
 
1167
1856
        request->proxy_listener->send(request->proxy_listener,
1168
1857
                                      request);
1169
1858
        return 1;
1176
1865
static int proxy_to_virtual_server(REQUEST *request)
1177
1866
{
1178
1867
        REQUEST *fake;
 
1868
        RAD_REQUEST_FUNP fun;
1179
1869
 
1180
1870
        if (!request->home_server || !request->home_server->server) return 0;
1181
1871
 
1182
1872
        if (request->parent) {
1183
 
                DEBUG2("WARNING: Cancelling proxy request to virtual server %s as this request was itself proxied.", request->home_server->server);
 
1873
                RDEBUG2("WARNING: Cancelling proxy request to virtual server %s as this request was itself proxied.", request->home_server->server);
1184
1874
                return 0;
1185
1875
        }
1186
1876
 
1187
1877
        fake = request_alloc_fake(request);
1188
1878
        if (!fake) {
1189
 
                DEBUG2("WARNING: Out of memory");
 
1879
                RDEBUG2("WARNING: Out of memory");
1190
1880
                return 0;
1191
1881
        }
1192
1882
 
1193
1883
        fake->packet->vps = paircopy(request->proxy->vps);
1194
1884
        fake->server = request->home_server->server;
1195
1885
 
1196
 
        DEBUG2(">>> Sending proxied request internally to virtual server.");
1197
 
        radius_handle_request(fake, rad_authenticate);
1198
 
        DEBUG2("<<< Received proxied response from internal virtual server.");
1199
 
 
1200
 
        request->proxy_reply = fake->reply;
1201
 
        fake->reply = NULL;
 
1886
        if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
 
1887
                fun = rad_authenticate;
 
1888
 
 
1889
#ifdef WITH_ACCOUNTING
 
1890
        } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
 
1891
                fun = rad_accounting;
 
1892
#endif
 
1893
 
 
1894
        } else {
 
1895
                RDEBUG2("Unknown packet type %d", request->proxy->code);
 
1896
                ev_request_free(&fake);
 
1897
                return 0;
 
1898
        }
 
1899
 
 
1900
        RDEBUG2(">>> Sending proxied request internally to virtual server.");
 
1901
        radius_handle_request(fake, fun);
 
1902
        RDEBUG2("<<< Received proxied response code %d from internal virtual server.", fake->reply->code);
 
1903
 
 
1904
        if (fake->reply->code != 0) {
 
1905
                request->proxy_reply = fake->reply;
 
1906
                fake->reply = NULL;
 
1907
        } else {
 
1908
                /*
 
1909
                 *      There was no response
 
1910
                 */
 
1911
                setup_post_proxy_fail(request);
 
1912
        }
 
1913
 
 
1914
        ev_request_free(&fake);
 
1915
 
 
1916
        process_proxy_reply(request);
1202
1917
 
1203
1918
        /*
1204
 
         *      And run it through the post-proxy section...
 
1919
         *      Process it through the normal section again, but ONLY
 
1920
         *      if we received a proxy reply..
1205
1921
         */
1206
 
        rad_authenticate(request);
 
1922
        if (request->proxy_reply) {
 
1923
                if (request->server) RDEBUG("server %s {",
 
1924
                                            request->server != NULL ?
 
1925
                                            request->server : ""); 
 
1926
                fun(request);
 
1927
                
 
1928
                if (request->server) RDEBUG("} # server %s",
 
1929
                                            request->server != NULL ?
 
1930
                                            request->server : "");
 
1931
        }
1207
1932
 
1208
1933
        return 2;               /* success, but NOT '1' !*/
1209
1934
}
1210
1935
 
1211
 
 
1212
1936
/*
1213
1937
 *      Return 1 if we did proxy it, or the proxy attempt failed
1214
1938
 *      completely.  Either way, the caller doesn't touch the request
1221
1945
        VALUE_PAIR *realmpair;
1222
1946
        VALUE_PAIR *strippedname;
1223
1947
        VALUE_PAIR *vp;
1224
 
        char *realmname;
 
1948
        char *realmname = NULL;
1225
1949
        home_server *home;
1226
1950
        REALM *realm = NULL;
1227
1951
        home_pool_t *pool;
1231
1955
         *
1232
1956
         *      FIXME: This should really be a serious error.
1233
1957
         */
1234
 
        if (request->in_proxy_hash) {
 
1958
        if (request->in_proxy_hash ||
 
1959
            (request->proxy_reply && (request->proxy_reply->code != 0))) {
1235
1960
                return 0;
1236
1961
        }
1237
1962
 
1238
1963
        realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
1239
1964
        if (!realmpair || (realmpair->length == 0)) {
1240
 
                return 0;
 
1965
                int pool_type;
 
1966
 
 
1967
                vp = pairfind(request->config_items, PW_HOME_SERVER_POOL);
 
1968
                if (!vp) return 0;
 
1969
 
 
1970
                switch (request->packet->code) {
 
1971
                case PW_AUTHENTICATION_REQUEST:
 
1972
                        pool_type = HOME_TYPE_AUTH;
 
1973
                        break;
 
1974
 
 
1975
#ifdef WITH_ACCOUNTING
 
1976
                case PW_ACCOUNTING_REQUEST:
 
1977
                        pool_type = HOME_TYPE_ACCT;
 
1978
                        break;
 
1979
#endif
 
1980
 
 
1981
#ifdef WITH_COA
 
1982
                case PW_COA_REQUEST:
 
1983
                case PW_DISCONNECT_REQUEST:
 
1984
                        pool_type = HOME_TYPE_COA;
 
1985
                        break;
 
1986
#endif
 
1987
 
 
1988
                default:
 
1989
                        return 0;
 
1990
                }
 
1991
 
 
1992
                pool = home_pool_byname(vp->vp_strvalue, pool_type);
 
1993
                if (!pool) {
 
1994
                        RDEBUG2("ERROR: Cannot proxy to unknown pool %s",
 
1995
                                vp->vp_strvalue);
 
1996
                        return 0;
 
1997
                }
 
1998
 
 
1999
                realmname = NULL; /* no realms */
 
2000
                realm = NULL;
 
2001
                goto found_pool;
1241
2002
        }
1242
2003
 
1243
2004
        realmname = (char *) realmpair->vp_strvalue;
1244
2005
 
1245
2006
        realm = realm_find2(realmname);
1246
2007
        if (!realm) {
1247
 
                DEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname);
 
2008
                RDEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname);
1248
2009
                return 0;
1249
2010
        }
1250
2011
 
1254
2015
        if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1255
2016
                pool = realm->auth_pool;
1256
2017
 
 
2018
#ifdef WITH_ACCOUNTING
1257
2019
        } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1258
2020
                pool = realm->acct_pool;
 
2021
#endif
 
2022
 
 
2023
#ifdef WITH_COA
 
2024
        } else if ((request->packet->code == PW_COA_REQUEST) ||
 
2025
                   (request->packet->code == PW_DISCONNECT_REQUEST)) {
 
2026
                pool = realm->acct_pool;
 
2027
#endif
1259
2028
 
1260
2029
        } else {
1261
2030
                rad_panic("Internal sanity check failed");
1262
2031
        }
1263
2032
 
1264
2033
        if (!pool) {
1265
 
                DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
 
2034
                RDEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
1266
2035
                       realmname);
1267
2036
                return 0;
1268
2037
        }
1269
2038
 
 
2039
found_pool:
1270
2040
        home = home_server_ldb(realmname, pool, request);
1271
2041
        if (!home) {
1272
 
                DEBUG2("ERROR: Failed to find live home server for realm %s",
 
2042
                RDEBUG2("ERROR: Failed to find live home server for realm %s",
1273
2043
                       realmname);
1274
2044
                return -1;
1275
2045
        }
1276
2046
        request->home_pool = pool;
1277
2047
 
 
2048
#ifdef WITH_COA
 
2049
        /*
 
2050
         *      Once we've decided to proxy a request, we cannot send
 
2051
         *      a CoA packet.  So we free up any CoA packet here.
 
2052
         */
 
2053
        ev_request_free(&request->coa);
 
2054
#endif
1278
2055
        /*
1279
2056
         *      Remember that we sent the request to a Realm.
1280
2057
         */
1281
 
        pairadd(&request->packet->vps,
1282
 
                pairmake("Realm", realmname, T_OP_EQ));
1283
 
 
1284
 
        /*
1285
 
         *      We read the packet from a detail file, AND it came from
1286
 
         *      the server we're about to send it to.  Don't do that.
1287
 
         */
1288
 
        if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
1289
 
            (request->listener->type == RAD_LISTEN_DETAIL) &&
1290
 
            (home->ipaddr.af == AF_INET) &&
1291
 
            (request->packet->src_ipaddr.af == AF_INET) &&
1292
 
            (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
1293
 
                DEBUG2("    rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
1294
 
                return 0;
1295
 
        }
1296
 
 
1297
 
        /*
1298
 
         *      Allocate the proxy packet, only if it wasn't already
1299
 
         *      allocated by a module.  This check is mainly to support
1300
 
         *      the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
1301
 
         *
1302
 
         *      In those cases, the EAP module creates a "fake"
1303
 
         *      request, and recursively passes it through the
1304
 
         *      authentication stage of the server.  The module then
1305
 
         *      checks if the request was supposed to be proxied, and
1306
 
         *      if so, creates a proxy packet from the TUNNELED request,
1307
 
         *      and not from the EAP request outside of the tunnel.
1308
 
         *
1309
 
         *      The proxy then works like normal, except that the response
1310
 
         *      packet is "eaten" by the EAP module, and encapsulated into
1311
 
         *      an EAP packet.
1312
 
         */
1313
 
        if (!request->proxy) {
1314
 
                if ((request->proxy = rad_alloc(TRUE)) == NULL) {
1315
 
                        radlog(L_ERR|L_CONS, "no memory");
1316
 
                        exit(1);
1317
 
                }
1318
 
 
1319
 
                /*
1320
 
                 *      Copy the request, then look up name and
1321
 
                 *      plain-text password in the copy.
1322
 
                 *
1323
 
                 *      Note that the User-Name attribute is the
1324
 
                 *      *original* as sent over by the client.  The
1325
 
                 *      Stripped-User-Name attribute is the one hacked
1326
 
                 *      through the 'hints' file.
1327
 
                 */
1328
 
                request->proxy->vps =  paircopy(request->packet->vps);
1329
 
        }
 
2058
        if (realmname) pairadd(&request->packet->vps,
 
2059
                               pairmake("Realm", realmname, T_OP_EQ));
1330
2060
 
1331
2061
        /*
1332
2062
         *      Strip the name, if told to.
1334
2064
         *      Doing it here catches the case of proxied tunneled
1335
2065
         *      requests.
1336
2066
         */
1337
 
        if (realm->striprealm == TRUE &&
 
2067
        if (realm && (realm->striprealm == TRUE) &&
1338
2068
           (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
1339
2069
                /*
1340
2070
                 *      If there's a Stripped-User-Name attribute in
1373
2103
         *      since we can't use the request authenticator
1374
2104
         *      anymore - we changed it.
1375
2105
         */
1376
 
        if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
 
2106
        if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
 
2107
            pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
1377
2108
            pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
1378
2109
                vp = radius_paircreate(request, &request->proxy->vps,
1379
2110
                                       PW_CHAP_CHALLENGE, PW_TYPE_OCTETS);
1396
2127
         *      pre-proxy may use this information, or change it.
1397
2128
         */
1398
2129
        request->proxy->code = request->packet->code;
1399
 
        request->proxy->dst_ipaddr = home->ipaddr;
1400
 
        request->proxy->dst_port = home->port;
1401
 
        request->home_server = home;
1402
2130
 
1403
2131
        /*
1404
2132
         *      Call the pre-proxy routines.
1405
2133
         */
1406
2134
        vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1407
2135
        if (vp) {
1408
 
                DEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
 
2136
                RDEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
1409
2137
                pre_proxy_type = vp->vp_integer;
1410
2138
        }
1411
2139
 
1415
2143
                const char *old_server = request->server;
1416
2144
                
1417
2145
                request->server = request->home_pool->virtual_server;
1418
 
                DEBUG2(" server %s {", request->server);
 
2146
                RDEBUG2(" server %s {", request->server);
1419
2147
                rcode = module_pre_proxy(pre_proxy_type, request);
1420
 
                DEBUG2(" }");
 
2148
                RDEBUG2(" }");
1421
2149
                        request->server = old_server;
1422
2150
        } else {
1423
2151
                rcode = module_pre_proxy(pre_proxy_type, request);
1459
2187
        }
1460
2188
 
1461
2189
        if (!proxy_request(request)) {
1462
 
                DEBUG("ERROR: Failed to proxy request %d", request->number);
 
2190
                RDEBUG("ERROR: Failed to proxy request %d", request->number);
1463
2191
                return -1;
1464
2192
        }
1465
2193
        
1466
2194
        return 1;
1467
2195
}
1468
 
 
 
2196
#endif
1469
2197
 
1470
2198
static void request_post_handler(REQUEST *request)
1471
2199
{
1476
2204
        if ((request->master_state == REQUEST_STOP_PROCESSING) ||
1477
2205
            (request->parent &&
1478
2206
             (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
1479
 
                DEBUG2("Request %d was cancelled.", request->number);
 
2207
                RDEBUG2("Request %d was cancelled.", request->number);
 
2208
#ifdef HAVE_PTHREAD_H
1480
2209
                request->child_pid = NO_SUCH_CHILD_PID;
1481
 
                request->child_state = REQUEST_DONE;
1482
 
                return;
 
2210
#endif
 
2211
                child_state = REQUEST_DONE;
 
2212
                goto cleanup;
1483
2213
        }
1484
2214
 
1485
2215
        if (request->child_state != REQUEST_RUNNING) {
1486
2216
                rad_panic("Internal sanity check failed");
1487
2217
        }
1488
2218
 
1489
 
        if ((request->reply->code == 0) &&
 
2219
#ifdef WITH_COA
 
2220
        /*
 
2221
         *      If it's not in the request hash, it's a CoA request.
 
2222
         *      We hope.
 
2223
         */
 
2224
        if (!request->in_request_hash &&
 
2225
            request->proxy &&
 
2226
            ((request->proxy->code == PW_COA_REQUEST) ||
 
2227
             (request->proxy->code == PW_DISCONNECT_REQUEST))) {
 
2228
                request->next_callback = NULL;
 
2229
                child_state = REQUEST_DONE;
 
2230
                goto cleanup;
 
2231
        }
 
2232
#endif
 
2233
 
 
2234
        /*
 
2235
         *      Catch Auth-Type := Reject BEFORE proxying the packet.
 
2236
         */
 
2237
        if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
 
2238
            (request->reply->code == 0) &&
1490
2239
            ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
1491
2240
            (vp->vp_integer == PW_AUTHTYPE_REJECT)) {
1492
2241
                request->reply->code = PW_AUTHENTICATION_REJECT;
1493
2242
        }
1494
2243
 
 
2244
#ifdef WITH_PROXY
1495
2245
        if (request->root->proxy_requests &&
1496
2246
            !request->in_proxy_hash &&
1497
2247
            (request->reply->code == 0) &&
1499
2249
            (request->packet->code != PW_STATUS_SERVER)) {
1500
2250
                int rcode = successfully_proxied_request(request);
1501
2251
 
1502
 
                if (rcode == 1) return;
 
2252
                if (rcode == 1) return; /* request is invalid */
1503
2253
 
1504
2254
                /*
1505
2255
                 *      Failed proxying it (dead home servers, etc.)
1521
2271
                 *      OR we proxied it internally to a virutal server.
1522
2272
                 */
1523
2273
        }
 
2274
#endif
1524
2275
 
1525
2276
        /*
1526
2277
         *      Fake requests don't get encoded or signed.  The caller
1528
2279
         *      here!
1529
2280
         */
1530
2281
        if (request->packet->dst_port == 0) {
1531
 
                /* FIXME: DEBUG going to the next request */
 
2282
                /* FIXME: RDEBUG going to the next request */
 
2283
#ifdef HAVE_PTHREAD_H
1532
2284
                request->child_pid = NO_SUCH_CHILD_PID;
 
2285
#endif
1533
2286
                request->child_state = REQUEST_DONE;
1534
2287
                return;
1535
2288
        }
1536
2289
 
 
2290
#ifdef WITH_PROXY
1537
2291
        /*
1538
2292
         *      Copy Proxy-State from the request to the reply.
1539
2293
         */
1540
2294
        vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
1541
2295
        if (vp) pairadd(&request->reply->vps, vp);
 
2296
#endif
1542
2297
 
1543
2298
        /*
1544
2299
         *      Access-Requests get delayed or cached.
1553
2308
                         */
1554
2309
                        vp = pairfind(request->config_items,
1555
2310
                                      PW_RESPONSE_PACKET_TYPE);
1556
 
                        if (!vp || (vp->vp_integer != 256)) {
1557
 
                                DEBUG2("There was no response configured: rejecting request %d",
 
2311
                        if (!vp) {
 
2312
                                RDEBUG2("There was no response configured: rejecting request %d",
1558
2313
                                       request->number);
1559
2314
                                request->reply->code = PW_AUTHENTICATION_REJECT;
 
2315
 
 
2316
                        } else if (vp->vp_integer == 256) {
 
2317
                                RDEBUG2("Not responding to request %d",
 
2318
                                       request->number);
 
2319
 
 
2320
                                /*
 
2321
                                 *      Force cleanup after a long
 
2322
                                 *      time, so that we don't
 
2323
                                 *      re-process the packet.
 
2324
                                 */
 
2325
                                request->next_when.tv_sec += request->root->max_request_time;
 
2326
                                request->next_callback = cleanup_delay;
 
2327
                                child_state = REQUEST_CLEANUP_DELAY;
 
2328
                                break;
1560
2329
                        } else {
1561
 
                                DEBUG2("Not responding to request %d",
1562
 
                                       request->number);
 
2330
                                request->reply->code = vp->vp_integer;
 
2331
 
1563
2332
                        }
1564
2333
                }
1565
2334
 
1585
2354
                        when.tv_sec += request->root->reject_delay;
1586
2355
 
1587
2356
                        if (timercmp(&when, &request->next_when, >)) {
1588
 
                                DEBUG2("Delaying reject of request %d for %d seconds",
 
2357
                                RDEBUG2("Delaying reject of request %d for %d seconds",
1589
2358
                                       request->number,
1590
2359
                                       request->root->reject_delay);
1591
2360
                                request->next_when = when;
1592
2361
                                request->next_callback = reject_delay;
 
2362
#ifdef HAVE_PTHREAD_H
1593
2363
                                request->child_pid = NO_SUCH_CHILD_PID;
 
2364
#endif
1594
2365
                                request->child_state = REQUEST_REJECT_DELAY;
1595
2366
                                return;
1596
2367
                        }
1597
2368
                }
1598
2369
 
 
2370
#ifdef WITH_COA
 
2371
        case PW_COA_REQUEST:
 
2372
        case PW_DISCONNECT_REQUEST:
 
2373
#endif
1599
2374
                request->next_when.tv_sec += request->root->cleanup_delay;
1600
2375
                request->next_callback = cleanup_delay;
1601
2376
                child_state = REQUEST_CLEANUP_DELAY;
1616
2391
                break;
1617
2392
 
1618
2393
        default:
1619
 
                if ((request->packet->code > 1024) &&
1620
 
                    (request->packet->code < (1024 + 254 + 1))) {
1621
 
                        request->next_callback = NULL;
1622
 
                        child_state = REQUEST_DONE;
1623
 
                        break;
1624
 
                }
1625
 
 
1626
 
                radlog(L_ERR, "Unknown packet type %d", request->packet->code);
1627
 
                rad_panic("Unknown packet type");
 
2394
                /*
 
2395
                 *      DHCP, VMPS, etc.
 
2396
                 */
 
2397
                request->next_callback = NULL;
 
2398
                child_state = REQUEST_DONE;
1628
2399
                break;
1629
2400
        }
1630
2401
 
1637
2408
         */
1638
2409
        if ((request->reply->code != 0) ||
1639
2410
            (request->listener->type == RAD_LISTEN_DETAIL)) {
 
2411
                DEBUG_PACKET(request, request->reply, 1);
1640
2412
                request->listener->send(request->listener, request);
1641
2413
        }
1642
2414
 
 
2415
#ifdef WITH_COA
 
2416
        /*
 
2417
         *      Now that we've completely processed the request,
 
2418
         *      see if we need to originate a CoA request.
 
2419
         */
 
2420
        if (request->coa ||
 
2421
            (pairfind(request->config_items, PW_SEND_COA_REQUEST) != NULL)) {
 
2422
                if (!originated_coa_request(request)) {
 
2423
                        RDEBUG2("Do CoA Fail handler here");
 
2424
                }
 
2425
                /* request->coa is stil set, so we can update events */
 
2426
        }
 
2427
#endif
 
2428
 
 
2429
 cleanup:
1643
2430
        /*
1644
2431
         *      Clean up.  These are no longer needed.
1645
2432
         */
1651
2438
 
1652
2439
        pairfree(&request->reply->vps);
1653
2440
 
 
2441
#ifdef WITH_PROXY
1654
2442
        if (request->proxy) {
1655
2443
                pairfree(&request->proxy->vps);
1656
2444
 
1658
2446
                        pairfree(&request->proxy_reply->vps);
1659
2447
                }
1660
2448
 
 
2449
#if 0
1661
2450
                /*
1662
2451
                 *      We're not tracking responses from the home
1663
2452
                 *      server, we can therefore free this memory in
1668
2457
                        rad_free(&request->proxy_reply);
1669
2458
                        request->home_server = NULL;
1670
2459
                }
 
2460
#endif
1671
2461
        }
1672
 
 
1673
 
        DEBUG2("Finished request %d.", request->number);
1674
 
 
 
2462
#endif
 
2463
 
 
2464
        RDEBUG2("Finished request %d.", request->number);
 
2465
        rad_assert(child_state >= 0);
1675
2466
        request->child_state = child_state;
1676
2467
 
1677
2468
        /*
1683
2474
 
1684
2475
static void received_retransmit(REQUEST *request, const RADCLIENT *client)
1685
2476
{
 
2477
#ifdef WITH_PROXY
1686
2478
        char buffer[128];
1687
 
 
1688
 
        RAD_SNMP_TYPE_INC(request->listener, total_dup_requests);
1689
 
        RAD_SNMP_CLIENT_INC(request->listener, client, dup_requests);
1690
 
 
 
2479
#endif
 
2480
 
 
2481
        RAD_STATS_TYPE_INC(request->listener, total_dup_requests);
 
2482
        RAD_STATS_CLIENT_INC(request->listener, client, total_dup_requests);
 
2483
        
1691
2484
        switch (request->child_state) {
1692
2485
        case REQUEST_QUEUED:
1693
2486
        case REQUEST_RUNNING:
 
2487
#ifdef WITH_PROXY
1694
2488
        discard:
 
2489
#endif
1695
2490
                radlog(L_ERR, "Discarding duplicate request from "
1696
2491
                       "client %s port %d - ID: %d due to unfinished request %d",
1697
2492
                       client->shortname,
1699
2494
                       request->number);
1700
2495
                break;
1701
2496
 
 
2497
#ifdef WITH_PROXY
1702
2498
        case REQUEST_PROXIED:
1703
2499
                /*
1704
2500
                 *      We're not supposed to have duplicate
1711
2507
                 *
1712
2508
                 *      Instead, we just discard the packet.  We may
1713
2509
                 *      eventually respond, or the client will send a
1714
 
                 *      new accounting packet.
 
2510
                 *      new accounting packet.            
 
2511
                 *
 
2512
                 *      The same comments go for Status-Server, and
 
2513
                 *      other packet types.
 
2514
                 *
 
2515
                 *      FIXME: coa: when we proxy CoA && Disconnect
 
2516
                 *      packets, this logic has to be fixed.
1715
2517
                 */
1716
 
                if (request->packet->code == PW_ACCOUNTING_REQUEST) {
 
2518
                if (request->packet->code != PW_AUTHENTICATION_REQUEST) {
1717
2519
                        goto discard;
1718
2520
                }
1719
2521
 
1731
2533
 
1732
2534
                        home = home_server_ldb(NULL, request->home_pool, request);
1733
2535
                        if (!home) {
1734
 
                                DEBUG2("Failed to find live home server for request %d", request->number);
 
2536
                                RDEBUG2("Failed to find live home server for request %d", request->number);
1735
2537
                        no_home_servers:
1736
2538
                                /*
1737
2539
                                 *      Do post-request processing,
1743
2545
                        }
1744
2546
 
1745
2547
                        request->proxy->code = request->packet->code;
1746
 
                        request->proxy->dst_ipaddr = home->ipaddr;
1747
 
                        request->proxy->dst_port = home->port;
1748
 
                        request->home_server = home;
1749
2548
 
1750
2549
                        /*
1751
2550
                         *      Free the old packet, to force re-encoding
1755
2554
                        request->proxy->data_len = 0;
1756
2555
 
1757
2556
                        /*
 
2557
                         *      This request failed over to a virtual
 
2558
                         *      server.  Push it back onto the queue
 
2559
                         *      to be processed.
 
2560
                         */
 
2561
                        if (request->home_server->server) {
 
2562
                                proxy_fallback_handler(request);
 
2563
                                return;
 
2564
                        }
 
2565
 
 
2566
                        /*
1758
2567
                         *      Try to proxy the request.
1759
2568
                         */
1760
2569
                        if (!proxy_request(request)) {
1761
 
                                DEBUG("ERROR: Failed to re-proxy request %d", request->number);
 
2570
                                RDEBUG("ERROR: Failed to re-proxy request %d", request->number);
1762
2571
                                goto no_home_servers;
1763
2572
                        }
1764
2573
 
1772
2581
                        return;
1773
2582
                } /* else the home server is still alive */
1774
2583
 
1775
 
                DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
 
2584
                RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
1776
2585
                       inet_ntop(request->proxy->dst_ipaddr.af,
1777
2586
                                 &request->proxy->dst_ipaddr.ipaddr,
1778
2587
                                 buffer, sizeof(buffer)),
1779
2588
                       request->proxy->dst_port,
1780
2589
                       request->proxy->id);
1781
2590
                request->num_proxied_requests++;
 
2591
 
 
2592
                DEBUG_PACKET(request, request->proxy, 1);
1782
2593
                request->proxy_listener->send(request->proxy_listener,
1783
2594
                                              request);
1784
2595
                break;
 
2596
#endif
1785
2597
 
1786
2598
        case REQUEST_REJECT_DELAY:
1787
 
                DEBUG2("Waiting to send Access-Reject "
 
2599
                RDEBUG2("Waiting to send Access-Reject "
1788
2600
                       "to client %s port %d - ID: %d",
1789
2601
                       client->shortname,
1790
2602
                       request->packet->src_port, request->packet->id);
1792
2604
 
1793
2605
        case REQUEST_CLEANUP_DELAY:
1794
2606
        case REQUEST_DONE:
1795
 
                DEBUG2("Sending duplicate reply "
 
2607
                if (request->reply->code == 0) {
 
2608
                        RDEBUG2("Ignoring retransmit from client %s port %d "
 
2609
                                "- ID: %d, no reply was configured",
 
2610
                                client->shortname,
 
2611
                                request->packet->src_port, request->packet->id);
 
2612
                        return;
 
2613
                }
 
2614
 
 
2615
                /*
 
2616
                 *      FIXME: This sends duplicate replies to
 
2617
                 *      accounting requests, even if Acct-Delay-Time
 
2618
                 *      or Event-Timestamp is in the packet.  In those
 
2619
                 *      cases, the Id should be changed, and the packet
 
2620
                 *      re-calculated.
 
2621
                 */
 
2622
                RDEBUG2("Sending duplicate reply "
1796
2623
                       "to client %s port %d - ID: %d",
1797
2624
                       client->shortname,
1798
2625
                       request->packet->src_port, request->packet->id);
 
2626
                DEBUG_PACKET(request, request->reply, 1);
1799
2627
                request->listener->send(request->listener, request);
1800
2628
                break;
1801
2629
        }
1818
2646
        remove_from_request_hash(request);
1819
2647
 
1820
2648
        switch (request->child_state) {
 
2649
#ifdef HAVE_PTHREAD_H
1821
2650
                /*
1822
2651
                 *      It's queued or running.  Tell it to stop, and
1823
2652
                 *      wait for it to do so.
1831
2660
 
1832
2661
                INSERT_EVENT(wait_for_child_to_die, request);
1833
2662
                return;
 
2663
#endif
 
2664
 
 
2665
                /*
 
2666
                 *      Catch race conditions.  It may have switched
 
2667
                 *      from running to done while this code is being
 
2668
                 *      executed.
 
2669
                 */
 
2670
        case REQUEST_REJECT_DELAY:
 
2671
        case REQUEST_CLEANUP_DELAY:
 
2672
        case REQUEST_DONE:
 
2673
                break;
1834
2674
 
1835
2675
                /*
1836
2676
                 *      It's in some other state, and therefore also
1837
2677
                 *      in the event queue.  At some point, the
1838
2678
                 *      child will notice, and we can then delete it.
1839
2679
                 */
 
2680
        case REQUEST_PROXIED:
1840
2681
        default:
1841
2682
                rad_assert(request->ev != NULL);
1842
2683
                break;
1922
2763
                        struct timeval when;
1923
2764
 
1924
2765
                default:
 
2766
                        /*
 
2767
                         *      Special hacks for race conditions.
 
2768
                         *      The reply is encoded, and therefore
 
2769
                         *      likely sent.  We received a *new*
 
2770
                         *      packet from the client, likely before
 
2771
                         *      the next line or two of code which
 
2772
                         *      updated the child state.  In this
 
2773
                         *      case, just accept the new request.
 
2774
                         */
 
2775
                        if ((request->reply->code != 0) &&
 
2776
                            request->reply->data) {
 
2777
                                radlog(L_INFO, "WARNING: Allowing fast client %s port %d - ID: %d for recent request %d.",
 
2778
                                       client->shortname,
 
2779
                                       packet->src_port, packet->id,
 
2780
                                       request->number);
 
2781
                                remove_from_request_hash(request);
 
2782
                                request = NULL;
 
2783
                                break;
 
2784
                        }
 
2785
 
1925
2786
                        gettimeofday(&when, NULL);
1926
2787
                        when.tv_sec -= 1;
1927
2788
 
1981
2842
        request->packet->timestamp = request->timestamp;
1982
2843
        request->number = request_num_counter++;
1983
2844
        request->priority = listener->type;
 
2845
#ifdef HAVE_PTHREAD_H
 
2846
        request->child_pid = NO_SUCH_CHILD_PID;
 
2847
#endif
 
2848
 
 
2849
        /*
 
2850
         *      Status-Server packets go to the head of the queue.
 
2851
         */
 
2852
        if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
1984
2853
 
1985
2854
        /*
1986
2855
         *      Set virtual server identity
1998
2867
         */
1999
2868
        if (!fr_packet_list_insert(pl, &request->packet)) {
2000
2869
                radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number);
2001
 
                request_free(&request);
 
2870
                ev_request_free(&request);
2002
2871
                return 0;
2003
2872
        }
2004
2873
 
2049
2918
}
2050
2919
 
2051
2920
 
 
2921
#ifdef WITH_PROXY
2052
2922
REQUEST *received_proxy_response(RADIUS_PACKET *packet)
2053
2923
{
2054
2924
        char            buffer[128];
2055
 
        home_server     *home;
2056
2925
        REQUEST         *request;
2057
2926
 
2058
 
        if (!home_server_find(&packet->src_ipaddr, packet->src_port)) {
2059
 
                radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
2060
 
                       inet_ntop(packet->src_ipaddr.af,
2061
 
                                 &packet->src_ipaddr.ipaddr,
2062
 
                                 buffer, sizeof(buffer)),
2063
 
                               packet->src_port);
2064
 
                rad_free(&packet);
2065
 
                return NULL;
2066
 
        }
2067
 
 
2068
2927
        /*
2069
2928
         *      Also removes from the proxy hash if responses == requests
2070
2929
         */
2071
2930
        request = lookup_in_proxy_hash(packet);
2072
2931
 
2073
2932
        if (!request) {
2074
 
                radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
 
2933
                radlog(L_PROXY, "No outstanding request was found for reply from host %s port %d - ID %d",
2075
2934
                       inet_ntop(packet->src_ipaddr.af,
2076
2935
                                 &packet->src_ipaddr.ipaddr,
2077
2936
                                 buffer, sizeof(buffer)),
2078
2937
                       packet->src_port, packet->id);
2079
 
                rad_free(&packet);
2080
 
                return NULL;
2081
 
        }
2082
 
 
2083
 
        home = request->home_server;
2084
 
 
2085
 
        gettimeofday(&now, NULL);
2086
 
        home->state = HOME_STATE_ALIVE;
2087
 
 
2088
 
        if (request->reply && request->reply->code != 0) {
2089
 
                DEBUG2("We already replied to this request.  Discarding response from home server.");
2090
 
                rad_free(&packet);
2091
2938
                return NULL;
2092
2939
        }
2093
2940
 
2094
2941
        /*
2095
 
         *      We had previously received a reply, so we don't need
2096
 
         *      to do anything here.
 
2942
         *      We haven't replied to the NAS, but we have seen an
 
2943
         *      earlier reply from the home server.  Ignore this packet,
 
2944
         *      as we're likely still processing the previous reply.
2097
2945
         */
2098
2946
        if (request->proxy_reply) {
2099
2947
                if (memcmp(request->proxy_reply->vector,
2100
2948
                           packet->vector,
2101
2949
                           sizeof(request->proxy_reply->vector)) == 0) {
2102
 
                        DEBUG2("Discarding duplicate reply from home server %s port %d  - ID: %d for request %d",
 
2950
                        RDEBUG2("Discarding duplicate reply from host %s port %d  - ID: %d for request %d",
2103
2951
                               inet_ntop(packet->src_ipaddr.af,
2104
2952
                                         &packet->src_ipaddr.ipaddr,
2105
2953
                                         buffer, sizeof(buffer)),
2108
2956
                } else {
2109
2957
                        /*
2110
2958
                         *      ? The home server gave us a new proxy
2111
 
                         *      reply, which doesn't match the old
 
2959
                         *      reply which doesn't match the old
2112
2960
                         *      one.  Delete it.
2113
2961
                         */
2114
 
                        DEBUG2("Ignoring conflicting proxy reply");
 
2962
                        RDEBUG2("Ignoring conflicting proxy reply");
2115
2963
                }
2116
 
 
 
2964
                
2117
2965
                /* assert that there's an event queued for request? */
2118
 
                rad_free(&packet);
2119
 
                return NULL;
2120
 
        }
 
2966
                return NULL;
 
2967
        }
 
2968
 
 
2969
        /*
 
2970
         *      Verify the packet before doing ANYTHING with it.  This
 
2971
         *      means we're doing more MD5 checks in the server core.
 
2972
         *      However, we can fix that by moving to multiple threads
 
2973
         *      listening on sockets.
 
2974
         *
 
2975
         *      We do this AFTER looking the request up in the hash,
 
2976
         *      and AFTER vhecking if we saw a previous request.  This
 
2977
         *      helps minimize the DoS effect of people attacking us
 
2978
         *      with spoofed packets.
 
2979
         */
 
2980
        if (rad_verify(packet, request->proxy,
 
2981
                       request->home_server->secret) != 0) {
 
2982
                DEBUG("Ignoring spoofed proxy reply.  Signature is invalid");
 
2983
                return NULL;
 
2984
        }
 
2985
 
 
2986
        gettimeofday(&now, NULL);
 
2987
 
 
2988
        /*
 
2989
         *      Maybe move this earlier in the decision process?
 
2990
         *      Having it here means that late or duplicate proxy
 
2991
         *      replies no longer get the home server marked as
 
2992
         *      "alive".  This might be good for stability, though.
 
2993
         *
 
2994
         *      FIXME: Do we really want to do this whenever we
 
2995
         *      receive a packet?  Setting this here means that we
 
2996
         *      mark it alive on *any* packet, even if it's lost all
 
2997
         *      of the *other* packets in the last 10s.
 
2998
         */
 
2999
        request->home_server->state = HOME_STATE_ALIVE;
 
3000
        
 
3001
#ifdef WITH_COA
 
3002
        /*
 
3003
         *      When originating CoA, the "proxy" reply is the reply
 
3004
         *      to the CoA request that we originated.  At this point,
 
3005
         *      the original request is finished, and it has a reply.
 
3006
         *
 
3007
         *      However, if we haven't separated the two requests, do
 
3008
         *      so now.  This is done so that cleaning up the original
 
3009
         *      request won't cause the CoA request to be free'd.  See
 
3010
         *      util.c, request_free()
 
3011
         */
 
3012
        if (request->parent && (request->parent->coa == request)) {
 
3013
                request->parent->coa = NULL;
 
3014
                request->parent = NULL;
 
3015
 
 
3016
        } else
 
3017
                /*
 
3018
                 *      Skip the next set of checks, as the original
 
3019
                 *      reply is cached.  We want to be able to still
 
3020
                 *      process the CoA reply, AND to reference the
 
3021
                 *      original request/reply.
 
3022
                 *
 
3023
                 *      This is getting to be really quite a bit of a
 
3024
                 *      hack.
 
3025
                 */
 
3026
#endif
 
3027
 
 
3028
        /*
 
3029
         *      If there's a reply to the NAS, ignore everything
 
3030
         *      related to proxy responses
 
3031
         */
 
3032
        if (request->reply && request->reply->code != 0) {
 
3033
                RDEBUG2("Ignoring proxy reply that arrived after we sent a reply to the NAS");
 
3034
                return NULL;
 
3035
        }
 
3036
        
 
3037
#ifdef WITH_STATS
 
3038
        /*
 
3039
         *      The average includes our time to receive packets and
 
3040
         *      look them up in the hashes, which should be the same
 
3041
         *      for all packets.
 
3042
         *
 
3043
         *      We update the response time only for the FIRST packet
 
3044
         *      we receive.
 
3045
         */
 
3046
        if (request->home_server->ema.window > 0) {
 
3047
                radius_stats_ema(&request->home_server->ema,
 
3048
                                 &now, &request->proxy_when);
 
3049
        }
 
3050
#endif
2121
3051
 
2122
3052
        switch (request->child_state) {
2123
3053
        case REQUEST_QUEUED:
2124
3054
        case REQUEST_RUNNING:
2125
 
                rad_panic("Internal sanity check failed for child state");
2126
 
                break;
 
3055
                radlog(L_ERR, "Internal sanity check failed for child state");
 
3056
                /* FALL-THROUGH */
2127
3057
 
2128
3058
        case REQUEST_REJECT_DELAY:
2129
3059
        case REQUEST_CLEANUP_DELAY:
2135
3065
                       packet->src_port, packet->id,
2136
3066
                       request->number);
2137
3067
                /* assert that there's an event queued for request? */
2138
 
                rad_free(&packet);
2139
3068
                return NULL;
2140
3069
 
2141
3070
        case REQUEST_PROXIED:
2147
3076
#if 0
2148
3077
        /*
2149
3078
         *      Perform RTT calculations, as per RFC 2988 (for TCP).
2150
 
         *      Note that we do so only if we sent one request, and
2151
 
         *      received one response.  If we sent two requests, we
2152
 
         *      have no idea if the response is for the first, or for
2153
 
         *      the second request/
 
3079
         *      Note that we only do so on the first response.
2154
3080
         */
2155
 
        if (request->num_proxied_requests == 1) {
 
3081
        if ((request->num_proxied_responses == 1)
2156
3082
                int rtt;
2157
3083
                home_server *home = request->home_server;
2158
3084
 
2189
3115
         */
2190
3116
        if (!request->packet) {
2191
3117
                received_response_to_ping(request);
 
3118
                request->proxy_reply = NULL; /* caller will free it */
 
3119
                ev_request_free(&request);
2192
3120
                return NULL;
2193
3121
        }
2194
3122
 
2205
3133
 
2206
3134
        return request;
2207
3135
}
2208
 
 
2209
 
 
2210
 
static void event_detail_timer(void *ctx)
 
3136
#endif
 
3137
 
 
3138
void event_new_fd(rad_listen_t *this)
2211
3139
{
2212
 
        rad_listen_t *listener = ctx;
2213
 
        RAD_REQUEST_FUNP fun;
2214
 
        REQUEST *request;
 
3140
        char buffer[1024];
2215
3141
 
2216
 
        if (listener->recv(listener, &fun, &request)) {
2217
 
                if (!thread_pool_addrequest(request, fun)) {
2218
 
                        request->child_state = REQUEST_DONE;
2219
 
                }
 
3142
        if (this->status == RAD_LISTEN_STATUS_KNOWN) return;
 
3143
        
 
3144
        this->print(this, buffer, sizeof(buffer));
 
3145
        
 
3146
        if (this->status == RAD_LISTEN_STATUS_INIT) {
 
3147
                if (just_started) {
 
3148
                        DEBUG("Listening on %s", buffer);
 
3149
                } else {
 
3150
                        DEBUG2(" ... adding new socket %s", buffer);
 
3151
                }
 
3152
                if (!fr_event_fd_insert(el, 0, this->fd,
 
3153
                                        event_socket_handler, this)) {
 
3154
                        radlog(L_ERR, "Failed remembering handle for proxy socket!");
 
3155
                        exit(1);
 
3156
                }
 
3157
                
 
3158
                this->status = RAD_LISTEN_STATUS_KNOWN;
 
3159
                return;
 
3160
        }
 
3161
        
 
3162
        if (this->status == RAD_LISTEN_STATUS_CLOSED) {
 
3163
                DEBUG2(" ... closing socket %s", buffer);
 
3164
                
 
3165
                fr_event_fd_delete(el, 0, this->fd);
 
3166
                this->status = RAD_LISTEN_STATUS_FINISH;
 
3167
                
 
3168
                /*
 
3169
                 *      Close the fd AFTER fixing up the requests and
 
3170
                 *      listeners, so that they don't send/recv on the
 
3171
                 *      wrong socket (if someone manages to open
 
3172
                 *      another one).
 
3173
                 */
 
3174
                close(this->fd);
 
3175
                this->fd = -1;
2220
3176
        }
2221
3177
}
2222
3178
 
2251
3207
                fr_event_loop_exit(el, 0x80);
2252
3208
        }
2253
3209
 
 
3210
#ifdef WITH_DETAIL
2254
3211
        if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
2255
3212
                rad_listen_t *this;
2256
3213
                
 
3214
                /*
 
3215
                 *      FIXME: O(N) loops suck.
 
3216
                 */
2257
3217
                for (this = mainconfig.listen;
2258
3218
                     this != NULL;
2259
3219
                     this = this->next) {
2260
 
                        int delay;
2261
 
                        struct timeval when;
2262
 
 
2263
3220
                        if (this->type != RAD_LISTEN_DETAIL) continue;
2264
 
                        
2265
 
                        delay = detail_delay(this);
2266
 
                        if (!delay) continue;
2267
 
 
2268
 
                        fr_event_now(el, &now);
2269
 
                        when = now;
2270
 
                        tv_add(&when, delay);
2271
 
 
2272
 
                        if (delay > 100000) {
2273
 
                                DEBUG2("Delaying next detail event for %d.%01u seconds.",
2274
 
                                       delay / USEC, (delay % USEC) / 100000);
2275
 
                        }
2276
 
 
2277
 
                        if (!fr_event_insert(el, event_detail_timer, this,
2278
 
                                             &when, NULL)) {
2279
 
                                radlog(L_ERR, "Failed remembering timer");
2280
 
                                exit(1);
2281
 
                        }
 
3221
 
 
3222
                        /*
 
3223
                         *      This one didn't send the signal, skip
 
3224
                         *      it.
 
3225
                         */
 
3226
                        if (!this->decode(this, NULL)) continue;
 
3227
 
 
3228
                        /*
 
3229
                         *      Go service the interrupt.
 
3230
                         */
 
3231
                        event_poll_detail(this);
2282
3232
                }
2283
3233
        }
 
3234
#endif
2284
3235
 
2285
3236
        if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
2286
3237
                rad_listen_t *this;
2288
3239
                for (this = mainconfig.listen;
2289
3240
                     this != NULL;
2290
3241
                     this = this->next) {
2291
 
                        if (this->type != RAD_LISTEN_PROXY) continue;
2292
 
                        
2293
 
                        if (!fr_event_fd_insert(el, 0, this->fd,
2294
 
                                                event_socket_handler, this)) {
2295
 
                                radlog(L_ERR, "Failed remembering handle for proxy socket!");
2296
 
                                exit(1);
2297
 
                        }
 
3242
                        event_new_fd(this);
2298
3243
                }
2299
3244
        }
2300
3245
}
2301
3246
 
2302
 
#ifdef __MINGW32__
 
3247
#ifndef WITH_SELF_PIPE
2303
3248
void radius_signal_self(int flag)
2304
3249
{
2305
3250
        handle_signal_self(flag);
2374
3319
        }
2375
3320
}
2376
3321
 
 
3322
typedef struct listen_detail_t {
 
3323
        fr_event_t      *ev;
 
3324
} listen_detail_t;
2377
3325
 
2378
3326
/*
2379
 
 *      This function is called periodically to see if any FD's are
2380
 
 *      available for reading.
 
3327
 *      This function is called periodically to see if this detail
 
3328
 *      file is available for reading.
2381
3329
 */
2382
 
static void event_poll_fds(UNUSED void *ctx)
 
3330
static void event_poll_detail(void *ctx)
2383
3331
{
2384
 
        int rcode;
 
3332
        int rcode, delay;
2385
3333
        RAD_REQUEST_FUNP fun;
2386
3334
        REQUEST *request;
2387
 
        rad_listen_t *this;
 
3335
        rad_listen_t *this = ctx;
2388
3336
        struct timeval when;
2389
 
 
2390
 
        fr_event_now(el, &now);
 
3337
        listen_detail_t *detail = this->data;
 
3338
 
 
3339
        rad_assert(this->type == RAD_LISTEN_DETAIL);
 
3340
 
 
3341
        /*
 
3342
         *      Try to read something.
 
3343
         *
 
3344
         *      FIXME: This does poll AND receive.
 
3345
         */
 
3346
        rcode = this->recv(this, &fun, &request);
 
3347
        if (rcode != 0) {
 
3348
                rad_assert(fun != NULL);
 
3349
                rad_assert(request != NULL);
 
3350
                
 
3351
                if (!thread_pool_addrequest(request, fun)) {
 
3352
                        request->child_state = REQUEST_DONE;
 
3353
                }
 
3354
        }
 
3355
 
 
3356
        if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
2391
3357
        when = now;
2392
 
        when.tv_sec += 1;
2393
 
 
2394
 
        for (this = mainconfig.listen; this != NULL; this = this->next) {
2395
 
                if (this->fd >= 0) continue;
2396
 
 
2397
 
                /*
2398
 
                 *      Try to read something.
2399
 
                 *
2400
 
                 *      FIXME: This does poll AND receive.
2401
 
                 */
2402
 
                rcode = this->recv(this, &fun, &request);
2403
 
                if (!rcode) continue;
2404
 
                
2405
 
                rad_assert(fun != NULL);
2406
 
                rad_assert(request != NULL);
2407
 
                        
2408
 
                if (!thread_pool_addrequest(request, fun)) {
2409
 
                        request->child_state = REQUEST_DONE;
2410
 
                }
2411
 
 
2412
 
                /*
2413
 
                 *      We have an FD.  Start watching it.
2414
 
                 */
2415
 
                if (this->fd >= 0) {
2416
 
                        /*
2417
 
                         *      ... unless it's a detail file.  In
2418
 
                         *      that case, we rely on the signal to
2419
 
                         *      self to know when to continue
2420
 
                         *      processing the detail file.
2421
 
                         */
2422
 
                        if (this->type == RAD_LISTEN_DETAIL) continue;
2423
 
 
2424
 
                        /*
2425
 
                         *      FIXME: this should be SNMP handler,
2426
 
                         *      and we should do SOMETHING when the
2427
 
                         *      fd is closed!
2428
 
                         */
2429
 
                        if (!fr_event_fd_insert(el, 0, this->fd,
2430
 
                                                event_socket_handler, this)) {
2431
 
                                char buffer[256];
2432
 
                                
2433
 
                                this->print(this, buffer, sizeof(buffer));
2434
 
                                rad_panic("Failed creating handler for snmp");
2435
 
                        }
2436
 
                }
2437
 
        }
2438
3358
 
2439
3359
        /*
2440
 
         *      Reset the poll.
 
3360
         *      Backdoor API to get the delay until the next poll
 
3361
         *      time.
2441
3362
         */
2442
 
        if (!fr_event_insert(el, event_poll_fds, NULL,
2443
 
                             &when, NULL)) {
 
3363
        delay = this->encode(this, NULL);
 
3364
        tv_add(&when, delay);
 
3365
 
 
3366
        if (!fr_event_insert(el, event_poll_detail, this,
 
3367
                             &when, &detail->ev)) {
2444
3368
                radlog(L_ERR, "Failed creating handler");
2445
3369
                exit(1);
2446
3370
        }
2490
3414
 
2491
3415
}
2492
3416
 
2493
 
 
2494
3417
/*
2495
3418
 *      Externally-visibly functions.
2496
3419
 */
2497
3420
int radius_event_init(CONF_SECTION *cs, int spawn_flag)
2498
3421
{
2499
 
        int i;
2500
 
        int has_snmp_listener = FALSE;
2501
3422
        rad_listen_t *this, *head = NULL;
2502
3423
 
2503
3424
        if (el) return 0;
2504
3425
 
2505
 
        time(&start_time);
 
3426
        time(&fr_start_time);
2506
3427
 
2507
3428
        el = fr_event_list_create(event_status);
2508
3429
        if (!el) return 0;
2509
3430
 
2510
3431
        pl = fr_packet_list_create(0);
2511
 
        if (!el) return 0;
 
3432
        if (!pl) return 0;      /* leak el */
2512
3433
 
2513
3434
        request_num_counter = 0;
2514
3435
 
2515
 
        /*
2516
 
         *      Move all of the thread calls to this file?
2517
 
         *
2518
 
         *      It may be best for the mutexes to be in this file...
2519
 
         */
2520
 
        have_children = spawn_flag;
2521
 
 
 
3436
#ifdef WITH_PROXY
2522
3437
        if (mainconfig.proxy_requests) {
 
3438
                pthread_mutexattr_t attr;
 
3439
 
2523
3440
                /*
2524
3441
                 *      Create the tree for managing proxied requests and
2525
3442
                 *      responses.
2528
3445
                if (!proxy_list) return 0;
2529
3446
 
2530
3447
#ifdef HAVE_PTHREAD_H
 
3448
                pthread_mutexattr_init(&attr);
 
3449
 
 
3450
#ifdef PTHREAD_MUTEX_RECURSIVE
 
3451
                if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) < 0) {
 
3452
                        radlog(L_ERR, "FATAL: Failed to set type for proxy mutex: %s",
 
3453
                               strerror(errno));
 
3454
                        exit(1);
 
3455
                }
 
3456
#endif
 
3457
 
2531
3458
                if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
2532
3459
                        radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
2533
3460
                               strerror(errno));
2534
3461
                        exit(1);
2535
3462
                }
 
3463
 
 
3464
                pthread_mutexattr_destroy(&attr);
2536
3465
#endif
2537
3466
        }
 
3467
#endif
2538
3468
 
2539
3469
        /*
2540
3470
         *      Just before we spawn the child threads, force the log
2543
3473
        if (spawn_flag) force_log_reopen();
2544
3474
 
2545
3475
#ifdef HAVE_PTHREAD_H
2546
 
        if (thread_pool_init(cs, spawn_flag) < 0) {
 
3476
#ifndef __MINGW32__
 
3477
        NO_SUCH_CHILD_PID = (pthread_t ) (0);
 
3478
#else
 
3479
        NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
 
3480
#endif
 
3481
        /*
 
3482
         *      Initialize the threads ONLY if we're spawning, AND
 
3483
         *      we're running normally.
 
3484
         */
 
3485
        if (spawn_flag && !check_config &&
 
3486
            (thread_pool_init(cs, &spawn_flag) < 0)) {
2547
3487
                exit(1);
2548
3488
        }
2549
3489
#endif
2550
3490
 
 
3491
        /*
 
3492
         *      Move all of the thread calls to this file?
 
3493
         *
 
3494
         *      It may be best for the mutexes to be in this file...
 
3495
         */
 
3496
        have_children = spawn_flag;
 
3497
 
2551
3498
        if (check_config) {
2552
 
                DEBUG2("%s: #### Skipping IP addresses and Ports ####",
 
3499
                DEBUG("%s: #### Skipping IP addresses and Ports ####",
2553
3500
                       mainconfig.name);
2554
3501
                return 1;
2555
3502
        }
2556
3503
 
2557
 
#ifndef __MINGW32__
 
3504
#ifdef WITH_SELF_PIPE
2558
3505
        /*
2559
3506
         *      Child threads need a pipe to signal us, as do the
2560
3507
         *      signal handlers.
2580
3527
                radlog(L_ERR, "Failed creating handler for signals");
2581
3528
                exit(1);
2582
3529
        }
2583
 
#endif
 
3530
#endif  /* WITH_SELF_PIPE */
2584
3531
 
 
3532
#ifdef WITH_PROXY
2585
3533
        /*
2586
3534
         *      Mark the proxy Fd's as unused.
2587
3535
         */
2588
 
        for (i = 0; i < 32; i++) proxy_fds[i] = -1;
2589
 
 
2590
 
        DEBUG2("%s: #### Opening IP addresses and Ports ####",
 
3536
        {
 
3537
                int i;
 
3538
 
 
3539
                for (i = 0; i < 32; i++) proxy_fds[i] = -1;
 
3540
        }
 
3541
#endif
 
3542
 
 
3543
       DEBUG("%s: #### Opening IP addresses and Ports ####",
2591
3544
               mainconfig.name);
2592
3545
 
 
3546
       /*
 
3547
        *       The server temporarily switches to an unprivileged
 
3548
        *       user very early in the bootstrapping process.
 
3549
        *       However, some sockets MAY require privileged access
 
3550
        *       (bind to device, or to port < 1024, or to raw
 
3551
        *       sockets).  Those sockets need to call suid up/down
 
3552
        *       themselves around the functions that need a privileged
 
3553
        *       uid.
 
3554
        */
2593
3555
        if (listen_init(cs, &head) < 0) {
2594
3556
                _exit(1);
2595
3557
        }
2596
3558
        
2597
3559
        /*
 
3560
         *      At this point, no one has any business *ever* going
 
3561
         *      back to root uid.
 
3562
         */
 
3563
        fr_suid_down_permanent();
 
3564
 
 
3565
        /*
2598
3566
         *      Add all of the sockets to the event loop.
2599
3567
         */
2600
3568
        for (this = head;
2605
3573
                this->print(this, buffer, sizeof(buffer));
2606
3574
 
2607
3575
                switch (this->type) {
 
3576
#ifdef WITH_DETAIL
2608
3577
                case RAD_LISTEN_DETAIL:
2609
3578
                        DEBUG("Listening on %s", buffer);
2610
 
                        has_detail_listener = TRUE;
2611
 
                        break;
2612
 
 
2613
 
                case RAD_LISTEN_SNMP:
2614
 
                        DEBUG("Listening on SNMP %s", buffer);
2615
 
                        has_snmp_listener = TRUE;
2616
 
                        break;
2617
 
 
 
3579
 
 
3580
                        /*
 
3581
                         *      Detail files are always known, and aren't
 
3582
                         *      put into the socket event loop.
 
3583
                         */
 
3584
                        this->status = RAD_LISTEN_STATUS_KNOWN;
 
3585
 
 
3586
                        /*
 
3587
                         *      Set up the first poll interval.
 
3588
                         */
 
3589
                        event_poll_detail(this);
 
3590
                        break;
 
3591
#endif
 
3592
 
 
3593
#ifdef WITH_PROXY
2618
3594
                case RAD_LISTEN_PROXY:
2619
3595
                        rad_assert(proxy_fds[this->fd & 0x1f] == -1);
2620
3596
                        rad_assert(proxy_listeners[this->fd & 0x1f] == NULL);
2626
3602
                                rad_assert(0 == 1);
2627
3603
                        }
2628
3604
                        /* FALL-THROUGH */
 
3605
#endif
2629
3606
 
2630
3607
                default:
2631
 
                        DEBUG("Listening on %s", buffer);
2632
3608
                        break;
2633
3609
                }
2634
3610
 
2635
 
                /*
2636
 
                 *      The file descriptor isn't ready.  Poll for
2637
 
                 *      when it will become ready.  This is for SNMP
2638
 
                 *      and detail file fd's.
2639
 
                 */
2640
 
                if (this->fd < 0) {
2641
 
                        continue;
2642
 
                }
2643
 
 
2644
 
                /*
2645
 
                 *      The socket is open.  It MUST be a socket,
2646
 
                 *      as we don't pre-open the detail files (yet).
2647
 
                 *
2648
 
                 *      FIXME: if we DO open the detail files automatically,
2649
 
                 *      then much of this code becomes simpler.
2650
 
                 */
2651
 
                if (!fr_event_fd_insert(el, 0, this->fd,
2652
 
                                          event_socket_handler, this)) {
2653
 
                        this->print(this, buffer, sizeof(buffer));
2654
 
                        radlog(L_ERR, "Failed creating handler for socket %s",
2655
 
                               buffer);
2656
 
                        exit(1);
2657
 
                }
2658
 
        }
2659
 
 
2660
 
        if (has_detail_listener || has_snmp_listener) {
2661
 
                struct timeval when;
2662
 
                
2663
 
                gettimeofday(&when, NULL);
2664
 
                when.tv_sec += 1;
2665
 
                
2666
 
                if (!fr_event_insert(el, event_poll_fds, NULL,
2667
 
                                     &when, NULL)) {
2668
 
                        radlog(L_ERR, "Failed creating handler");
2669
 
                        exit(1);
2670
 
                }
 
3611
                event_new_fd(this);
2671
3612
        }
2672
3613
 
2673
3614
        mainconfig.listen = head;
2680
3621
{
2681
3622
        REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
2682
3623
 
 
3624
#ifdef WITH_PROXY
2683
3625
        rad_assert(request->in_proxy_hash == FALSE);
 
3626
#endif
2684
3627
 
2685
 
        fr_event_delete(el, &request->ev);
2686
 
        remove_from_request_hash(request);
2687
 
        request_free(&request);
 
3628
        ev_request_free(&request);
2688
3629
 
2689
3630
        return 0;
2690
3631
}
2691
3632
 
2692
3633
 
 
3634
#ifdef WITH_PROXY
2693
3635
static int proxy_hash_cb(UNUSED void *ctx, void *data)
2694
3636
{
2695
3637
        REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
2696
3638
 
2697
 
        fr_packet_list_yank(proxy_list, request->proxy);
2698
 
        request->in_proxy_hash = FALSE;
2699
 
 
2700
 
        if (!request->in_request_hash) {
2701
 
                fr_event_delete(el, &request->ev);
2702
 
                request_free(&request);
2703
 
        }
 
3639
        ev_request_free(&request);
2704
3640
 
2705
3641
        return 0;
2706
3642
}
2707
 
 
 
3643
#endif
2708
3644
 
2709
3645
void radius_event_free(void)
2710
3646
{
2714
3650
         *      are empty.
2715
3651
         */
2716
3652
 
 
3653
#ifdef WITH_PROXY
2717
3654
        /*
2718
3655
         *      There are requests in the proxy hash that aren't
2719
3656
         *      referenced from anywhere else.  Remove them first.
2725
3662
                fr_packet_list_free(proxy_list);
2726
3663
                proxy_list = NULL;
2727
3664
        }
 
3665
#endif
2728
3666
 
2729
3667
        fr_packet_list_walk(pl, NULL, request_hash_cb);
2730
3668
 
2738
3676
{
2739
3677
        if (!el) return 0;
2740
3678
 
2741
 
        just_started = TRUE;
2742
 
 
2743
3679
        return fr_event_loop(el);
2744
3680
}
2745
3681
 
2746
3682
void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
2747
3683
{
 
3684
        request->options = RAD_REQUEST_OPTION_DEBUG2;
 
3685
 
2748
3686
        if (request_pre_handler(request)) {
2749
3687
                rad_assert(fun != NULL);
2750
3688
                rad_assert(request != NULL);
2751
3689
                
2752
 
                if (request->server) DEBUG("server %s {",
2753
 
                                             request->server); 
 
3690
                if (request->server) RDEBUG("server %s {",
 
3691
                                            request->server != NULL ?
 
3692
                                            request->server : ""); 
2754
3693
                fun(request);
2755
3694
 
2756
 
                if (request->server) DEBUG("} # server %s",
2757
 
                                             request->server);
 
3695
                if (request->server) RDEBUG("} # server %s",
 
3696
                                             request->server != NULL ?
 
3697
                                            request->server : "");
2758
3698
 
2759
3699
                request_post_handler(request);
2760
3700
        }