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