1 | /***************************************
2 | $Revision: 1.20 $
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 | #include <stdio.h>
31 | #include <glib.h>
32 |
33 | #define AC_OK RX_OK
34 | #define AC_INVARG IP_INVARG
35 |
36 | #define AC_IMPL
37 | #include <rxroutines.h>
38 | #include <erroutines.h>
39 | #include <access_control.h>
40 | #include "socket.h"
41 | #include "mysql_driver.h"
42 | #include <constants.h>
43 | #include <server.h>
44 |
45 | #define AC_DECAY_TIME 600
46 |
47 | /* formats for printing the access control list entries */
48 | #define ACL_FORMAT "%10d %10d %10d %10d %10d"
49 | #define ACL_HEADER "%-20s %10s %10s %10s %10s %10s\n"
50 |
51 | /* formats for printing the accounting entries */
52 | #define ACC_FORMAT "%4d %4d %4d %4d %6d %6d %6d"
53 | #define ACC_HEADER "%-20s %4s %4s %4s %4s %6s %6s %6s\n"
54 |
55 |
56 | /*++++++++++++++++++++++++++++++++++++++
57 | AC_to_string_header:
58 |
59 | produce a header for the access stats printout
60 |
61 | returns an allocated string
62 | ++++++++++++++++++++++++++++++++++++++*/
63 | char *AC_to_string_header(void)
64 | {
65 | char *result_buf;
66 |
67 | dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
68 |
69 | sprintf(result_buf, ACC_HEADER,
70 | "ip", "conn", "pass", "deny", "qry", "pub", "priv", "bonus" );
71 |
72 | return result_buf;
73 | }
74 |
75 | /*++++++++++++++++++++++++++++++++++++++
76 | AC_to_string:
77 |
78 | Show an access structure
79 |
80 | returns an allocated string
81 | ++++++++++++++++++++++++++++++++++++++*/
82 | char *AC_to_string(GList *leafptr)
83 | {
84 | char *result_buf;
85 | acc_st *a = leafptr->data;
86 |
87 | if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
88 | /* XXX generic malloc handler pending ...*/
89 | return NULL;
90 | }
91 |
92 | if( a == NULL ) {
93 | strcpy(result_buf, "DATA MISSING!");
94 | }
95 | else {
96 | sprintf(result_buf, ACC_FORMAT,
97 | a->connections,
98 | a->addrpasses,
99 | a->denials,
100 | a->queries,
101 | a->public_objects,
102 | a->private_objects,
103 | a->private_bonus
104 | );
105 | }
106 |
107 | return result_buf;
108 | } /* AC_to_string() */
109 |
110 |
111 | /*++++++++++++++++++++++++++++++++++++++
112 | AC_credit_to_string:
113 |
114 | Show credit used (for logging of queries)
115 |
116 | acc_st *a - the credit structure
117 |
118 | returns an allocated string
119 | ++++++++++++++++++++++++++++++++++++++*/
120 | char *AC_credit_to_string(acc_st *a)
121 | {
122 | char *result_buf;
123 |
124 | if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
125 | /* XXX generic malloc handler pending ...*/
126 | return NULL;
127 | }
128 |
129 | dieif( a == NULL );
130 |
131 | sprintf(result_buf,"%d+%d%s",
132 | a->private_objects,
133 | a->public_objects,
134 | a->denials ? " **DENIED**" : ""
135 | );
136 |
137 | return result_buf;
138 | } /* AC_credit_to_string */
139 |
140 |
141 | /*+++++++++++++++++++++++++++++++++++++++
142 | AC_acl_to_string_header:
143 |
144 | produce a header for the acl printout
145 |
146 | returns an allocated string
147 | ++++++++++++++++++++++++++++++++++++++*/
148 | char *
149 | AC_acl_to_string_header(void)
150 | {
151 | char *result_buf;
152 | dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
153 |
154 | sprintf(result_buf, ACL_HEADER, "ip",
155 | "maxbonus", "maxdenials", "maxpublic", "ban", "trustpass" );
156 |
157 | return result_buf;
158 | }
159 |
160 |
161 |
162 | /*++++++++++++++++++++++++++++++++++++++
163 | AC_acl_to_string:
164 |
165 | Show an access control list structure
166 |
167 | returns an allocated string
168 | ++++++++++++++++++++++++++++++++++++++*/
169 | char *AC_acl_to_string(GList *leafptr)
170 | {
171 | char *result_buf;
172 | acl_st *a = leafptr->data;
173 |
174 | if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
175 | /* XXX generic malloc handler pending ...*/
176 | return NULL;
177 | }
178 |
179 | if( a != NULL ) {
180 | sprintf(result_buf, ACL_FORMAT,
181 | a->maxbonus,
182 | a->maxdenials,
183 | a->maxpublic,
184 | a->deny,
185 | a->trustpass
186 | );
187 | }
188 | else {
189 | strcpy(result_buf, "DATA MISSING\n");
190 | }
191 |
192 | return result_buf;
193 | } /* AC_acl_to_string() */
194 |
195 |
196 | /*+++++++++++++++++++++++++++++++++++++++
197 | AC_findexless_acl_l:
198 |
199 | find the exact or less specific match for the given prefix in the acl tree.
200 |
201 | ip_prefix_t *prefix - prefix to look for
202 | acl_st *store_acl - pointer to store the output
203 |
204 | returns error code from RX or OK
205 |
206 | MT-Note: assumes locked acl tree
207 | ++++++++++++++++++++++++++++++++++++++*/
208 | er_ret_t
209 | AC_findexless_acl_l(ip_prefix_t *prefix, acl_st *store_acl)
210 | {
211 | GList *datlist=NULL;
212 | er_ret_t ret_err;
213 | rx_datref_t *datref;
214 |
215 | if( (ret_err = RX_bin_search(RX_SRCH_EXLESS, 0, 0, act_acl,
216 | prefix, &datlist, RX_ANS_ALL)
217 | ) != RX_OK || g_list_length(datlist) == 0 ) {
218 | /* acl tree is not configured at all ! There always must be a
219 | catch-all record with defaults */
220 | die;
221 | }
222 |
223 | datref = (rx_datref_t *)g_list_nth_data(datlist,0);
224 |
225 | *store_acl = * ((acl_st *) datref->leafptr);
226 |
227 | wr_clear_list( &datlist );
228 |
229 | /* XXX dbg checking tree consistency */
230 | {
231 | rx_treecheck_t errorfound;
232 | er_ret_t err;
233 | if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
234 | fprintf(stderr, "Nope! %d returned \n", err);
235 | die;
236 | }
237 | }
238 |
239 | return ret_err;
240 | }
241 | /* AC_findexless_acl_l */
242 |
243 |
244 | /*+++++++++++++++++++++++++++++++++++++++
245 | AC_findcreate_acl_l:
246 |
247 | find or create an entry for the given prefix in the acl tree.
248 |
249 | ip_prefix_t *prefix - prefix to look for
250 | acl_st **store_acl - pointer to store the ptr to the acl struct
251 | (initialised to the values of the parent entry
252 | if just created)
253 |
254 | returns error code from RX or OK
255 |
256 | MT-Note: assumes locked acl tree
257 | ++++++++++++++++++++++++++++++++++++++*/
258 | er_ret_t
259 | AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
260 | {
261 | GList *datlist=NULL;
262 | er_ret_t ret_err;
263 | acl_st *newacl;
264 | acl_st acl_copy;
265 |
266 | if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl,
267 | prefix, &datlist, RX_ANS_ALL)
268 | )) {
269 |
270 | switch( g_list_length(datlist)) {
271 | case 0:
272 | dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
273 |
274 | /* make the new one inherit all parameters after the old one */
275 |
276 | AC_findexless_acl_l(prefix, &acl_copy);
277 |
278 | *newacl = acl_copy;
279 |
280 | /* link in */
281 | rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
282 | break;
283 | case 1:
284 | {
285 | /* Uh-oh, the guy is already known ! (or special, in any case) */
286 | rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
287 | newacl = (acl_st *) datref->leafptr;
288 | }
289 | break;
290 | default:
291 | die;
292 | }
293 | }
294 |
295 | /* free search results */
296 | wr_clear_list( &datlist );
297 |
298 | /* store */
299 | *store_acl = newacl;
300 | return ret_err;
301 | }
302 | /* AC_findcreate_acl_l */
303 |
304 |
305 | /*+++++++++++++++++++++++++++++++++++++++
306 | AC_findcreate_account_l:
307 |
308 | finds exact prefix in the accounting tree
309 | or creates area initialised to zeros + sets ptr to it.
310 |
311 | rx_tree_t *tree - the tree
312 | ip_prefix_t *prefix - prefix to look for
313 | acc_st **store_acl - pointer to store the ptr to the account struct
314 |
315 | returns error code from RX or OK
316 |
317 | MT-Note: assumes locked accounting tree
318 | ++++++++++++++++++++++++++++++++++++++*/
319 | er_ret_t
320 | AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix,
321 | acc_st **acc_store)
322 | {
323 | GList *datlist=NULL;
324 | er_ret_t ret_err;
325 | acc_st *recacc;
326 |
327 | if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree,
328 | prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
329 | switch( g_list_length(datlist) ) {
330 | case 0:
331 | /* need to create a new accounting record */
332 | if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
333 | /* counters = init to zeros */
334 | memset( recacc, 0, sizeof(acc_st));
335 |
336 | /* attach. The recacc is to be treated as a dataleaf
337 | (must use lower levels than RX_asc_*)
338 | */
339 | ret_err = rx_bin_node( RX_OPER_CRE, prefix,
340 | act_runtime, (rx_dataleaf_t *)recacc );
341 | }
342 | break;
343 | case 1:
344 | {
345 | rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
346 |
347 | /* OK, there is a record already */
348 | recacc = (acc_st *) datref->leafptr;
349 |
350 | }
351 | break;
352 | default: die; /* there shouldn't be more than 1 entry per IP */
353 | }
354 | }
355 |
356 | wr_clear_list( &datlist );
357 |
358 | *acc_store = recacc;
359 |
360 | return ret_err;
361 | }
362 |
363 |
364 | /*++++++++++++++++++++++++++++++++++++++
365 | AC_fetch_acc:
366 |
367 | Finds the runtime accounting record for this IP,
368 | stores a copy of it in acc_store.
369 | If not found, then it is created and initialised to zeros in findcreate()
370 |
371 | ip_addr_t *addr - address
372 | acc_st *acc_store - pointer to store the account struct
373 |
374 | MT-Note: locks/unlocks the accounting tree
375 | ++++++++++++++++++++++++++++++++++++++*/
376 | er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
377 | {
378 | er_ret_t ret_err;
379 | ip_prefix_t prefix;
380 | acc_st *ac_ptr;
381 |
382 | prefix.ip = *addr;
383 | prefix.bits = IP_sizebits(addr->space);
384 |
385 | TH_acquire_read_lock( &(act_runtime->rwlock) );
386 |
387 | ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
388 | *acc_store = *ac_ptr;
389 |
390 | TH_release_read_lock( &(act_runtime->rwlock) );
391 |
392 | return ret_err;
393 | }/* AC_fetch_acc() */
394 |
395 |
396 | /*++++++++++++++++++++++++++++++++++++++
397 | AC_check_acl:
398 |
399 | search for this ip or less specific record in the access control tree
400 |
401 | if( bonus in combined runtime+connection accountings > max_bonus in acl)
402 | set denial in the acl for this ip (create if needed)
403 | if( combined denialcounter > max_denials in acl)
404 | set the permanent ban in acl; save in SQL too
405 | calculate credit if pointer provided
406 | save the access record (ip if created or found/prefix otherwise)
407 | at *acl_store if provided
408 |
409 | ip_addr_t *addr - address
410 | acc_st *acc_store - pointer to store the *credit* account struct
411 | acl_st *acl_store - pointer to store the acl struct
412 |
413 | any of the args except address can be NULL
414 |
415 | returns error code from RX or OK
416 |
417 | MT-Note: locks/unlocks the accounting tree
418 | ++++++++++++++++++++++++++++++++++++++*/
419 | er_ret_t AC_check_acl( ip_addr_t *addr,
420 | acc_st *credit_acc,
421 | acl_st *acl_store
422 | )
423 | {
424 | ip_prefix_t prefix;
425 | er_ret_t ret_err;
426 | acl_st acl_record;
427 | acc_st run_acc;
428 |
429 | AC_fetch_acc( addr, &run_acc );
430 |
431 | prefix.ip = *addr;
432 | prefix.bits = IP_sizebits(addr->space);
433 |
434 | /* lock the tree accordingly */
435 | TH_acquire_read_lock( &(act_acl->rwlock) );
436 |
437 | /* find an applicable record */
438 | AC_findexless_acl_l(&prefix, &acl_record);
439 |
440 | /* calculate the credit if pointer given */
441 | if( credit_acc ) {
442 | memset( credit_acc, 0, sizeof(acc_st));
443 | credit_acc->public_objects = /* -1 == unlimited */
444 | acl_record.maxpublic - run_acc.public_objects;
445 | credit_acc->private_objects =
446 | acl_record.maxbonus - run_acc.private_bonus;
447 | }
448 |
449 | /* copy the acl record if asked for it*/
450 | if( acl_store ) {
451 | *acl_store = acl_record;
452 | }
453 |
454 | /* release lock */
455 | TH_release_read_lock( &(act_acl->rwlock) );
456 |
457 |
458 | return ret_err;
459 | }
460 |
461 |
462 |
463 | /*++++++++++++++++++++++++++++++++++++++
464 | AC_acc_addup:
465 |
466 | Add/subtract the values from one accounting structure to another
467 |
468 | acc_st *a - this one gets changed
469 | acc_st *b - this one provides the values to change a
470 | int minus - triggers subtraction if non-zero
471 |
472 | +++++++++++++++++++++++++++++++++++++++*/
473 | void AC_acc_addup(acc_st *a, acc_st *b, int minus)
474 | {
475 | int mul = minus ? -1 : 1;
476 |
477 | /* add all counters from b to those in a */
478 | a->connections += mul * b->connections;
479 | a->addrpasses += mul * b->addrpasses;
480 |
481 | a->denials += mul * b->denials;
482 | a->queries += mul * b->queries;
483 | a->public_objects += mul * b->public_objects;
484 | a->private_objects += mul * b->private_objects;
485 | a->private_bonus += mul * b->private_bonus;
486 | }/* AC_acc_addup */
487 |
488 | /*++++++++++++++++++++++++++++++++++++++
489 | AC_commit_credit:
490 |
491 | performs the commit on an accounting tree (locks them first)
492 | stores a copy of the accounting record at rec_store
493 |
494 | rx_tree_t *tree - the tree
495 | ip_prefix_t *prefix - prefix (usually a /32)
496 | acc_st *acc_conn - credit used
497 | acc_st *rec_store - pointer to store the account struct
498 |
499 | returns error code from AC_findcreate_account_l or OK
500 |
501 | MT-Note: locks/unlocks the accounting tree
502 | +++++++++++++++++++++++++++++++++++++++*/
503 | er_ret_t
504 | AC_commit_credit(rx_tree_t *tree, ip_prefix_t *prefix,
505 | acc_st *acc_conn, acc_st *rec_store )
506 | {
507 | acc_st *accountrec;
508 | er_ret_t ret_err;
509 |
510 |
511 | acc_conn->private_bonus = acc_conn->private_objects;
512 |
513 | TH_acquire_write_lock( &(tree->rwlock) );
514 |
515 | ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
516 |
517 | if( NOERR(ret_err)) {
518 | AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
519 | }
520 |
521 | TH_release_write_lock( &(tree->rwlock) );
522 |
523 | *rec_store = *accountrec;
524 |
525 | return ret_err;
526 | }/* AC_commit_credit */
527 |
528 |
529 |
530 | /*++++++++++++++++++++++++++++++++++++++
531 | AC_acl_sql:
532 |
533 | updates/creates a record for the given prefix in the acl table of
534 | the RIPADMIN database. Adds a comment.
535 |
536 | ip_prefix_t *prefix - prefix
537 | acl_st *newacl - new values to store in the database
538 | char *newcomment - comment to be added (must not be NULL)
539 |
540 | placeholder: it may return an error code from SQ - as soon as sq
541 | implements common error scheme
542 |
543 | ++++++++++++++++++++++++++++++++++++++*/
544 | er_ret_t
545 | AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
546 | {
547 | SQ_connection_t *sql_connection = NULL;
548 | SQ_result_set_t *result;
549 | SQ_row_t *row;
550 | char *oldcomment;
551 | char *query;
552 | char querybuf[256];
553 |
554 | sql_connection = SQ_get_connection(CO_get_host(),
555 | CO_get_database_port(),
556 | "RIPADMIN",
557 | CO_get_user(),
558 | CO_get_password() );
559 |
560 | /* get the old entry, extend it */
561 | sprintf(querybuf, "SELECT comment FROM acl WHERE "
562 | "prefix = %u AND prefix_length = %d",
563 | prefix->ip.words[0],
564 | prefix->bits);
565 | dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
566 |
567 | if( SQ_num_rows(result) == 1 ) {
568 | dieif( (row = SQ_row_next(result)) == NULL);
569 | oldcomment = SQ_get_column_string(result, row, 0);
570 | }
571 | else {
572 | oldcomment = "";
573 | }
574 |
575 | SQ_free_result(result);
576 |
577 | /* must hold the thing below (REPLACE..blah blah blah) + text */
578 | dieif( wr_malloc((void **)&query,
579 | strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
580 |
581 | /* compose new entry and insert it */
582 | sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
583 | "\"%s%s%s\")",
584 | prefix->ip.words[0],
585 | prefix->bits,
586 | newacl->maxbonus,
587 | newacl->maxpublic,
588 | newacl->maxdenials,
589 | newacl->deny,
590 | newacl->trustpass,
591 | oldcomment,
592 | strlen(oldcomment) > 0 ? "\n" : "",
593 | newcomment
594 | );
595 |
596 | SQ_execute_query(sql_connection, query, NULL);
597 | SQ_close_connection(sql_connection);
598 |
599 | wr_free(query);
600 |
601 | return AC_OK;
602 |
603 | }/* AC_acl_sql */
604 |
605 | /*++++++++++++++++++++++++++++++++++++++
606 | AC_ban_set:
607 |
608 | re/sets the permanent ban flag both in the acl tree in memory
609 | and the sql table. The "text" is appended to the comment
610 | in the sql record (the expected cases are
611 | - "automatic" in case the limit is exceeded and ban is set by s/w
612 | - "manual" in case it is (un)set from the config iface
613 |
614 | ip_prefix_t *prefix - prefix
615 | char *text - usually "automatic" or "manual"
616 | int denyflag - new value of the denyflag (ban)
617 |
618 | returns error code from AC_acl_sql or OK
619 | +++++++++++++++++++++++++++++++++++++++*/
620 | er_ret_t
621 | AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
622 | {
623 | acl_st *treeacl;
624 | char newcomment[256];
625 | er_ret_t ret_err;
626 | time_t clock;
627 | char timebuf[26];
628 |
629 | time(&clock);
630 | ctime_r(&clock, timebuf);
631 |
632 | sprintf(newcomment,"%s permanent ban set to %d at %s", text,
633 | denyflag, timebuf);
634 |
635 | TH_acquire_write_lock( &(act_acl->rwlock) );
636 |
637 | /* find a record in the tree */
638 | if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
639 | treeacl->deny = denyflag;
640 | ret_err = AC_acl_sql( prefix, treeacl, newcomment );
641 | }
642 | TH_release_write_lock( &(act_acl->rwlock) );
643 |
644 | return ret_err;
645 | }/* AC_ban_set */
646 |
647 |
648 | /*++++++++++++++++++++++++++++++++++++++
649 | AC_asc_ban_set:
650 |
651 | sets ban on text address/range. Parses the text address/range/prefix
652 | and then calls AC_ban_set on that prefix.
653 |
654 | Precondition: if the key is a range, it must decompose into one prefix
655 |
656 | returns error code from IP_smart_conv, AC_ban_set or
657 | AC_INVARG if range composed
658 | +++++++++++++++++++++++++++++++++++++++*/
659 | er_ret_t
660 | AC_asc_ban_set(char *addrstr, char *text, int denyflag)
661 | {
662 | er_ret_t ret_err;
663 | GList *preflist = NULL;
664 | ip_keytype_t key_type;
665 |
666 | if( (ret_err = IP_smart_conv(addrstr, 0, 0,
667 | &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
668 | return ret_err;
669 | }
670 |
671 | /* allow only one prefix */
672 | /* The argument can be even a range, but must decompose into one prefix */
673 | if( NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
674 | ret_err = AC_INVARG;
675 | }
676 |
677 | if( NOERR(ret_err) ) {
678 | ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
679 | }
680 |
681 | wr_clear_list( &preflist );
682 |
683 | return ret_err;
684 | }/* AC_asc_ban_set */
685 |
686 |
687 | /*++++++++++++++++++++++++++++++++++++++
688 | AC_commit:
689 |
690 | commits the credit into all accounting trees, (XXX: only one at the moment)
691 | checks the limits and sets automatic ban if limit exceeded.
692 |
693 | ip_addr_t *addr - user's address
694 | acc_st *acc_conn - credit used
695 | acl_st *acl_copy - pointer to store a copy of the acl
696 |
697 | returns error code from AC_commit_credit or AC_ban_set or OK.
698 |
699 | outline:
700 | lock runtime + minute accounting trees
701 | ----------------------- XXX runtime only for the moment
702 | find or create entries,
703 | increase accounting values by the values from passed acc
704 | check values against acl, see if permanent ban applies
705 |
706 | reset the connection acc
707 | unlock accounting trees
708 |
709 | if permanent ban - set it! :
710 | lock acl
711 | find/create IP in memory
712 | set ban
713 | find/create IP in SQL
714 | copy old values (if any), set ban, append comment
715 | unlock acl
716 |
717 | +++++++++++++++++++++++++++++++++++++++*/
718 | er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
719 | acc_st account;
720 | er_ret_t ret_err;
721 | ip_prefix_t prefix;
722 |
723 | prefix.ip = *addr;
724 | prefix.bits = IP_sizebits(addr->space);
725 |
726 | ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
727 | /* XXX add more trees here */
728 |
729 | memset(acc_conn,0, sizeof(acc_st));
730 |
731 | /* set permanent ban if deserved and if not set yet */
732 | if( account.denials > acl_copy->maxdenials
733 | && acl_copy->deny == 0
734 | && NOERR(ret_err) ) {
735 |
736 | ret_err = AC_ban_set(&prefix, "Automatic", 1);
737 | }
738 |
739 | return ret_err;
740 | } /* AC_commit */
741 |
742 |
743 | /*++++++++++++++++++++++++++++++++++++++
744 | AC_decay_hook:
745 |
746 | action performed on a single account node during decay (diminishing the
747 | bonus). Conforms to rx_walk_tree interface, therefore some of the
748 | arguments do not apply and are not used.
749 |
750 | rx_node_t *node - pointer to the node of the radix tree
751 | int level - n/a
752 | int nodecounter - n/a
753 | void *con - n/a
754 |
755 | returns always OK
756 | +++++++++++++++++++++++++++++++++++++++*/
757 | er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con)
758 | {
759 | acc_st *a = node->leaves_ptr->data;
760 |
761 | a->private_bonus *= 0.95;
762 |
763 | return RX_OK;
764 | } /* AC_decay_hook() */
765 |
766 |
767 |
768 | /*++++++++++++++++++++++++++++++++++++++
769 | AC_decay:
770 |
771 | Every AC_DECAY_TIME goes through the accounting tree(s) and decays the
772 | bonus values.
773 |
774 | returns always OK
775 |
776 | MT-Note This should be run as a detached thread.
777 | +++++++++++++++++++++++++++++++++++++++*/
778 | er_ret_t AC_decay(void) {
779 | er_ret_t ret_err;
780 |
781 |
782 | while(CO_get_do_server()) {
783 |
784 | TH_acquire_write_lock( &(act_runtime->rwlock) );
785 |
786 | if( act_runtime->top_ptr != NULL ) {
787 | rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
788 | RX_WALK_SKPGLU, /* skip glue nodes */
789 | 255, 0, 0, NULL, &ret_err);
790 | }
791 |
792 | /* it should also be as smart as to delete nodes that have reached
793 | zero, otherwise the whole of memory will be filled.
794 | Next release :-)
795 | */
796 |
797 | TH_release_write_lock( &(act_runtime->rwlock) );
798 |
799 | printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
800 |
801 | SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
802 | }
803 |
804 | return ret_err;
805 | } /* AC_decay() */
806 |
807 |
808 | /*++++++++++++++++++++++++++++++++++++++
809 | AC_acc_load:
810 |
811 | loads the acl access tree from the acl table of the RIPADMIN database.
812 | (takes port/host/user/password from the config module).
813 |
814 | bails out if encounters problems with the database (logs to stderr).
815 |
816 | returns error code from RX_bin_node or wr_malloc.
817 | ++++++++++++++++++++++++++++++++++++++*/
818 | er_ret_t AC_acc_load(void)
819 | {
820 | SQ_connection_t *con=NULL;
821 | SQ_result_set_t *result;
822 | SQ_row_t *row;
823 | er_ret_t ret_err = RX_OK;
824 |
825 | if( (con = SQ_get_connection(CO_get_host(), CO_get_database_port(),
826 | "RIPADMIN", CO_get_user(), CO_get_password() )
827 | ) == NULL ) {
828 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
829 | die;
830 | }
831 |
832 | if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
833 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
834 | die;
835 | }
836 |
837 | TH_acquire_write_lock( &(act_acl->rwlock) );
838 |
839 | while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
840 | ip_prefix_t mypref;
841 | acl_st *newacl;
842 | char *col[7];
843 | unsigned myint;
844 | int i;
845 |
846 | memset(&mypref, 0, sizeof(ip_prefix_t));
847 | mypref.ip.space = IP_V4;
848 |
849 | if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
850 | ) == UT_OK ) {
851 |
852 | for(i=0; i<7; i++) {
853 | if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
854 | die;
855 | }
856 | }
857 |
858 | /* prefix ip */
859 | if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
860 |
861 | /* prefix length */
862 | if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
863 |
864 | /* acl contents */
865 | if( sscanf(col[2], "%u", & (newacl->maxbonus) ) < 1 ) { die; }
866 | if( sscanf(col[3], "%u", & (newacl->maxpublic) ) < 1 ) { die; }
867 | if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
868 |
869 | /* these are chars therefore cannot read directly */
870 | if( sscanf(col[5], "%u", &myint ) < 1 ) { die; }
871 | else {
872 | newacl->deny = myint;
873 | }
874 | if( sscanf(col[6], "%u", &myint ) < 1 ) { die; }
875 | else {
876 | newacl->trustpass = myint;
877 | }
878 |
879 | /* free space */
880 | for(i=0; i<6; i++) {
881 | wr_free(col[i]);
882 | }
883 |
884 | /* now add to the tree */
885 | ret_err = rx_bin_node( RX_OPER_CRE, &mypref,
886 | act_acl, (rx_dataleaf_t *) newacl );
887 | }
888 | } /* while row */
889 |
890 | TH_release_write_lock( &(act_acl->rwlock) );
891 |
892 | SQ_free_result(result);
893 | /* Close connection */
894 | SQ_close_connection(con);
895 |
896 | return ret_err;
897 | } /* AC_acc_load */
898 |
899 |
900 |
901 | /*++++++++++++++++++++++++++++++++++++++
902 | AC_build:
903 |
904 | creates empty trees for accounting/acl.
905 |
906 | returns error code from RX_tree_cre or OK.
907 | (XXX): just now only bails out when encounters problems.
908 | ++++++++++++++++++++++++++++++++++++++*/
909 | er_ret_t AC_build(void)
910 | {
911 | /* create trees */
912 | if ( RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
913 | RX_SUB_NONE, &act_runtime) != RX_OK
914 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
915 | RX_SUB_NONE, &act_hour) != RX_OK
916 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
917 | RX_SUB_NONE, &act_minute) != RX_OK
918 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
919 | RX_SUB_NONE, &act_acl) != RX_OK
920 | )
921 | die; /*can be changed to an error and handled ... some day */
922 |
923 | return RX_OK;
924 | }
925 |
926 | /*++++++++++++++++++++++++++++++++++++++
927 | AC_rxwalkhook_print:
928 |
929 | action performed on a single account node
930 | when listing the contents of the access tree: format and print the
931 | data from this node.
932 |
933 | Conforms to rx_walk_tree interface, therefore some of the
934 | arguments do not apply and are not used.
935 |
936 | rx_node_t *node - pointer to the node of the radix tree
937 | int level - n/a
938 | int nodecounter - n/a
939 | void *con - pointer to the connection structure (prints to it)
940 |
941 | returns always OK
942 | +++++++++++++++++++++++++++++++++++++++*/
943 | er_ret_t AC_rxwalkhook_print(rx_node_t *node,
944 | int level, int nodecounter,
945 | void *con)
946 | {
947 | char adstr[IP_ADDRSTR_MAX];
948 | char line[1024];
949 | char *dat;
950 |
951 |
952 | if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
953 | die; /* program error. */
954 | }
955 |
956 | sprintf(line, "%-20s %s\n", adstr,
957 | dat=AC_to_string( node->leaves_ptr ));
958 | wr_free(dat);
959 |
960 | SK_cd_puts((sk_conn_st *)con, line);
961 | return RX_OK;
962 | } /* AC_rxwalkhook_print */
963 |
964 |
965 | /*++++++++++++++++++++++++++++++++++++++
966 | AC_rxwalkhook_print_acl:
967 |
968 | action performed on a single account node
969 | when listing the contents of the acl tree: format and print the
970 | data from this node.
971 |
972 | Conforms to rx_walk_tree interface, therefore some of the
973 | arguments do not apply and are not used.
974 |
975 | rx_node_t *node - pointer to the node of the radix tree
976 | int level - n/a
977 | int nodecounter - n/a
978 | void *con - pointer to the connection structure (prints to it)
979 |
980 | returns always OK
981 | +++++++++++++++++++++++++++++++++++++++*/
982 | er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node,
983 | int level, int nodecounter,
984 | void *con)
985 | {
986 | char prefstr[IP_PREFSTR_MAX];
987 | char line[1024];
988 | char *dat;
989 |
990 |
991 | if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
992 | die; /* program error. */
993 | }
994 |
995 | sprintf(line, "%-20s %s\n", prefstr,
996 | dat=AC_acl_to_string( node->leaves_ptr ));
997 | wr_free(dat);
998 |
999 | SK_cd_puts((sk_conn_st *)con, line);
1000 | return RX_OK;
1001 | }/* AC_rxwalkhook_print_acl */
1002 |