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