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