modules/ac/access_control.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- AC_to_string_header
- AC_to_string
- AC_credit_to_string
- AC_acl_to_string_header
- AC_acl_to_string
- AC_findexless_acl_l
- AC_findcreate_acl_l
- AC_findcreate_account_l
- AC_fetch_acc
- AC_check_acl
- AC_acc_addup
- AC_commit_credit
- AC_acl_sql
- AC_ban_set
- AC_asc_ban_set
- AC_commit
- AC_decay_hook
- AC_decay
- AC_acc_load
- AC_build
- AC_rxwalkhook_print
- AC_rxwalkhook_print_acl
- AC_count_object
- AC_credit_isdenied
- AC_get_higher_limit
1 /***************************************
2 $Revision: 1.23 $
3
4 Access control module (ac) - access control for the query part
5
6 Status: NOT REVIEWED, TESTED
7
8 Design and implementation by: Marek Bukowy
9
10 ******************/ /******************
11 Copyright (c) 1999 RIPE NCC
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of the author not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 ***************************************/
30 #include <stdio.h>
31 #include <glib.h>
32
33 #define AC_OK RX_OK
34 #define AC_INVARG IP_INVARG
35
36 #define AC_IMPL
37 #include <rxroutines.h>
38 #include <erroutines.h>
39 #include <access_control.h>
40 #include "socket.h"
41 #include "mysql_driver.h"
42 #include <constants.h>
43 #include <server.h>
44
45 #define AC_DECAY_TIME 600
46
47 /* formats for printing the access control list entries */
48 #define ACL_FORMAT "%10d %10d %10d %10d %10d"
49 #define ACL_HEADER "%-20s %10s %10s %10s %10s %10s\n"
50
51 /* formats for printing the accounting entries */
52 #define ACC_FORMAT "%4d %4d %4d %4d %9d %9d %9d %9d"
53 #define ACC_HEADER "%-20s %4s %4s %4s %4s %9s %9s %9s %9s\n"
54
55
56 /*++++++++++++++++++++++++++++++++++++++
57 AC_to_string_header:
58
59 produce a header for the access stats printout
60
61 returns an allocated string
62 ++++++++++++++++++++++++++++++++++++++*/
63 char *AC_to_string_header(void)
/* [<][>][^][v][top][bottom][index][help] */
64 {
65 char *result_buf;
66
67 dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
68
69 sprintf(result_buf, ACC_HEADER,
70 "ip", "conn", "pass", "deny", "qry", "pub", "priv", "prv_bonus","pub_bonus");
71
72 return result_buf;
73 }
74
75 /*++++++++++++++++++++++++++++++++++++++
76 AC_to_string:
77
78 Show an access structure
79
80 returns an allocated string
81 ++++++++++++++++++++++++++++++++++++++*/
82 char *AC_to_string(GList *leafptr)
/* [<][>][^][v][top][bottom][index][help] */
83 {
84 char *result_buf;
85 acc_st *a = leafptr->data;
86
87 if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
88 /* XXX generic malloc handler pending ...*/
89 return NULL;
90 }
91
92 if( a == NULL ) {
93 strcpy(result_buf, "DATA MISSING!");
94 }
95 else {
96 sprintf(result_buf, ACC_FORMAT,
97 a->connections,
98 a->addrpasses,
99 a->denials,
100 a->queries,
101 a->public_objects,
102 a->private_objects,
103 a->private_bonus,
104 a->public_bonus
105 );
106 }
107
108 return result_buf;
109 } /* AC_to_string() */
110
111
112 /*++++++++++++++++++++++++++++++++++++++
113 AC_credit_to_string:
114
115 Show credit used (for logging of queries)
116
117 acc_st *a - the credit structure
118
119 returns an allocated string
120 ++++++++++++++++++++++++++++++++++++++*/
121 char *AC_credit_to_string(acc_st *a)
/* [<][>][^][v][top][bottom][index][help] */
122 {
123 char *result_buf;
124
125 if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
126 /* XXX generic malloc handler pending ...*/
127 return NULL;
128 }
129
130 dieif( a == NULL );
131
132 sprintf(result_buf,"%d+%d%s",
133 a->private_objects,
134 a->public_objects,
135 a->denials ? " **DENIED**" : ""
136 );
137
138 return result_buf;
139 } /* AC_credit_to_string */
140
141
142 /*+++++++++++++++++++++++++++++++++++++++
143 AC_acl_to_string_header:
144
145 produce a header for the acl printout
146
147 returns an allocated string
148 ++++++++++++++++++++++++++++++++++++++*/
149 char *
150 AC_acl_to_string_header(void)
/* [<][>][^][v][top][bottom][index][help] */
151 {
152 char *result_buf;
153 dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
154
155 sprintf(result_buf, ACL_HEADER, "ip",
156 "maxpriv", "maxpub","maxdenials", "ban", "trustpass" );
157
158 return result_buf;
159 }
160
161
162
163 /*++++++++++++++++++++++++++++++++++++++
164 AC_acl_to_string:
165
166 Show an access control list structure
167
168 returns an allocated string
169 ++++++++++++++++++++++++++++++++++++++*/
170 char *AC_acl_to_string(GList *leafptr)
/* [<][>][^][v][top][bottom][index][help] */
171 {
172 char *result_buf;
173 acl_st *a = leafptr->data;
174
175 if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
176 /* XXX generic malloc handler pending ...*/
177 return NULL;
178 }
179
180 if( a != NULL ) {
181 sprintf(result_buf, ACL_FORMAT,
182 a->maxprivate,
183 a->maxpublic,
184 a->maxdenials,
185 a->deny,
186 a->trustpass
187 );
188 }
189 else {
190 strcpy(result_buf, "DATA MISSING\n");
191 }
192
193 return result_buf;
194 } /* AC_acl_to_string() */
195
196
197 /*+++++++++++++++++++++++++++++++++++++++
198 AC_findexless_acl_l:
199
200 find the exact or less specific match for the given prefix in the acl tree.
201
202 ip_prefix_t *prefix - prefix to look for
203 acl_st *store_acl - pointer to store the output
204
205 returns error code from RX or OK
206
207 MT-Note: assumes locked acl tree
208 ++++++++++++++++++++++++++++++++++++++*/
209 er_ret_t
210 AC_findexless_acl_l(ip_prefix_t *prefix, acl_st *store_acl)
/* [<][>][^][v][top][bottom][index][help] */
211 {
212 GList *datlist=NULL;
213 er_ret_t ret_err;
214 rx_datref_t *datref;
215
216 if( (ret_err = RX_bin_search(RX_SRCH_EXLESS, 0, 0, act_acl,
217 prefix, &datlist, RX_ANS_ALL)
218 ) != RX_OK || g_list_length(datlist) == 0 ) {
219 /* acl tree is not configured at all ! There always must be a
220 catch-all record with defaults */
221 die;
222 }
223
224 datref = (rx_datref_t *)g_list_nth_data(datlist,0);
225
226 *store_acl = * ((acl_st *) datref->leafptr);
227
228 wr_clear_list( &datlist );
229
230 /* XXX dbg checking tree consistency */
231 {
232 rx_treecheck_t errorfound;
233 er_ret_t err;
234 if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
235 fprintf(stderr, "Nope! %d returned \n", err);
236 die;
237 }
238 }
239
240 return ret_err;
241 }
242 /* AC_findexless_acl_l */
243
244
245 /*+++++++++++++++++++++++++++++++++++++++
246 AC_findcreate_acl_l:
247
248 find or create an entry for the given prefix in the acl tree.
249
250 ip_prefix_t *prefix - prefix to look for
251 acl_st **store_acl - pointer to store the ptr to the acl struct
252 (initialised to the values of the parent entry
253 if just created)
254
255 returns error code from RX or OK
256
257 MT-Note: assumes locked acl tree
258 ++++++++++++++++++++++++++++++++++++++*/
259 er_ret_t
260 AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
/* [<][>][^][v][top][bottom][index][help] */
261 {
262 GList *datlist=NULL;
263 er_ret_t ret_err;
264 acl_st *newacl;
265 acl_st acl_copy;
266
267 if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl,
268 prefix, &datlist, RX_ANS_ALL)
269 )) {
270
271 switch( g_list_length(datlist)) {
272 case 0:
273 dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
274
275 /* make the new one inherit all parameters after the old one */
276
277 AC_findexless_acl_l(prefix, &acl_copy);
278
279 *newacl = acl_copy;
280
281 /* link in */
282 rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
283 break;
284 case 1:
285 {
286 /* Uh-oh, the guy is already known ! (or special, in any case) */
287 rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
288 newacl = (acl_st *) datref->leafptr;
289 }
290 break;
291 default:
292 die;
293 }
294 }
295
296 /* free search results */
297 wr_clear_list( &datlist );
298
299 /* store */
300 *store_acl = newacl;
301 return ret_err;
302 }
303 /* AC_findcreate_acl_l */
304
305
306 /*+++++++++++++++++++++++++++++++++++++++
307 AC_findcreate_account_l:
308
309 finds exact prefix in the accounting tree
310 or creates area initialised to zeros + sets ptr to it.
311
312 rx_tree_t *tree - the tree
313 ip_prefix_t *prefix - prefix to look for
314 acc_st **store_acl - pointer to store the ptr to the account struct
315
316 returns error code from RX or OK
317
318 MT-Note: assumes locked accounting tree
319 ++++++++++++++++++++++++++++++++++++++*/
320 er_ret_t
321 AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix,
/* [<][>][^][v][top][bottom][index][help] */
322 acc_st **acc_store)
323 {
324 GList *datlist=NULL;
325 er_ret_t ret_err;
326 acc_st *recacc;
327
328 if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree,
329 prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
330 switch( g_list_length(datlist) ) {
331 case 0:
332 /* need to create a new accounting record */
333 if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
334 /* counters = init to zeros */
335 memset( recacc, 0, sizeof(acc_st));
336
337 /* attach. The recacc is to be treated as a dataleaf
338 (must use lower levels than RX_asc_*)
339 */
340 ret_err = rx_bin_node( RX_OPER_CRE, prefix,
341 act_runtime, (rx_dataleaf_t *)recacc );
342 }
343 break;
344 case 1:
345 {
346 rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
347
348 /* OK, there is a record already */
349 recacc = (acc_st *) datref->leafptr;
350
351 }
352 break;
353 default: die; /* there shouldn't be more than 1 entry per IP */
354 }
355 }
356
357 wr_clear_list( &datlist );
358
359 *acc_store = recacc;
360
361 return ret_err;
362 }
363
364
365 /*++++++++++++++++++++++++++++++++++++++
366 AC_fetch_acc:
367
368 Finds the runtime accounting record for this IP,
369 stores a copy of it in acc_store.
370 If not found, then it is created and initialised to zeros in findcreate()
371
372 ip_addr_t *addr - address
373 acc_st *acc_store - pointer to store the account struct
374
375 MT-Note: locks/unlocks the accounting tree
376 ++++++++++++++++++++++++++++++++++++++*/
377 er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
/* [<][>][^][v][top][bottom][index][help] */
378 {
379 er_ret_t ret_err;
380 ip_prefix_t prefix;
381 acc_st *ac_ptr;
382
383 prefix.ip = *addr;
384 prefix.bits = IP_sizebits(addr->space);
385
386 TH_acquire_read_lock( &(act_runtime->rwlock) );
387
388 ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
389 *acc_store = *ac_ptr;
390
391 TH_release_read_lock( &(act_runtime->rwlock) );
392
393 return ret_err;
394 }/* AC_fetch_acc() */
395
396
397 /*++++++++++++++++++++++++++++++++++++++
398 AC_check_acl:
399
400 search for this ip or less specific record in the access control tree
401
402 if( bonus in combined runtime+connection accountings > max_bonus in acl)
403 set denial in the acl for this ip (create if needed)
404 if( combined denialcounter > max_denials in acl)
405 set the permanent ban in acl; save in SQL too
406 calculate credit if pointer provided
407 save the access record (ip if created or found/prefix otherwise)
408 at *acl_store if provided
409
410 ip_addr_t *addr - address
411 acc_st *acc_store - pointer to store the *credit* account struct
412 acl_st *acl_store - pointer to store the acl struct
413
414 any of the args except address can be NULL
415
416 returns error code from RX or OK
417
418 MT-Note: locks/unlocks the accounting tree
419 ++++++++++++++++++++++++++++++++++++++*/
420 er_ret_t AC_check_acl( ip_addr_t *addr,
/* [<][>][^][v][top][bottom][index][help] */
421 acc_st *credit_acc,
422 acl_st *acl_store
423 )
424 {
425 ip_prefix_t prefix;
426 er_ret_t ret_err = AC_OK;
427 acl_st acl_record;
428 acc_st run_acc;
429
430 AC_fetch_acc( addr, &run_acc );
431
432 prefix.ip = *addr;
433 prefix.bits = IP_sizebits(addr->space);
434
435 /* lock the tree accordingly */
436 TH_acquire_read_lock( &(act_acl->rwlock) );
437
438 /* find an applicable record */
439 AC_findexless_acl_l(&prefix, &acl_record);
440
441 /* calculate the credit if pointer given */
442 if( credit_acc ) {
443 memset( credit_acc, 0, sizeof(acc_st));
444
445 /* credit = -1 if unlimited, otherwise credit = limit - bonus */
446 credit_acc->public_objects =
447 ( acl_record.maxpublic == -1 )
448 ? -1 /* -1 == unlimited */
449 : (acl_record.maxpublic - run_acc.public_bonus);
450
451 credit_acc->private_objects =
452 ( acl_record.maxprivate == -1 )
453 ? -1 /* -1 == unlimited */
454 : (acl_record.maxprivate - run_acc.private_bonus);
455 }
456
457 /* copy the acl record if asked for it*/
458 if( acl_store ) {
459 *acl_store = acl_record;
460 }
461
462 /* release lock */
463 TH_release_read_lock( &(act_acl->rwlock) );
464
465
466 return ret_err;
467 }
468
469
470
471 /*++++++++++++++++++++++++++++++++++++++
472 AC_acc_addup:
473
474 Add/subtract the values from one accounting structure to another
475
476 acc_st *a - this one gets changed
477 acc_st *b - this one provides the values to change a
478 int minus - triggers subtraction if non-zero
479
480 +++++++++++++++++++++++++++++++++++++++*/
481 void AC_acc_addup(acc_st *a, acc_st *b, int minus)
/* [<][>][^][v][top][bottom][index][help] */
482 {
483 int mul = minus ? -1 : 1;
484
485 /* add all counters from b to those in a */
486 a->connections += mul * b->connections;
487 a->addrpasses += mul * b->addrpasses;
488
489 a->denials += mul * b->denials;
490 a->queries += mul * b->queries;
491 a->public_objects += mul * b->public_objects;
492 a->private_objects += mul * b->private_objects;
493 a->private_bonus += mul * b->private_bonus;
494 a->public_bonus += mul * b->public_bonus;
495 }/* AC_acc_addup */
496
497 /*++++++++++++++++++++++++++++++++++++++
498 AC_commit_credit:
499
500 performs the commit on an accounting tree (locks them first)
501 stores a copy of the accounting record at rec_store
502
503 rx_tree_t *tree - the tree
504 ip_prefix_t *prefix - prefix (usually a /32)
505 acc_st *acc_conn - credit used
506 acc_st *rec_store - pointer to store the account struct
507
508 returns error code from AC_findcreate_account_l or OK
509
510 MT-Note: locks/unlocks the accounting tree
511 +++++++++++++++++++++++++++++++++++++++*/
512 er_ret_t
513 AC_commit_credit(rx_tree_t *tree, ip_prefix_t *prefix,
/* [<][>][^][v][top][bottom][index][help] */
514 acc_st *acc_conn, acc_st *rec_store )
515 {
516 acc_st *accountrec;
517 er_ret_t ret_err;
518
519
520 acc_conn->private_bonus = acc_conn->private_objects;
521 acc_conn->public_bonus = acc_conn->public_objects;
522
523 TH_acquire_write_lock( &(tree->rwlock) );
524
525 ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
526
527 if( NOERR(ret_err)) {
528 AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
529 }
530
531 TH_release_write_lock( &(tree->rwlock) );
532
533 *rec_store = *accountrec;
534
535 return ret_err;
536 }/* AC_commit_credit */
537
538
539
540 /*++++++++++++++++++++++++++++++++++++++
541 AC_acl_sql:
542
543 updates/creates a record for the given prefix in the acl table of
544 the RIPADMIN database. Adds a comment.
545
546 ip_prefix_t *prefix - prefix
547 acl_st *newacl - new values to store in the database
548 char *newcomment - comment to be added (must not be NULL)
549
550 placeholder: it may return an error code from SQ - as soon as sq
551 implements common error scheme
552
553 ++++++++++++++++++++++++++++++++++++++*/
554 er_ret_t
555 AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
/* [<][>][^][v][top][bottom][index][help] */
556 {
557 SQ_connection_t *sql_connection = NULL;
558 SQ_result_set_t *result;
559 SQ_row_t *row;
560 char *oldcomment;
561 char *query;
562 char querybuf[256];
563
564 sql_connection = SQ_get_connection(CO_get_host(),
565 CO_get_database_port(),
566 "RIPADMIN",
567 CO_get_user(),
568 CO_get_password() );
569
570 /* get the old entry, extend it */
571 sprintf(querybuf, "SELECT comment FROM acl WHERE "
572 "prefix = %u AND prefix_length = %d",
573 prefix->ip.words[0],
574 prefix->bits);
575 dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
576
577 if( SQ_num_rows(result) == 1 ) {
578 dieif( (row = SQ_row_next(result)) == NULL);
579 oldcomment = SQ_get_column_string(result, row, 0);
580 }
581 else {
582 oldcomment = "";
583 }
584
585 SQ_free_result(result);
586
587 /* must hold the thing below (REPLACE..blah blah blah) + text */
588 dieif( wr_malloc((void **)&query,
589 strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
590
591 /* compose new entry and insert it */
592 sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
593 "\"%s%s%s\")",
594 prefix->ip.words[0],
595 prefix->bits,
596 newacl->maxprivate,
597 newacl->maxpublic,
598 newacl->maxdenials,
599 newacl->deny,
600 newacl->trustpass,
601 oldcomment,
602 strlen(oldcomment) > 0 ? "\n" : "",
603 newcomment
604 );
605
606 SQ_execute_query(sql_connection, query, NULL);
607 SQ_close_connection(sql_connection);
608
609 wr_free(query);
610
611 return AC_OK;
612
613 }/* AC_acl_sql */
614
615 /*++++++++++++++++++++++++++++++++++++++
616 AC_ban_set:
617
618 re/sets the permanent ban flag both in the acl tree in memory
619 and the sql table. The "text" is appended to the comment
620 in the sql record (the expected cases are
621 - "automatic" in case the limit is exceeded and ban is set by s/w
622 - "manual" in case it is (un)set from the config iface
623
624 ip_prefix_t *prefix - prefix
625 char *text - usually "automatic" or "manual"
626 int denyflag - new value of the denyflag (ban)
627
628 returns error code from AC_acl_sql or OK
629 +++++++++++++++++++++++++++++++++++++++*/
630 er_ret_t
631 AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
/* [<][>][^][v][top][bottom][index][help] */
632 {
633 acl_st *treeacl;
634 char newcomment[256];
635 er_ret_t ret_err;
636 time_t clock;
637 char timebuf[26];
638
639 time(&clock);
640 ctime_r(&clock, timebuf);
641
642 sprintf(newcomment,"%s permanent ban set to %d at %s", text,
643 denyflag, timebuf);
644
645 TH_acquire_write_lock( &(act_acl->rwlock) );
646
647 /* find a record in the tree */
648 if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
649 treeacl->deny = denyflag;
650 ret_err = AC_acl_sql( prefix, treeacl, newcomment );
651 }
652 TH_release_write_lock( &(act_acl->rwlock) );
653
654 return ret_err;
655 }/* AC_ban_set */
656
657
658 /*++++++++++++++++++++++++++++++++++++++
659 AC_asc_ban_set:
660
661 sets ban on text address/range. Parses the text address/range/prefix
662 and then calls AC_ban_set on that prefix.
663
664 Precondition: if the key is a range, it must decompose into one prefix
665
666 returns error code from IP_smart_conv, AC_ban_set or
667 AC_INVARG if range composed
668 +++++++++++++++++++++++++++++++++++++++*/
669 er_ret_t
670 AC_asc_ban_set(char *addrstr, char *text, int denyflag)
/* [<][>][^][v][top][bottom][index][help] */
671 {
672 er_ret_t ret_err;
673 GList *preflist = NULL;
674 ip_keytype_t key_type;
675
676 if( (ret_err = IP_smart_conv(addrstr, 0, 0,
677 &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
678 return ret_err;
679 }
680
681 /* allow only one prefix */
682 /* The argument can be even a range, but must decompose into one prefix */
683 if( NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
684 ret_err = AC_INVARG;
685 }
686
687 if( NOERR(ret_err) ) {
688 ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
689 }
690
691 wr_clear_list( &preflist );
692
693 return ret_err;
694 }/* AC_asc_ban_set */
695
696
697 /*++++++++++++++++++++++++++++++++++++++
698 AC_commit:
699
700 commits the credit into all accounting trees, (XXX: only one at the moment)
701 checks the limits and sets automatic ban if limit exceeded.
702
703 ip_addr_t *addr - user's address
704 acc_st *acc_conn - credit used
705 acl_st *acl_copy - pointer to store a copy of the acl
706
707 returns error code from AC_commit_credit or AC_ban_set or OK.
708
709 outline:
710 lock runtime + minute accounting trees
711 ----------------------- XXX runtime only for the moment
712 find or create entries,
713 increase accounting values by the values from passed acc
714 check values against acl, see if permanent ban applies
715
716 reset the connection acc
717 unlock accounting trees
718
719 if permanent ban - set it! :
720 lock acl
721 find/create IP in memory
722 set ban
723 find/create IP in SQL
724 copy old values (if any), set ban, append comment
725 unlock acl
726
727 +++++++++++++++++++++++++++++++++++++++*/
728 er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
/* [<][>][^][v][top][bottom][index][help] */
729 acc_st account;
730 er_ret_t ret_err;
731 ip_prefix_t prefix;
732
733 prefix.ip = *addr;
734 prefix.bits = IP_sizebits(addr->space);
735
736 ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
737 /* XXX add more trees here */
738
739 memset(acc_conn,0, sizeof(acc_st));
740
741 /* set permanent ban if deserved and if not set yet */
742 if( account.denials > acl_copy->maxdenials
743 && acl_copy->deny == 0
744 && NOERR(ret_err) ) {
745
746 ret_err = AC_ban_set(&prefix, "Automatic", 1);
747 }
748
749 return ret_err;
750 } /* AC_commit */
751
752
753 /*++++++++++++++++++++++++++++++++++++++
754 AC_decay_hook:
755
756 action performed on a single account node during decay (diminishing the
757 bonus). Conforms to rx_walk_tree interface, therefore some of the
758 arguments do not apply and are not used.
759
760 rx_node_t *node - pointer to the node of the radix tree
761 int level - n/a
762 int nodecounter - n/a
763 void *con - n/a
764
765 returns always OK
766 +++++++++++++++++++++++++++++++++++++++*/
767 er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con)
/* [<][>][^][v][top][bottom][index][help] */
768 {
769 acc_st *a = node->leaves_ptr->data;
770
771 a->private_bonus *= 0.95;
772 a->public_bonus *= 0.95;
773
774 return RX_OK;
775 } /* AC_decay_hook() */
776
777
778
779 /*++++++++++++++++++++++++++++++++++++++
780 AC_decay:
781
782 Every AC_DECAY_TIME goes through the accounting tree(s) and decays the
783 bonus values.
784
785 returns always OK
786
787 MT-Note This should be run as a detached thread.
788 +++++++++++++++++++++++++++++++++++++++*/
789 er_ret_t AC_decay(void) {
/* [<][>][^][v][top][bottom][index][help] */
790 er_ret_t ret_err = AC_OK;
791
792
793 while(CO_get_do_server()) {
794
795 TH_acquire_write_lock( &(act_runtime->rwlock) );
796
797 if( act_runtime->top_ptr != NULL ) {
798 rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
799 RX_WALK_SKPGLU, /* skip glue nodes */
800 255, 0, 0, NULL, &ret_err);
801 }
802
803 /* it should also be as smart as to delete nodes that have reached
804 zero, otherwise the whole of memory will be filled.
805 Next release :-)
806 */
807
808 TH_release_write_lock( &(act_runtime->rwlock) );
809
810 printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
811
812 SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
813 }
814
815 return ret_err;
816 } /* AC_decay() */
817
818
819 /*++++++++++++++++++++++++++++++++++++++
820 AC_acc_load:
821
822 loads the acl access tree from the acl table of the RIPADMIN database.
823 (takes port/host/user/password from the config module).
824
825 bails out if encounters problems with the database (logs to stderr).
826
827 returns error code from RX_bin_node or wr_malloc.
828 ++++++++++++++++++++++++++++++++++++++*/
829 er_ret_t AC_acc_load(void)
/* [<][>][^][v][top][bottom][index][help] */
830 {
831 SQ_connection_t *con=NULL;
832 SQ_result_set_t *result;
833 SQ_row_t *row;
834 er_ret_t ret_err = RX_OK;
835
836 if( (con = SQ_get_connection(CO_get_host(), CO_get_database_port(),
837 "RIPADMIN", CO_get_user(), CO_get_password() )
838 ) == NULL ) {
839 fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
840 die;
841 }
842
843 if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
844 fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
845 die;
846 }
847
848 TH_acquire_write_lock( &(act_acl->rwlock) );
849
850 while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
851 ip_prefix_t mypref;
852 acl_st *newacl;
853 #define NUMELEM (7)
854 char *col[NUMELEM];
855 unsigned myint;
856 int i;
857
858 memset(&mypref, 0, sizeof(ip_prefix_t));
859 mypref.ip.space = IP_V4;
860
861 if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
862 ) == UT_OK ) {
863
864 for(i=0; i<NUMELEM; i++) {
865 if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
866 die;
867 }
868 }
869
870 /* prefix ip */
871 if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
872
873 /* prefix length */
874 if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
875
876 /* acl contents */
877 if( sscanf(col[2], "%u", & (newacl->maxprivate) ) < 1 ) { die; }
878 if( sscanf(col[3], "%u", & (newacl->maxpublic) ) < 1 ) { die; }
879 if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
880
881 /* these are chars therefore cannot read directly */
882 if( sscanf(col[5], "%u", &myint ) < 1 ) { die; }
883 else {
884 newacl->deny = myint;
885 }
886 if( sscanf(col[6], "%u", &myint ) < 1 ) { die; }
887 else {
888 newacl->trustpass = myint;
889 }
890
891 /* free space */
892 for(i=0; i<NUMELEM; i++) {
893 wr_free(col[i]);
894 }
895
896 /* now add to the tree */
897 ret_err = rx_bin_node( RX_OPER_CRE, &mypref,
898 act_acl, (rx_dataleaf_t *) newacl );
899 }
900 } /* while row */
901
902 TH_release_write_lock( &(act_acl->rwlock) );
903
904 SQ_free_result(result);
905 /* Close connection */
906 SQ_close_connection(con);
907
908 return ret_err;
909 } /* AC_acc_load */
910
911
912
913 /*++++++++++++++++++++++++++++++++++++++
914 AC_build:
915
916 creates empty trees for accounting/acl.
917
918 returns error code from RX_tree_cre or OK.
919 (XXX): just now only bails out when encounters problems.
920 ++++++++++++++++++++++++++++++++++++++*/
921 er_ret_t AC_build(void)
/* [<][>][^][v][top][bottom][index][help] */
922 {
923 /* create trees */
924 if ( RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
925 RX_SUB_NONE, &act_runtime) != RX_OK
926 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
927 RX_SUB_NONE, &act_hour) != RX_OK
928 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
929 RX_SUB_NONE, &act_minute) != RX_OK
930 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
931 RX_SUB_NONE, &act_acl) != RX_OK
932 )
933 die; /*can be changed to an error and handled ... some day */
934
935 return RX_OK;
936 }
937
938 /*++++++++++++++++++++++++++++++++++++++
939 AC_rxwalkhook_print:
940
941 action performed on a single account node
942 when listing the contents of the access tree: format and print the
943 data from this node.
944
945 Conforms to rx_walk_tree interface, therefore some of the
946 arguments do not apply and are not used.
947
948 rx_node_t *node - pointer to the node of the radix tree
949 int level - n/a
950 int nodecounter - n/a
951 void *con - pointer to the connection structure (prints to it)
952
953 returns always OK
954 +++++++++++++++++++++++++++++++++++++++*/
955 er_ret_t AC_rxwalkhook_print(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
956 int level, int nodecounter,
957 void *con)
958 {
959 char adstr[IP_ADDRSTR_MAX];
960 char line[1024];
961 char *dat;
962
963
964 if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
965 die; /* program error. */
966 }
967
968 sprintf(line, "%-20s %s\n", adstr,
969 dat=AC_to_string( node->leaves_ptr ));
970 wr_free(dat);
971
972 SK_cd_puts((sk_conn_st *)con, line);
973 return RX_OK;
974 } /* AC_rxwalkhook_print */
975
976
977 /*++++++++++++++++++++++++++++++++++++++
978 AC_rxwalkhook_print_acl:
979
980 action performed on a single account node
981 when listing the contents of the acl tree: format and print the
982 data from this node.
983
984 Conforms to rx_walk_tree interface, therefore some of the
985 arguments do not apply and are not used.
986
987 rx_node_t *node - pointer to the node of the radix tree
988 int level - n/a
989 int nodecounter - n/a
990 void *con - pointer to the connection structure (prints to it)
991
992 returns always OK
993 +++++++++++++++++++++++++++++++++++++++*/
994 er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
995 int level, int nodecounter,
996 void *con)
997 {
998 char prefstr[IP_PREFSTR_MAX];
999 char line[1024];
1000 char *dat;
1001
1002
1003 if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
1004 die; /* program error. */
1005 }
1006
1007 sprintf(line, "%-20s %s\n", prefstr,
1008 dat=AC_acl_to_string( node->leaves_ptr ));
1009 wr_free(dat);
1010
1011 SK_cd_puts((sk_conn_st *)con, line);
1012 return RX_OK;
1013 }/* AC_rxwalkhook_print_acl */
1014
1015 /*++++++++++++++++++++++++++++++++++++++
1016 AC_count_object:
1017
1018 accounts an objects in the credit accordingly to its type,
1019 or sets denial if the limit is defined and the credit is exceeded.
1020
1021 type - object type
1022 credit - pointer to the credit structure (gets modified)
1023
1024 */
1025 void
1026 AC_count_object( acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1027 acl_st *acl,
1028 int private )
1029 {
1030 if( private ) {
1031 if( acc_credit->private_objects <= 0 && acl->maxprivate != -1 ) {
1032 /* must be negative - will be subtracted */
1033 acc_credit->denials = -1;
1034 } else {
1035 acc_credit->private_objects --;
1036 }
1037 }
1038 else {
1039 if( acc_credit->public_objects <= 0 && acl->maxpublic != -1 ) {
1040 acc_credit->denials = -1;
1041 } else {
1042 acc_credit->public_objects --;
1043 }
1044 }
1045 } /* AC_count_object */
1046
1047
1048 /*++++++++++++++++++++++++++++++++++++++
1049 AC_credit_isdenied:
1050 checks the denied flag in credit (-1 or 1 => denied)
1051
1052 credit - pointer to the credit structure
1053 +*/
1054 int
1055 AC_credit_isdenied(acc_st *acc_credit)
/* [<][>][^][v][top][bottom][index][help] */
1056 {
1057 return (acc_credit->denials != 0);
1058 } /* AC_credit_isdenied */
1059
1060
1061 /*++++++++++++++++++++++++++++++++++++++
1062 AC_get_higher_limit:
1063
1064 returns the higher number of the two acl limits: maxprivate & maxpublic
1065 corrected w.r.t the current credit left,
1066 or unlimited if any of them is 'unlimited'.
1067 +*/
1068 int
1069 AC_get_higher_limit(acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1070 acl_st *acl)
1071 {
1072 if( acl->maxprivate == -1 && acl->maxpublic == -1 ) {
1073 return -1;
1074 }
1075 else {
1076 int a = acc_credit->private_objects;
1077 int b = acc_credit->public_objects;
1078
1079 return (a > b ? a : b);
1080 }
1081 }