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