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