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