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