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_find_acl_l
- AC_findcreate_acl_l
- AC_findcreate_account_l
- AC_fetch_acc
- AC_check_acl
- AC_acc_addup
- AC_commit_credit_l
- AC_dbopen_admin
- AC_acl_sql
- AC_ban_set
- AC_asc_ban_set
- AC_asc_all_set
- AC_asc_acl_command_set
- AC_asc_set_nodeny
- AC_commit
- AC_prune
- AC_decay_hook
- AC_decay
- AC_acc_load
- AC_build
- ac_rxwalkhook_print
- AC_print_access
- ac_rxwalkhook_print_acl
- AC_print_acl
- AC_count_object
- AC_credit_isdenied
- AC_get_higher_limit
1 /***************************************
2 $Revision: 1.40 $
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
31 /*
32 test excercises:
33
34 1. add a function to delete an entry from the acl table,
35 it should be called from the pc module.
36
37 */
38
39 #include <stdio.h>
40 #include <glib.h>
41 #include <string.h>
42
43 #define AC_IMPL
44 #include "rxroutines.h"
45 #include "erroutines.h"
46 #include "access_control.h"
47 #include "sk.h"
48 #include "ta.h"
49 #include "mysql_driver.h"
50 #include "constants.h"
51 #include "server.h"
52
53 #include "ca_configFns.h"
54 #include "ca_dictionary.h"
55 #include "ca_macros.h"
56 #include "ca_srcAttribs.h"
57 #include "timediff.h"
58
59 #include "math.h" /* exp() */
60
61 /* formats for printing the access control list entries */
62 #define ACL_FORMAT "%10d %10d %10d %10d %10d"
63 #define ACL_HEADER "%-20s %10s %10s %10s %10s %10s\n"
64
65 /* formats for printing the accounting entries */
66 #define ACC_FORMAT "%4d %4d %4d %4d %7d %7d %7d %7.1f %7.1f"
67 #define ACC_HEADER "%-20s %4s %4s %4s %4s %7s %7s %7s %7s %7s\n"
68
69
70 typedef struct {
71 double decay_factor;
72 unsigned newtotal;
73 GList *prunelist;
74 } ac_decay_data_t;
75
76 /*++++++++++++++++++++++++++++++++++++++
77 ac_to_string_header:
78
79 produce a header for the access stats printout
80
81 returns an allocated string
82 ++++++++++++++++++++++++++++++++++++++*/
83 static
84 char *ac_to_string_header(void)
/* [<][>][^][v][top][bottom][index][help] */
85 {
86 char *result_buf;
87
88 dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
89
90 sprintf(result_buf, ACC_HEADER,
91 "ip", "conn", "pass", "deny", "qry", "refs", "priv_o", "pub_o", "priv_b","pub_b");
92
93 return result_buf;
94 }
95
96 /*++++++++++++++++++++++++++++++++++++++
97 ac_to_string:
98
99 Show an access structure
100
101 returns an allocated string
102 ++++++++++++++++++++++++++++++++++++++*/
103 static
104 char *ac_to_string(GList *leafptr)
/* [<][>][^][v][top][bottom][index][help] */
105 {
106 char *result_buf;
107 acc_st *a = leafptr->data;
108
109 if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
110 /* XXX generic malloc handler pending ...*/
111 return NULL;
112 }
113
114 if( a == NULL ) {
115 strcpy(result_buf, "DATA MISSING!");
116 }
117 else {
118 sprintf(result_buf, ACC_FORMAT,
119 a->connections,
120 a->addrpasses,
121 a->denials,
122 a->queries,
123 a->referrals,
124 a->private_objects,
125 a->public_objects,
126 a->private_bonus,
127 a->public_bonus
128 );
129 }
130
131 return result_buf;
132 } /* ac_to_string() */
133
134
135 /*++++++++++++++++++++++++++++++++++++++
136 AC_credit_to_string:
137
138 Show credit used (for logging of queries)
139
140 acc_st *a - the credit structure
141
142 returns an allocated string
143 ++++++++++++++++++++++++++++++++++++++*/
144 char *AC_credit_to_string(acc_st *a)
/* [<][>][^][v][top][bottom][index][help] */
145 {
146 char *result_buf;
147
148 if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
149 /* XXX generic malloc handler pending ...*/
150 return NULL;
151 }
152
153 dieif( a == NULL );
154
155 sprintf(result_buf,"%d+%d+%d%s",
156 a->private_objects,
157 a->public_objects,
158 a->referrals,
159 a->denials ? " **DENIED**" : ""
160 );
161
162 return result_buf;
163 } /* AC_credit_to_string */
164
165
166 /*+++++++++++++++++++++++++++++++++++++++
167 ac_acl_to_string_header:
168
169 produce a header for the acl printout
170
171 returns an allocated string
172 ++++++++++++++++++++++++++++++++++++++*/
173 static char *
174 ac_acl_to_string_header(void)
/* [<][>][^][v][top][bottom][index][help] */
175 {
176 char *result_buf;
177 dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
178
179 sprintf(result_buf, ACL_HEADER, "ip",
180 /* the names must match those in AC_ar_acl, so just take
181 them from there */
182 AC_ar_acl[AC_AR_MAXPRIVATE],
183 AC_ar_acl[AC_AR_MAXPUBLIC],
184 AC_ar_acl[AC_AR_MAXDENIALS],
185 AC_ar_acl[AC_AR_DENY],
186 AC_ar_acl[AC_AR_TRUSTPASS]
187 );
188
189
190 return result_buf;
191 }
192
193
194
195 /*++++++++++++++++++++++++++++++++++++++
196 ac_acl_to_string:
197
198 Show an access control list structure
199
200 returns an allocated string
201 ++++++++++++++++++++++++++++++++++++++*/
202 static
203 char *ac_acl_to_string(GList *leafptr)
/* [<][>][^][v][top][bottom][index][help] */
204 {
205 char *result_buf;
206 acl_st *a = leafptr->data;
207
208 if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
209 /* XXX generic malloc handler pending ...*/
210 return NULL;
211 }
212
213 if( a != NULL ) {
214 sprintf(result_buf, ACL_FORMAT,
215 a->maxprivate,
216 a->maxpublic,
217 a->maxdenials,
218 a->deny,
219 a->trustpass
220 );
221 }
222 else {
223 strcpy(result_buf, "DATA MISSING\n");
224 }
225
226 return result_buf;
227 } /* ac_acl_to_string() */
228
229
230 /*+++++++++++++++++++++++++++++++++++++++
231 ac_find_acl_l:
232
233 find the exact or exact/less specific match for the given prefix in the acl tree.
234
235 ip_prefix_t *prefix - prefix to look for
236
237 acl_st *store_acl - pointer to store the output
238
239 returns error code from RX or OK
240
241 MT-Note: assumes locked acl tree
242 ++++++++++++++++++++++++++++++++++++++*/
243 static er_ret_t
244 ac_find_acl_l(rx_srch_mt searchmode, ip_prefix_t *prefix, acl_st *store_acl)
/* [<][>][^][v][top][bottom][index][help] */
245 {
246 GList *datlist=NULL;
247 er_ret_t ret_err;
248 rx_datref_t *datref;
249
250 /* accept only RX_SRCH_EXLESS | RX_SRCH_EXACT modes */
251 dieif( searchmode != RX_SRCH_EXLESS && searchmode != RX_SRCH_EXACT);
252
253 /* it must work */
254 dieif( (ret_err = RX_bin_search(searchmode, 0, 0, act_acl,
255 prefix, &datlist, RX_ANS_ALL)
256 ) != RX_OK );
257 /* In exless mode, something must be found or the acl tree is not
258 configured at all !
259 There always must be a catch-all record with defaults */
260 dieif( searchmode == RX_SRCH_EXLESS && g_list_length(datlist) == 0 );
261
262
263 datref = (rx_datref_t *)g_list_nth_data(datlist,0);
264
265 *store_acl = * ((acl_st *) datref->leafptr);
266
267 wr_clear_list( &datlist );
268
269 #if 0
270 /* XXX dbg checking tree consistency */
271 {
272 rx_treecheck_t errorfound;
273 er_ret_t err;
274 if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
275 fprintf(stderr, "Nope! %d returned \n", err);
276 die;
277 }
278 }
279 #endif
280
281 return ret_err;
282 }
283 /* ac_find_acl_l */
284
285
286 /*+++++++++++++++++++++++++++++++++++++++
287 AC_findcreate_acl_l:
288
289 find or create an entry for the given prefix in the acl tree.
290
291 ip_prefix_t *prefix - prefix to look for
292
293 acl_st **store_acl - pointer to store the ptr to the acl struct
294 (initialised to the values of the parent entry
295 if just created)
296
297 returns error code from RX or OK
298
299 MT-Note: assumes locked acl tree
300 ++++++++++++++++++++++++++++++++++++++*/
301 er_ret_t
302 AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
/* [<][>][^][v][top][bottom][index][help] */
303 {
304 GList *datlist=NULL;
305 er_ret_t ret_err;
306 acl_st *newacl;
307 acl_st acl_copy;
308
309 if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl,
310 prefix, &datlist, RX_ANS_ALL)
311 )) {
312
313 switch( g_list_length(datlist)) {
314 case 0:
315 dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
316
317 /* make the new one inherit all parameters after the old one */
318
319 ac_find_acl_l(RX_SRCH_EXLESS, prefix, &acl_copy);
320
321 *newacl = acl_copy;
322
323 /* link in */
324 rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
325 break;
326 case 1:
327 {
328 /* Uh-oh, the guy is already known ! (or special, in any case) */
329 rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
330 newacl = (acl_st *) datref->leafptr;
331 }
332 break;
333 default:
334 die;
335 }
336 }
337
338 /* free search results */
339 wr_clear_list( &datlist );
340
341 /* store */
342 *store_acl = newacl;
343 return ret_err;
344 }
345 /* AC_findcreate_acl_l */
346
347
348 /*+++++++++++++++++++++++++++++++++++++++
349 AC_findcreate_account_l:
350
351 finds exact prefix in the accounting tree
352 or creates area initialised to zeros + sets ptr to it.
353
354 rx_tree_t *tree - the tree
355
356 ip_prefix_t *prefix - prefix to look for
357
358 acc_st **store_acl - pointer to store the ptr to the account struct
359
360 returns error code from RX or OK
361
362 MT-Note: assumes locked accounting tree
363 ++++++++++++++++++++++++++++++++++++++*/
364 er_ret_t
365 AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix,
/* [<][>][^][v][top][bottom][index][help] */
366 acc_st **acc_store)
367 {
368 GList *datlist=NULL;
369 er_ret_t ret_err;
370 acc_st *recacc;
371
372 if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree,
373 prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
374 switch( g_list_length(datlist) ) {
375 case 0:
376 /* need to create a new accounting record */
377 if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
378 /* counters = init to zeros */
379 memset( recacc, 0, sizeof(acc_st));
380
381 /* attach. The recacc is to be treated as a dataleaf
382 (must use lower levels than RX_asc_*)
383 */
384 ret_err = rx_bin_node( RX_OPER_CRE, prefix,
385 act_runtime, (rx_dataleaf_t *)recacc );
386 }
387 break;
388 case 1:
389 {
390 rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
391
392 /* OK, there is a record already */
393 recacc = (acc_st *) datref->leafptr;
394
395 }
396 break;
397 default: die; /* there shouldn't be more than 1 entry per IP */
398 }
399 }
400
401 wr_clear_list( &datlist );
402
403 *acc_store = recacc;
404
405 #if 0
406 /* XXX dbg checking tree consistency */
407 if( act_runtime->top_ptr != NULL ) {
408 rx_treecheck_t errorfound;
409 er_ret_t err;
410 if( (err=RX_treecheck(act_runtime, 1, &errorfound)) != RX_OK ) {
411 fprintf(stderr, "Nope! %d returned \n", errorfound);
412 ER_dbg_va( FAC_AC, ASP_AC_DECAY,
413 "AC: checking access tree consistency: error %d",
414 errorfound);
415 die; /* access tree not consistent */
416 }
417 }
418 #endif
419
420 return ret_err;
421 }
422
423
424 /*++++++++++++++++++++++++++++++++++++++
425 AC_fetch_acc:
426
427 Finds the runtime accounting record for this IP,
428 stores a copy of it in acc_store.
429 If not found, then it is created and initialised to zeros in findcreate()
430
431 ip_addr_t *addr - address
432
433 acc_st *acc_store - pointer to store the account struct
434
435 MT-Note: locks/unlocks the accounting tree
436 ++++++++++++++++++++++++++++++++++++++*/
437 er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
/* [<][>][^][v][top][bottom][index][help] */
438 {
439 er_ret_t ret_err;
440 ip_prefix_t prefix;
441 acc_st *ac_ptr;
442
443 prefix.ip = *addr;
444 prefix.bits = IP_sizebits(addr->space);
445
446 TH_acquire_write_lock( &(act_runtime->rwlock) );
447
448 ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
449 *acc_store = *ac_ptr;
450
451 TH_release_write_lock( &(act_runtime->rwlock) );
452
453 return ret_err;
454 }/* AC_fetch_acc() */
455
456
457 /*++++++++++++++++++++++++++++++++++++++
458 AC_check_acl:
459
460 search for this ip or less specific record in the access control tree
461
462 if( bonus in combined runtime+connection accountings > max_bonus in acl)
463 set denial in the acl for this ip (create if needed)
464 if( combined denialcounter > max_denials in acl)
465 set the permanent ban in acl; save in SQL too
466 calculate credit if pointer provided
467 save the access record (ip if created or found/prefix otherwise)
468 at *acl_store if provided
469
470 ip_addr_t *addr - address
471
472 acc_st *acc_store - pointer to store the *credit* account struct
473
474 acl_st *acl_store - pointer to store the acl struct
475
476 any of the args except address can be NULL
477
478 returns error code from RX or OK
479
480 MT-Note: locks/unlocks the accounting tree
481 ++++++++++++++++++++++++++++++++++++++*/
482 er_ret_t AC_check_acl( ip_addr_t *addr,
/* [<][>][^][v][top][bottom][index][help] */
483 acc_st *credit_acc,
484 acl_st *acl_store
485 )
486 {
487 ip_prefix_t prefix;
488 er_ret_t ret_err = AC_OK;
489 acl_st acl_record;
490 acc_st run_acc;
491
492 AC_fetch_acc( addr, &run_acc );
493
494 prefix.ip = *addr;
495 prefix.bits = IP_sizebits(addr->space);
496
497 /* lock the tree accordingly */
498 TH_acquire_read_lock( &(act_acl->rwlock) );
499
500 /* find an applicable record */
501 ac_find_acl_l(RX_SRCH_EXLESS, &prefix, &acl_record);
502
503 /* calculate the credit if pointer given */
504 if( credit_acc ) {
505 memset( credit_acc, 0, sizeof(acc_st));
506
507 /* credit = -1 if unlimited, otherwise credit = limit - bonus */
508 credit_acc->public_objects =
509 ( acl_record.maxpublic == -1 )
510 ? -1 /* -1 == unlimited */
511 : (acl_record.maxpublic - run_acc.public_bonus);
512
513 credit_acc->private_objects =
514 ( acl_record.maxprivate == -1 )
515 ? -1 /* -1 == unlimited */
516 : (acl_record.maxprivate - run_acc.private_bonus);
517 }
518
519 /* copy the acl record if asked for it*/
520 if( acl_store ) {
521 *acl_store = acl_record;
522 }
523
524 /* release lock */
525 TH_release_read_lock( &(act_acl->rwlock) );
526
527
528 return ret_err;
529 }
530
531
532
533 /*++++++++++++++++++++++++++++++++++++++
534 AC_acc_addup:
535
536 Add/subtract the values from one accounting structure to another
537
538 acc_st *a this one gets changed
539
540 acc_st *b this one provides the values to change a
541
542 int minus triggers subtraction if non-zero
543
544 +++++++++++++++++++++++++++++++++++++++*/
545 void AC_acc_addup(acc_st *a, acc_st *b, int minus)
/* [<][>][^][v][top][bottom][index][help] */
546 {
547 int mul = minus ? -1 : 1;
548
549 /* add all counters from b to those in a */
550 a->connections += mul * b->connections;
551 a->addrpasses += mul * b->addrpasses;
552
553 a->denials += mul * b->denials;
554 a->queries += mul * b->queries;
555 a->referrals += mul * b->referrals;
556 a->public_objects += mul * b->public_objects;
557 a->private_objects += mul * b->private_objects;
558 a->private_bonus += mul * b->private_bonus;
559 a->public_bonus += mul * b->public_bonus;
560 }/* AC_acc_addup */
561
562 /*++++++++++++++++++++++++++++++++++++++
563 AC_commit_credit_l:
564
565 performs the commit on an accounting tree (locks them first)
566 stores a copy of the accounting record at rec_store
567
568 Assumes locked tree.
569
570 rx_tree_t *tree - the tree
571
572 ip_prefix_t *prefix - prefix (usually a /32)
573
574 acc_st *acc_conn - credit used
575
576 acc_st *rec_store - pointer to store the account struct or NULL
577
578 returns error code from AC_findcreate_account_l or OK
579
580 MT-Note: locks/unlocks the accounting tree
581 +++++++++++++++++++++++++++++++++++++++*/
582 static
583 er_ret_t
584 AC_commit_credit_l(rx_tree_t *tree, ip_prefix_t *prefix,
/* [<][>][^][v][top][bottom][index][help] */
585 acc_st *acc_conn, acc_st *rec_store )
586 {
587 acc_st *accountrec;
588 er_ret_t ret_err;
589
590
591 acc_conn->private_bonus = acc_conn->private_objects;
592 acc_conn->public_bonus = acc_conn->public_objects;
593
594
595 ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
596
597 if( NOERR(ret_err)) {
598 AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
599 }
600
601 if( rec_store ) {
602 *rec_store = *accountrec;
603 }
604
605 return ret_err;
606 }/* AC_commit_credit */
607
608 /*++++++++++++++++++++++++++++++++++++++
609 AC_dbopen_admin:
610
611 opens the ADMIN database and returns a pointer to the connection structure
612 (rationale: the opening process became a bit bloated and is done twice,
613 so I put it into a separate function)
614 ++++++++++++++++++++++++++++++++++++++*/
615 SQ_connection_t *
616 AC_dbopen_admin(void)
/* [<][>][^][v][top][bottom][index][help] */
617 {
618 SQ_connection_t *con=NULL;
619 char *dbhost = ca_get_ripadminhost;
620 char *dbname = ca_get_ripadmintable;
621 char *dbuser = ca_get_ripadminuser;
622 char *dbpass = ca_get_ripadminpassword;
623 unsigned dbport = ca_get_ripadminport;
624
625 if( (con = SQ_get_connection(dbhost, dbport, dbname, dbuser, dbpass)
626 ) == NULL ) {
627 fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
628 die;
629 }
630
631 free(dbhost);
632 free(dbname);
633 free(dbuser);
634 free(dbpass);
635
636 return con;
637 }
638
639 /*++++++++++++++++++++++++++++++++++++++
640 AC_acl_sql:
641
642 updates/creates a record for the given prefix in the acl table of
643 the RIPADMIN database. Adds a comment.
644
645 ip_prefix_t *prefix - prefix
646
647 acl_st *newacl - new values to store in the database
648
649 char *newcomment - comment to be added (must not be NULL)
650
651 placeholder: it may return an error code from SQ - as soon as sq
652 implements common error scheme
653
654 ++++++++++++++++++++++++++++++++++++++*/
655 er_ret_t
656 AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
/* [<][>][^][v][top][bottom][index][help] */
657 {
658 SQ_connection_t *sql_connection = NULL;
659 SQ_result_set_t *result;
660 SQ_row_t *row;
661 char *oldcomment;
662 char *query;
663 char querybuf[256];
664
665 sql_connection = AC_dbopen_admin();
666
667 /* get the old entry, extend it */
668 sprintf(querybuf, "SELECT comment FROM acl WHERE "
669 "prefix = %u AND prefix_length = %d",
670 prefix->ip.words[0],
671 prefix->bits);
672 dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
673
674 if( SQ_num_rows(result) == 1 ) {
675 dieif( (row = SQ_row_next(result)) == NULL);
676 oldcomment = SQ_get_column_string(result, row, 0);
677 }
678 else {
679 oldcomment = "";
680 }
681
682 SQ_free_result(result);
683
684 /* must hold the thing below (REPLACE..blah blah blah) + text */
685 dieif( wr_malloc((void **)&query,
686 strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
687
688 /* compose new entry and insert it */
689 sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
690 "\"%s%s%s\")",
691 prefix->ip.words[0],
692 prefix->bits,
693 newacl->maxprivate,
694 newacl->maxpublic,
695 newacl->maxdenials,
696 newacl->deny,
697 newacl->trustpass,
698 oldcomment,
699 strlen(oldcomment) > 0 ? "\n" : "",
700 newcomment
701 );
702
703 SQ_execute_query(sql_connection, query, NULL);
704 SQ_close_connection(sql_connection);
705
706 wr_free(query);
707
708 return AC_OK;
709
710 }/* AC_acl_sql */
711
712 /*++++++++++++++++++++++++++++++++++++++
713 AC_ban_set:
714
715 re/sets the permanent ban flag both in the acl tree in memory
716 and the sql table. The "text" is appended to the comment
717 in the sql record (the expected cases are
718 - "automatic" in case the limit is exceeded and ban is set by s/w
719 - "manual" in case it is (un)set from the config iface
720
721 ip_prefix_t *prefix - prefix
722
723 char *text - usually "automatic" or "manual"
724
725 int denyflag - new value of the denyflag (ban)
726
727 returns error code from AC_acl_sql or OK
728 +++++++++++++++++++++++++++++++++++++++*/
729 er_ret_t
730 AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
/* [<][>][^][v][top][bottom][index][help] */
731 {
732 acl_st *treeacl;
733 char newcomment[256];
734 er_ret_t ret_err;
735 time_t clock;
736 char timebuf[26];
737 char prefstr[IP_PREFSTR_MAX];
738
739 time(&clock);
740 ctime_r(&clock, timebuf);
741
742 sprintf(newcomment,"%s permanent ban set to %d at %s", text,
743 denyflag, timebuf);
744
745 if( IP_pref_b2a(prefix, prefstr, IP_PREFSTR_MAX) != IP_OK ) {
746 die; /* program error - this is already converted so must be OK */
747 }
748
749 ER_inf_va( FAC_AC, ASP_AC_I_PERMBAN,
750 "%s permanent ban set to %d for %s", text, denyflag, prefstr );
751
752 TH_acquire_write_lock( &(act_acl->rwlock) );
753
754 /* find a record in the tree */
755 if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
756 treeacl->deny = denyflag;
757 ret_err = AC_acl_sql( prefix, treeacl, newcomment );
758 }
759 TH_release_write_lock( &(act_acl->rwlock) );
760
761 return ret_err;
762 }/* AC_ban_set */
763
764
765 /*++++++++++++++++++++++++++++++++++++++
766 AC_asc_ban_set:
767
768 sets ban on text address/range. Parses the text address/range/prefix
769 and then calls AC_ban_set on that prefix.
770
771 Precondition: if the key is a range, it must decompose into one prefix
772
773 returns error code from IP_smart_conv, AC_ban_set or
774 AC_INVARG if range composed
775 +++++++++++++++++++++++++++++++++++++++*/
776 er_ret_t
777 AC_asc_ban_set(char *addrstr, char *text, int denyflag)
/* [<][>][^][v][top][bottom][index][help] */
778 {
779 er_ret_t ret_err;
780 GList *preflist = NULL;
781 ip_keytype_t key_type;
782
783 if( (ret_err = IP_smart_conv(addrstr, 0, 0,
784 &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
785 return ret_err;
786 }
787
788 /* allow only one prefix */
789 /* The argument can be even a range, but must decompose into one prefix */
790 if( NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
791 ret_err = AC_INVARG;
792 }
793
794 if( NOERR(ret_err) ) {
795 ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
796 }
797
798 wr_clear_list( &preflist );
799
800 return ret_err;
801 }/* AC_asc_ban_set */
802
803 /*++++++++++++++++++++++++++++++++++++++
804 AC_asc_all_set:
805
806 take ascii prefix and find/create a new entry, inheriting all parameters
807 and then set them according to the array of args.
808
809 +*/
810 er_ret_t
811 AC_asc_all_set(ip_prefix_t *prefix, char *comment, char * array[])
/* [<][>][^][v][top][bottom][index][help] */
812 {
813 er_ret_t ret_err;
814 acl_st *treeacl;
815 int i;
816
817 TH_acquire_write_lock( &(act_acl->rwlock) );
818
819 /* find/create a record in the tree */
820 if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
821
822 /* update it from the array */
823 for(i=0; i<AC_AR_SIZE; i++) {
824 if(array[i] != NULL) { /* set only those that have been specified */
825 int val,k;
826
827 if( (k=sscanf( array[i], "%d", &val)) < 1 ) {
828 ret_err = AC_INVARG;
829 break; /* quit the for */
830 }
831
832 /* otherwise, the value makes sense. Put it in the structure. */
833 switch(i) {
834 case AC_AR_MAXPRIVATE: treeacl->maxprivate = val; break;
835 case AC_AR_MAXPUBLIC: treeacl->maxpublic = val; break;
836 case AC_AR_MAXDENIALS: treeacl->maxdenials = val; break;
837 case AC_AR_DENY: treeacl->deny = val; break;
838 case AC_AR_TRUSTPASS: treeacl->trustpass = val; break;
839 } /* switch */
840 } /* if array[i] not null */
841 } /* for each array element */
842
843 if( NOERR(ret_err) ) { /* protect against AC_INVARG */
844 ret_err = AC_acl_sql( prefix, treeacl, comment );
845 }
846 } /* if find/create OK */
847
848 TH_release_write_lock( &(act_acl->rwlock) );
849
850 return ret_err;
851 }
852
853
854 /*++++++++++++++++++++++++++++++++++++++
855 AC_asc_acl_command_set:
856
857 parse a command and set acl options for an entry.
858 command syntax:
859
860 <prefix> option=value,option=value,option=value...
861
862 where <option> is defined in AC_ar_acl[] array, value is an integer
863
864 char *command text of the command.
865 Syntax: ip[/prefixlength] column=value,column=value...
866 Column names as in acl display. Unset columns are inherited.
867
868 char *comment text to be added to the acl record's comment column.
869
870 ++++++++++++++++++++++++++++++++++++++*/
871
872 er_ret_t
873 AC_asc_acl_command_set( char *command, char *comment )
/* [<][>][^][v][top][bottom][index][help] */
874 {
875 ip_prefix_t *prefix;
876 char *eop, *eoc, *value;
877 char *array[AC_AR_SIZE];
878 er_ret_t ret_err = AC_OK;
879 GList *preflist = NULL;
880 ip_keytype_t key_type;
881
882 char *copy = strdup(command);
883 char *addrstr = copy;
884 eoc = strchr(copy, '\0'); /* points to the end of it */
885
886 memset(array, 0 ,sizeof(array));
887
888 /* first comes the prefix. Find the space after it
889 and break the string there.
890 */
891 if( (eop = strchr(copy,' ')) == NULL) {
892 ret_err = AC_INVARG;
893 }
894
895 if( NOERR(ret_err) ) {
896 *eop++ = 0;
897
898 /* now eop points to the rest of the string (if any). Take options.
899 */
900 while( eop != eoc && ret_err == AC_OK) {
901 char *sp;
902
903 /* give getsubopt chunks with no spaces */
904 if( (sp = strchr(eop, ' ')) != NULL ) {
905 *sp=0;
906 }
907
908 while( *eop != '\0' ) {
909 int k = getsubopt(&eop, AC_ar_acl, &value);
910 if( k < 0 ) {
911 ret_err = AC_INVARG;
912 break;
913 }
914
915 array[k] = value;
916 }
917
918 if( eop != eoc ) { /*getsubopt finished but did not consume all string*/
919 eop ++; /* must have been a space. advance one */
920 }
921 }
922 }
923
924 /* convert the prefix */
925 if( NOERR(ret_err) ) {
926 ret_err = IP_smart_conv(addrstr, 0, 0, &preflist, IP_PLAIN, &key_type);
927
928 /* allow only one prefix */
929 /* The argument can be even a range, but must decompose into one prefix */
930 if( NOERR(ret_err) && g_list_length( preflist ) == 1 ) {
931 prefix = (g_list_first(preflist)->data);
932 }
933 else {
934 ret_err = AC_INVARG;
935 }
936 }
937
938 /* perform changes */
939 if( NOERR(ret_err) ) {
940 ret_err = AC_asc_all_set(prefix, comment, array);
941 }
942
943 wr_clear_list( &preflist );
944 free(copy);
945
946 return ret_err;
947 }/* AC_asc_acl_command_set */
948
949
950 /*++++++++++++++++++++++++++++++++++++++
951 AC_asc_set_nodeny:
952
953 reset the deny counter in the access tree to 0 (after reenabling).
954
955 Operates on the runtime access tree.
956
957 char *ip text IP (ip only, not prefix or range).
958 +++++++++++++++++++++++++++++++++++++++*/
959 er_ret_t AC_asc_set_nodeny(char *ip)
/* [<][>][^][v][top][bottom][index][help] */
960 {
961 ip_prefix_t prefix;
962 er_ret_t ret_err;
963 acc_st *ac_ptr;
964
965 ret_err = IP_addr_e2b( &(prefix.ip), ip );
966 prefix.bits = IP_sizebits(prefix.ip.space);
967
968 if( NOERR(ret_err)) {
969 TH_acquire_write_lock( &(act_runtime->rwlock) );
970
971 ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
972 if( NOERR(ret_err)) {
973 ac_ptr->denials = 0;
974 }
975
976 TH_release_write_lock( &(act_runtime->rwlock) );
977 }
978
979 return ret_err;
980 }
981
982
983
984 /*++++++++++++++++++++++++++++++++++++++
985 AC_commit:
986
987 commits the credit into all accounting trees, (XXX: only one at the moment)
988 checks the limits and sets automatic ban if limit exceeded.
989
990 ip_addr_t *addr - user's address
991
992 acc_st *acc_conn - credit used
993
994 acl_st *acl_copy - pointer to store a copy of the acl
995
996 returns error code from AC_commit_credit or AC_ban_set or OK.
997
998 outline:
999 lock runtime + minute accounting trees
1000 ----------------------- XXX runtime only for the moment
1001 find or create entries,
1002 increase accounting values by the values from passed acc
1003 check values against acl, see if permanent ban applies
1004
1005 reset the connection acc
1006 unlock accounting trees
1007
1008 if permanent ban - set it! :
1009 lock acl
1010 find/create IP in memory
1011 set ban
1012 find/create IP in SQL
1013 copy old values (if any), set ban, append comment
1014 unlock acl
1015
1016 +++++++++++++++++++++++++++++++++++++++*/
1017 er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
/* [<][>][^][v][top][bottom][index][help] */
1018 acc_st account;
1019 er_ret_t ret_err;
1020 ip_prefix_t prefix;
1021
1022 prefix.ip = *addr;
1023 prefix.bits = IP_sizebits(addr->space);
1024
1025 TH_acquire_write_lock( &(act_runtime->rwlock) );
1026 ret_err = AC_commit_credit_l(act_runtime, &prefix, acc_conn, &account);
1027 TH_release_write_lock( &(act_runtime->rwlock) );
1028 /* XXX add more trees here */
1029
1030 memset(acc_conn,0, sizeof(acc_st));
1031
1032 /* set permanent ban if deserved and if not set yet */
1033 if( account.denials > acl_copy->maxdenials
1034 && acl_copy->deny == 0
1035 && NOERR(ret_err) ) {
1036
1037 ret_err = AC_ban_set(&prefix, "Automatic", 1);
1038 }
1039
1040 return ret_err;
1041 } /* AC_commit */
1042
1043
1044
1045 /*++++++++++++++++++++++++++++++++++++++
1046
1047
1048 unsigned AC_prune deletes the entries listed in the prunelist
1049 (this cannot be done from within the rx_walk_tree,
1050 because the walk would be confused).
1051 Returns number of nodes deleted.
1052
1053 GList *prunelist list of pointers to nodes that should be deleted.
1054 the prefixes actually are allocated in the node
1055 structures, so they must not be dereferenced after
1056 they are freed here.
1057
1058 ++++++++++++++++++++++++++++++++++++++*/
1059 unsigned AC_prune(GList *prunelist)
/* [<][>][^][v][top][bottom][index][help] */
1060 {
1061 GList *pitem;
1062 char prstr[IP_PREFSTR_MAX];
1063 unsigned count = 0;
1064 acc_st accu; /* to accumulate the accounting of deleted nodes */
1065 ip_prefix_t globalpref;
1066
1067 memset( &accu, 0, sizeof(accu));
1068
1069 for( pitem = g_list_first(prunelist);
1070 pitem != NULL;
1071 pitem = g_list_next(pitem)) {
1072
1073 rx_node_t *nodeptr = (rx_node_t *) pitem->data;
1074 ip_prefix_t *prefptr = &(nodeptr->prefix);
1075 acc_st *nodeacc = nodeptr->leaves_ptr->data;
1076
1077 AC_acc_addup(&accu, nodeacc, ACC_PLUS); /* transfer the account */
1078
1079 dieif( IP_pref_b2a( prefptr, prstr, IP_PREFSTR_MAX ) != IP_OK );
1080 ER_dbg_va( FAC_AC, ASP_AC_PRUNE_DET, "AC_prune: entry %s", prstr );
1081
1082 /* delete the node. Assume there's one and only one dataleaf */
1083 rx_bin_node( RX_OPER_DEL, prefptr, act_runtime, (void *)nodeacc );
1084 count ++;
1085 }
1086
1087 /* store the accumulated account at 0/0 */
1088 dieif( !NOERR (IP_pref_a2b( &globalpref, "0/0" )));
1089 AC_commit_credit_l(act_runtime, &globalpref, &accu, NULL);
1090
1091 return count;
1092 }
1093
1094
1095
1096 /*++++++++++++++++++++++++++++++++++++++
1097 AC_decay_hook:
1098
1099 action performed on a single account node during decay (diminishing the
1100 bonus). Conforms to rx_walk_tree interface, therefore some of the
1101 arguments do not apply and are not used.
1102
1103 rx_node_t *node - pointer to the node of the radix tree
1104
1105 int level - not used
1106
1107 int nodecounter - not used
1108
1109 void *con - in real life: (double *) - points to the decay factor.
1110
1111 returns always OK
1112 +++++++++++++++++++++++++++++++++++++++*/
1113 er_ret_t AC_decay_hook(rx_node_t *node, int level,
/* [<][>][^][v][top][bottom][index][help] */
1114 int nodecounter, void *con)
1115 {
1116 acc_st *a = node->leaves_ptr->data;
1117 ac_decay_data_t *dec_dat_p = (ac_decay_data_t *)con;
1118 double factor = dec_dat_p->decay_factor;
1119 double bpr, bpu;
1120
1121 bpr = a->private_bonus;
1122 bpu = a->public_bonus;
1123
1124 a->private_bonus *= factor;
1125 a->public_bonus *= factor;
1126
1127 /* XXX pending: if bonus is close to zero and the node did not hit
1128 its limit, and it's not an address-passing node
1129 then add it to the list of nodes for deletion */
1130
1131 ER_dbg_va( FAC_AC, ASP_AC_PRUNE_DET,
1132 "%5.2f / %5.2f * %5.2f -> %5.2f / %5.2f ",
1133 bpr, bpu, factor, a->private_bonus, a->public_bonus);
1134
1135 if( a->private_bonus < 0.5
1136 && a->public_bonus < 0.5
1137 && a->denials == 0
1138 && a->addrpasses == 0 ) {
1139 dec_dat_p->prunelist = g_list_append(dec_dat_p->prunelist, node);
1140 }
1141
1142 /* process accounting - add all queries to the total counter */
1143 dec_dat_p->newtotal += a->queries;
1144
1145 return RX_OK;
1146 } /* AC_decay_hook() */
1147
1148
1149
1150 /*++++++++++++++++++++++++++++++++++++++
1151 AC_decay:
1152
1153 Every AC_DECAY_TIME goes through the accounting tree(s) and decays the
1154 bonus values.
1155
1156 returns always OK
1157
1158 MT-Note This should be run as a detached thread.
1159 +++++++++++++++++++++++++++++++++++++++*/
1160 er_ret_t AC_decay(void) {
/* [<][>][^][v][top][bottom][index][help] */
1161 er_ret_t ret_err = AC_OK;
1162 ac_decay_data_t dec_dat;
1163 ut_timer_t begintime, endtime;
1164 unsigned pruned;
1165 float elapsed, rate, exactinterval;
1166 unsigned oldtotal = 0;
1167 unsigned increase;
1168 unsigned count;
1169
1170 TA_add(0, "decay");
1171
1172 UT_timeget( &endtime );
1173
1174 /* XXX uses CO_get_do_server() to see when to exit the program.
1175 this will change */
1176 while(CO_get_do_server()) {
1177 UT_timeget( &begintime );
1178 exactinterval = UT_timediff( &endtime, &begintime ); /* old endtime */
1179
1180 /* those values can be changed in runtime - so recalculate
1181 the decay factor vefore each pass */
1182 dieif( ca_get_ac_decay_halflife == 0 );
1183
1184 dec_dat.prunelist = NULL;
1185 /* the decay factor of
1186 f(t) = exp(-a*t)
1187 a = -ln(0.5) / t
1188 so for T being the half-life period and v being the sampling interval
1189 used as the unit of time
1190 a = -ln(0.5) / T;
1191 f(t+x) = exp(-a(t+x)) = f(t)*f(x) = f(t)*exp(-ax) =
1192 = f(t)*exp(ln(0.5)*v/T)
1193 so you multiply the previous value by exp(ln(0.5)*v/T)
1194 */
1195 dec_dat.decay_factor =
1196 exp ( -0.693147180559945 * exactinterval / ca_get_ac_decay_halflife) ;
1197 dec_dat.newtotal = 0;
1198
1199 TH_acquire_write_lock( &(act_runtime->rwlock) );
1200
1201 if( act_runtime->top_ptr != NULL ) {
1202 count = rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
1203 RX_WALK_SKPGLU, /* skip glue nodes */
1204 255, 0, 0, &dec_dat, &ret_err);
1205 }
1206 else {
1207 count = 0;
1208 }
1209
1210 /* it should also be as smart as to delete nodes that have reached
1211 zero, otherwise the whole of memory will be filled.
1212 Next release :-)
1213 */
1214
1215 pruned = AC_prune( dec_dat.prunelist );
1216 g_list_free( dec_dat.prunelist );
1217
1218 #if 0
1219 /* XXX dbg checking tree consistency */
1220 if( act_runtime->top_ptr != NULL ) {
1221 rx_treecheck_t errorfound;
1222 er_ret_t err;
1223 if( (err=RX_treecheck(act_runtime, 1, &errorfound)) != RX_OK ) {
1224 fprintf(stderr, "Nope! %d returned \n", err);
1225 ER_dbg_va( FAC_AC, ASP_AC_DECAY,
1226 "AC: checking access tree consistency: error %d", err);
1227 die; /* access tree not consistent */
1228 }
1229 }
1230 #endif
1231
1232 TH_release_write_lock( &(act_runtime->rwlock) );
1233
1234 UT_timeget(&endtime);
1235
1236 elapsed = UT_timediff( &begintime, &endtime);
1237
1238 ER_dbg_va( FAC_AC, ASP_AC_DECAY,
1239 "AC_decay: Pruned %d of %d nodes. Took %5.3fs. Runs every %ds.",
1240 pruned, count, elapsed, ca_get_ac_decay_interval);
1241
1242 /* number/rate of queries within the last <interval> */
1243 {
1244 char actbuf[32];
1245
1246 increase = dec_dat.newtotal - oldtotal;
1247 rate = increase / exactinterval;
1248
1249 sprintf(actbuf, "%.2f q/s in %.1fs", rate, exactinterval);
1250 TA_setactivity(actbuf);
1251
1252 oldtotal = dec_dat.newtotal;
1253 }
1254
1255 SV_sleep(ca_get_ac_decay_interval);
1256 } /* while */
1257
1258 TA_delete();
1259
1260 return ret_err;
1261 } /* AC_decay() */
1262
1263
1264 /*++++++++++++++++++++++++++++++++++++++
1265 AC_acc_load:
1266
1267 loads the acl access tree from the acl table of the RIPADMIN database.
1268 (takes port/host/user/password from the config module).
1269
1270 bails out if encounters problems with the database (logs to stderr).
1271
1272 returns error code from RX_bin_node or wr_malloc.
1273 ++++++++++++++++++++++++++++++++++++++*/
1274 er_ret_t AC_acc_load(void)
/* [<][>][^][v][top][bottom][index][help] */
1275 {
1276 SQ_connection_t *con=NULL;
1277 SQ_result_set_t *result;
1278 SQ_row_t *row;
1279 er_ret_t ret_err = RX_OK;
1280
1281 con = AC_dbopen_admin();
1282
1283 if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
1284 fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
1285 die;
1286 }
1287
1288 TH_acquire_write_lock( &(act_acl->rwlock) );
1289
1290 while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
1291 ip_prefix_t mypref;
1292 acl_st *newacl;
1293 #define NUMELEM (7)
1294 char *col[NUMELEM];
1295 unsigned myint, i;
1296
1297 memset(&mypref, 0, sizeof(ip_prefix_t));
1298 mypref.ip.space = IP_V4;
1299
1300 if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
1301 ) == UT_OK ) {
1302
1303 for(i=0; i<NUMELEM; i++) {
1304 if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
1305 die;
1306 }
1307 }
1308
1309 /* prefix ip */
1310 if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
1311
1312 /* prefix length */
1313 if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
1314
1315 /* acl contents */
1316 if( sscanf(col[2], "%u", & (newacl->maxprivate) ) < 1 ) { die; }
1317 if( sscanf(col[3], "%u", & (newacl->maxpublic) ) < 1 ) { die; }
1318 if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
1319
1320 /* these are chars therefore cannot read directly */
1321 if( sscanf(col[5], "%u", &myint ) < 1 ) { die; }
1322 else {
1323 newacl->deny = myint;
1324 }
1325 if( sscanf(col[6], "%u", &myint ) < 1 ) { die; }
1326 else {
1327 newacl->trustpass = myint;
1328 }
1329
1330 /* free space */
1331 for(i=0; i<NUMELEM; i++) {
1332 wr_free(col[i]);
1333 }
1334
1335 /* now add to the tree */
1336 ret_err = rx_bin_node( RX_OPER_CRE, &mypref,
1337 act_acl, (rx_dataleaf_t *) newacl );
1338 }
1339 } /* while row */
1340
1341 TH_release_write_lock( &(act_acl->rwlock) );
1342
1343 SQ_free_result(result);
1344 /* Close connection */
1345 SQ_close_connection(con);
1346
1347 return ret_err;
1348 } /* AC_acc_load */
1349
1350
1351
1352 /*++++++++++++++++++++++++++++++++++++++
1353 AC_build:
1354
1355 creates empty trees for accounting/acl.
1356
1357 returns error code from RX_tree_cre or OK.
1358 (XXX): just now only bails out when encounters problems.
1359 ++++++++++++++++++++++++++++++++++++++*/
1360 er_ret_t AC_build(void)
/* [<][>][^][v][top][bottom][index][help] */
1361 {
1362 /* create trees */
1363 if ( RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1364 RX_SUB_NONE, &act_runtime) != RX_OK
1365 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1366 RX_SUB_NONE, &act_hour) != RX_OK
1367 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1368 RX_SUB_NONE, &act_minute) != RX_OK
1369 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1370 RX_SUB_NONE, &act_acl) != RX_OK
1371 )
1372 die; /*can be changed to an error and handled ... some day */
1373
1374 return RX_OK;
1375 }
1376
1377 /*++++++++++++++++++++++++++++++++++++++
1378 ac_rxwalkhook_print:
1379
1380 action performed on a single account node
1381 when listing the contents of the access tree: format and print the
1382 data from this node.
1383
1384 Conforms to rx_walk_tree interface, therefore some of the
1385 arguments do not apply and are not used.
1386
1387 rx_node_t *node - pointer to the node of the radix tree
1388
1389 int level - not used
1390
1391 int nodecounter - not used
1392
1393 void *con - pointer to the target string (prints to it)
1394
1395 returns always OK
1396 +++++++++++++++++++++++++++++++++++++++*/
1397 static
1398 er_ret_t ac_rxwalkhook_print(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
1399 int level, int nodecounter,
1400 void *outvoid)
1401 {
1402 char adstr[IP_ADDRSTR_MAX];
1403 char *dat;
1404 GString *output = outvoid;
1405
1406 dieif( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK );
1407 /* program error. */
1408
1409 dat = ac_to_string( node->leaves_ptr );
1410 g_string_sprintfa(output, "%-20s %s\n", adstr, dat );
1411 wr_free(dat);
1412
1413 return RX_OK;
1414 } /* ac_rxwalkhook_print */
1415
1416
1417 /*++++++++++++++++++++++++++++++++++++++
1418 This function displays the access table to the given connection.
1419
1420 unsigned AC_print_access Returns the number of nodes traversed
1421
1422 GString *output target string
1423 ++++++++++++++++++++++++++++++++++++++*/
1424 unsigned AC_print_access(GString *output)
/* [<][>][^][v][top][bottom][index][help] */
1425 {
1426 int cnt = 0;
1427 er_ret_t err;
1428
1429 if( act_runtime->top_ptr != NULL ) {
1430 char *header = ac_to_string_header();
1431
1432 /* print header */
1433 g_string_append(output, header);
1434 wr_free(header);
1435
1436 cnt = rx_walk_tree(act_runtime->top_ptr, ac_rxwalkhook_print,
1437 RX_WALK_SKPGLU, /* print no glue nodes */
1438 255, 0, 0, output, &err);
1439 }
1440
1441 return cnt;
1442 } /* show_access() */
1443
1444
1445
1446 /*++++++++++++++++++++++++++++++++++++++
1447 ac_rxwalkhook_print_acl:
1448
1449 action performed on a single account node
1450 when listing the contents of the acl tree: format and print the
1451 data from this node.
1452
1453 Conforms to rx_walk_tree interface, therefore some of the
1454 arguments do not apply and are not used.
1455
1456 rx_node_t *node - pointer to the node of the radix tree
1457
1458 int level - not used
1459
1460 int nodecounter - not used
1461
1462 void *con - pointer to the target string (prints to it)
1463
1464 returns always OK
1465 +++++++++++++++++++++++++++++++++++++++*/
1466 static
1467 er_ret_t ac_rxwalkhook_print_acl(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
1468 int level, int nodecounter,
1469 void *outvoid)
1470 {
1471 char prefstr[IP_PREFSTR_MAX];
1472 char *dat;
1473 GString *output = outvoid;
1474
1475 dieif( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK );
1476
1477 dat = ac_acl_to_string( node->leaves_ptr );
1478 g_string_sprintfa(output, "%-20s %s\n", prefstr, dat );
1479 wr_free(dat);
1480
1481 return RX_OK;
1482 }/* ac_rxwalkhook_print_acl */
1483
1484
1485 /*++++++++++++++++++++++++++++++++++++++
1486 This function writes the acl (access control) table to the given
1487 Gstring (auto-expandable)
1488
1489 unsigned AC_print_acl Returns the number of nodes traversed
1490
1491 GString *output target string
1492 ++++++++++++++++++++++++++++++++++++++*/
1493 unsigned AC_print_acl(GString *output)
/* [<][>][^][v][top][bottom][index][help] */
1494 {
1495 /* Administrator wishes to show access control list. */
1496 int cnt = 0;
1497 er_ret_t err;
1498
1499 if( act_acl->top_ptr != NULL ) {
1500 char *header = ac_acl_to_string_header();
1501
1502 /* print header */
1503 g_string_append(output, header);
1504 wr_free(header);
1505
1506 cnt = rx_walk_tree(act_acl->top_ptr, ac_rxwalkhook_print_acl,
1507 RX_WALK_SKPGLU, /* print no glue nodes */
1508 255, 0, 0, output, &err);
1509 }
1510
1511 return cnt;
1512 }
1513
1514
1515 /*++++++++++++++++++++++++++++++++++++++
1516 AC_count_object:
1517
1518 accounts an objects in the credit accordingly to its type,
1519 or sets denial if the limit is defined and the credit is exceeded.
1520
1521 acc_st *acc_credit pointer to the credit structure (gets modified)
1522
1523 acl_st *acl acl, contains the limits for private/public objects
1524
1525 int private indicates if the object type is private
1526 ++++++++++++++++++++++++++++++++++++++*/
1527 void
1528 AC_count_object( acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1529 acl_st *acl,
1530 int private )
1531 {
1532 if( private ) {
1533 if( acc_credit->private_objects <= 0 && acl->maxprivate != -1 ) {
1534 /* must be negative - will be subtracted */
1535 acc_credit->denials = -1;
1536 } else {
1537 acc_credit->private_objects --;
1538 }
1539 }
1540 else {
1541 if( acc_credit->public_objects <= 0 && acl->maxpublic != -1 ) {
1542 acc_credit->denials = -1;
1543 } else {
1544 acc_credit->public_objects --;
1545 }
1546 }
1547 } /* AC_count_object */
1548
1549
1550 /* AC_credit_isdenied */
1551 /*++++++++++++++++++++++++++++++++++++++
1552
1553 checks the denied flag in credit (-1 or 1 means denied)
1554
1555 int
1556 AC_credit_isdenied returns 1 if denied, 0 otherwise
1557
1558 acc_st *acc_credit pointer to the credit structure
1559 ++++++++++++++++++++++++++++++++++++++*/
1560 int
1561 AC_credit_isdenied(acc_st *acc_credit)
/* [<][>][^][v][top][bottom][index][help] */
1562 {
1563 return (acc_credit->denials != 0);
1564 } /* AC_credit_isdenied */
1565
1566
1567 /* AC_get_higher_limit */
1568 /*++++++++++++++++++++++++++++++++++++++
1569
1570 returns the higher number of the two acl limits: maxprivate & maxpublic
1571 corrected w.r.t the current credit left,
1572 or unlimited if any of them is 'unlimited'.
1573
1574 int AC_get_higher_limit returns the higher limit
1575
1576 acc_st *acc_credit current credit left
1577
1578 acl_st *acl acl for that user
1579 ++++++++++++++++++++++++++++++++++++++*/
1580 int
1581 AC_get_higher_limit(acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1582 acl_st *acl)
1583 {
1584 if( acl->maxprivate == -1 || acl->maxpublic == -1 ) {
1585 return -1;
1586 }
1587 else {
1588 int a = acc_credit->private_objects;
1589 int b = acc_credit->public_objects;
1590
1591 return (a > b ? a : b);
1592 }
1593 }/* AC_get_higher_limit */