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