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.25 $
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 eop = strchr(copy,' ');
819 *eop++ = 0;
820
821 /* now eop points to the rest of the string (if any). Take options.
822 */
823 while( eop != eoc && ret_err == AC_OK) {
824 char *sp;
825
826 /* give getsubopt chunks with no spaces */
827 if( (sp = strchr(eop, ' ')) != NULL ) {
828 *sp=0;
829 }
830
831 while( *eop != '\0' ) {
832 int k = getsubopt(&eop, AC_ar_acl, &value);
833 if( k < 0 ) {
834 ret_err = AC_INVARG;
835 break;
836 }
837
838 array[k] = value;
839 }
840
841 if( eop != eoc ) { /*getsubopt finished but did not consume all string*/
842 eop ++; /* must have been a space. advance one */
843 }
844 }
845
846 /* convert the prefix */
847 if( NOERR(ret_err) ) {
848 ret_err = IP_smart_conv(addrstr, 0, 0, &preflist, IP_PLAIN, &key_type);
849
850 /* allow only one prefix */
851 /* The argument can be even a range, but must decompose into one prefix */
852 if( NOERR(ret_err) && g_list_length( preflist ) == 1 ) {
853 prefix = (g_list_first(preflist)->data);
854 }
855 else {
856 ret_err = AC_INVARG;
857 }
858 }
859
860 /* perform changes */
861 if( NOERR(ret_err) ) {
862 ret_err = AC_asc_all_set(prefix, comment, array);
863 }
864
865 wr_clear_list( &preflist );
866 free(copy);
867
868 return ret_err;
869 }
870
871
872 /*++++++++++++++++++++++++++++++++++++++
873 AC_commit:
874
875 commits the credit into all accounting trees, (XXX: only one at the moment)
876 checks the limits and sets automatic ban if limit exceeded.
877
878 ip_addr_t *addr - user's address
879 acc_st *acc_conn - credit used
880 acl_st *acl_copy - pointer to store a copy of the acl
881
882 returns error code from AC_commit_credit or AC_ban_set or OK.
883
884 outline:
885 lock runtime + minute accounting trees
886 ----------------------- XXX runtime only for the moment
887 find or create entries,
888 increase accounting values by the values from passed acc
889 check values against acl, see if permanent ban applies
890
891 reset the connection acc
892 unlock accounting trees
893
894 if permanent ban - set it! :
895 lock acl
896 find/create IP in memory
897 set ban
898 find/create IP in SQL
899 copy old values (if any), set ban, append comment
900 unlock acl
901
902 +++++++++++++++++++++++++++++++++++++++*/
903 er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
/* [<][>][^][v][top][bottom][index][help] */
904 acc_st account;
905 er_ret_t ret_err;
906 ip_prefix_t prefix;
907
908 prefix.ip = *addr;
909 prefix.bits = IP_sizebits(addr->space);
910
911 ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
912 /* XXX add more trees here */
913
914 memset(acc_conn,0, sizeof(acc_st));
915
916 /* set permanent ban if deserved and if not set yet */
917 if( account.denials > acl_copy->maxdenials
918 && acl_copy->deny == 0
919 && NOERR(ret_err) ) {
920
921 ret_err = AC_ban_set(&prefix, "Automatic", 1);
922 }
923
924 return ret_err;
925 } /* AC_commit */
926
927
928 /*++++++++++++++++++++++++++++++++++++++
929 AC_decay_hook:
930
931 action performed on a single account node during decay (diminishing the
932 bonus). Conforms to rx_walk_tree interface, therefore some of the
933 arguments do not apply and are not used.
934
935 rx_node_t *node - pointer to the node of the radix tree
936 int level - n/a
937 int nodecounter - n/a
938 void *con - n/a
939
940 returns always OK
941 +++++++++++++++++++++++++++++++++++++++*/
942 er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con)
/* [<][>][^][v][top][bottom][index][help] */
943 {
944 acc_st *a = node->leaves_ptr->data;
945
946 a->private_bonus *= 0.95;
947 a->public_bonus *= 0.95;
948
949 return RX_OK;
950 } /* AC_decay_hook() */
951
952
953
954 /*++++++++++++++++++++++++++++++++++++++
955 AC_decay:
956
957 Every AC_DECAY_TIME goes through the accounting tree(s) and decays the
958 bonus values.
959
960 returns always OK
961
962 MT-Note This should be run as a detached thread.
963 +++++++++++++++++++++++++++++++++++++++*/
964 er_ret_t AC_decay(void) {
/* [<][>][^][v][top][bottom][index][help] */
965 er_ret_t ret_err = AC_OK;
966
967
968 while(CO_get_do_server()) {
969
970 TH_acquire_write_lock( &(act_runtime->rwlock) );
971
972 if( act_runtime->top_ptr != NULL ) {
973 rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
974 RX_WALK_SKPGLU, /* skip glue nodes */
975 255, 0, 0, NULL, &ret_err);
976 }
977
978 /* it should also be as smart as to delete nodes that have reached
979 zero, otherwise the whole of memory will be filled.
980 Next release :-)
981 */
982
983 TH_release_write_lock( &(act_runtime->rwlock) );
984
985 printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
986
987 SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
988 }
989
990 return ret_err;
991 } /* AC_decay() */
992
993
994 /*++++++++++++++++++++++++++++++++++++++
995 AC_acc_load:
996
997 loads the acl access tree from the acl table of the RIPADMIN database.
998 (takes port/host/user/password from the config module).
999
1000 bails out if encounters problems with the database (logs to stderr).
1001
1002 returns error code from RX_bin_node or wr_malloc.
1003 ++++++++++++++++++++++++++++++++++++++*/
1004 er_ret_t AC_acc_load(void)
/* [<][>][^][v][top][bottom][index][help] */
1005 {
1006 SQ_connection_t *con=NULL;
1007 SQ_result_set_t *result;
1008 SQ_row_t *row;
1009 er_ret_t ret_err = RX_OK;
1010
1011 con = AC_dbopen_admin();
1012
1013 if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
1014 fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
1015 die;
1016 }
1017
1018 TH_acquire_write_lock( &(act_acl->rwlock) );
1019
1020 while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
1021 ip_prefix_t mypref;
1022 acl_st *newacl;
1023 #define NUMELEM (7)
1024 char *col[NUMELEM];
1025 unsigned myint;
1026 int i;
1027
1028 memset(&mypref, 0, sizeof(ip_prefix_t));
1029 mypref.ip.space = IP_V4;
1030
1031 if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
1032 ) == UT_OK ) {
1033
1034 for(i=0; i<NUMELEM; i++) {
1035 if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
1036 die;
1037 }
1038 }
1039
1040 /* prefix ip */
1041 if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
1042
1043 /* prefix length */
1044 if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
1045
1046 /* acl contents */
1047 if( sscanf(col[2], "%u", & (newacl->maxprivate) ) < 1 ) { die; }
1048 if( sscanf(col[3], "%u", & (newacl->maxpublic) ) < 1 ) { die; }
1049 if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
1050
1051 /* these are chars therefore cannot read directly */
1052 if( sscanf(col[5], "%u", &myint ) < 1 ) { die; }
1053 else {
1054 newacl->deny = myint;
1055 }
1056 if( sscanf(col[6], "%u", &myint ) < 1 ) { die; }
1057 else {
1058 newacl->trustpass = myint;
1059 }
1060
1061 /* free space */
1062 for(i=0; i<NUMELEM; i++) {
1063 wr_free(col[i]);
1064 }
1065
1066 /* now add to the tree */
1067 ret_err = rx_bin_node( RX_OPER_CRE, &mypref,
1068 act_acl, (rx_dataleaf_t *) newacl );
1069 }
1070 } /* while row */
1071
1072 TH_release_write_lock( &(act_acl->rwlock) );
1073
1074 SQ_free_result(result);
1075 /* Close connection */
1076 SQ_close_connection(con);
1077
1078 return ret_err;
1079 } /* AC_acc_load */
1080
1081
1082
1083 /*++++++++++++++++++++++++++++++++++++++
1084 AC_build:
1085
1086 creates empty trees for accounting/acl.
1087
1088 returns error code from RX_tree_cre or OK.
1089 (XXX): just now only bails out when encounters problems.
1090 ++++++++++++++++++++++++++++++++++++++*/
1091 er_ret_t AC_build(void)
/* [<][>][^][v][top][bottom][index][help] */
1092 {
1093 /* create trees */
1094 if ( RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1095 RX_SUB_NONE, &act_runtime) != RX_OK
1096 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1097 RX_SUB_NONE, &act_hour) != RX_OK
1098 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1099 RX_SUB_NONE, &act_minute) != RX_OK
1100 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
1101 RX_SUB_NONE, &act_acl) != RX_OK
1102 )
1103 die; /*can be changed to an error and handled ... some day */
1104
1105 return RX_OK;
1106 }
1107
1108 /*++++++++++++++++++++++++++++++++++++++
1109 AC_rxwalkhook_print:
1110
1111 action performed on a single account node
1112 when listing the contents of the access tree: format and print the
1113 data from this node.
1114
1115 Conforms to rx_walk_tree interface, therefore some of the
1116 arguments do not apply and are not used.
1117
1118 rx_node_t *node - pointer to the node of the radix tree
1119 int level - n/a
1120 int nodecounter - n/a
1121 void *con - pointer to the connection structure (prints to it)
1122
1123 returns always OK
1124 +++++++++++++++++++++++++++++++++++++++*/
1125 er_ret_t AC_rxwalkhook_print(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
1126 int level, int nodecounter,
1127 void *con)
1128 {
1129 char adstr[IP_ADDRSTR_MAX];
1130 char line[1024];
1131 char *dat;
1132
1133
1134 if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
1135 die; /* program error. */
1136 }
1137
1138 sprintf(line, "%-20s %s\n", adstr,
1139 dat=AC_to_string( node->leaves_ptr ));
1140 wr_free(dat);
1141
1142 SK_cd_puts((sk_conn_st *)con, line);
1143 return RX_OK;
1144 } /* AC_rxwalkhook_print */
1145
1146
1147 /*++++++++++++++++++++++++++++++++++++++
1148 AC_rxwalkhook_print_acl:
1149
1150 action performed on a single account node
1151 when listing the contents of the acl tree: format and print the
1152 data from this node.
1153
1154 Conforms to rx_walk_tree interface, therefore some of the
1155 arguments do not apply and are not used.
1156
1157 rx_node_t *node - pointer to the node of the radix tree
1158 int level - n/a
1159 int nodecounter - n/a
1160 void *con - pointer to the connection structure (prints to it)
1161
1162 returns always OK
1163 +++++++++++++++++++++++++++++++++++++++*/
1164 er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
1165 int level, int nodecounter,
1166 void *con)
1167 {
1168 char prefstr[IP_PREFSTR_MAX];
1169 char line[1024];
1170 char *dat;
1171
1172
1173 if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
1174 die; /* program error. */
1175 }
1176
1177 sprintf(line, "%-20s %s\n", prefstr,
1178 dat=AC_acl_to_string( node->leaves_ptr ));
1179 wr_free(dat);
1180
1181 SK_cd_puts((sk_conn_st *)con, line);
1182 return RX_OK;
1183 }/* AC_rxwalkhook_print_acl */
1184
1185 /*++++++++++++++++++++++++++++++++++++++
1186 AC_count_object:
1187
1188 accounts an objects in the credit accordingly to its type,
1189 or sets denial if the limit is defined and the credit is exceeded.
1190
1191 type - object type
1192 credit - pointer to the credit structure (gets modified)
1193
1194 */
1195 void
1196 AC_count_object( acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1197 acl_st *acl,
1198 int private )
1199 {
1200 if( private ) {
1201 if( acc_credit->private_objects <= 0 && acl->maxprivate != -1 ) {
1202 /* must be negative - will be subtracted */
1203 acc_credit->denials = -1;
1204 } else {
1205 acc_credit->private_objects --;
1206 }
1207 }
1208 else {
1209 if( acc_credit->public_objects <= 0 && acl->maxpublic != -1 ) {
1210 acc_credit->denials = -1;
1211 } else {
1212 acc_credit->public_objects --;
1213 }
1214 }
1215 } /* AC_count_object */
1216
1217
1218 /*++++++++++++++++++++++++++++++++++++++
1219 AC_credit_isdenied:
1220 checks the denied flag in credit (-1 or 1 => denied)
1221
1222 credit - pointer to the credit structure
1223 +*/
1224 int
1225 AC_credit_isdenied(acc_st *acc_credit)
/* [<][>][^][v][top][bottom][index][help] */
1226 {
1227 return (acc_credit->denials != 0);
1228 } /* AC_credit_isdenied */
1229
1230
1231 /*++++++++++++++++++++++++++++++++++++++
1232 AC_get_higher_limit:
1233
1234 returns the higher number of the two acl limits: maxprivate & maxpublic
1235 corrected w.r.t the current credit left,
1236 or unlimited if any of them is 'unlimited'.
1237 +*/
1238 int
1239 AC_get_higher_limit(acc_st *acc_credit,
/* [<][>][^][v][top][bottom][index][help] */
1240 acl_st *acl)
1241 {
1242 if( acl->maxprivate == -1 && acl->maxpublic == -1 ) {
1243 return -1;
1244 }
1245 else {
1246 int a = acc_credit->private_objects;
1247 int b = acc_credit->public_objects;
1248
1249 return (a > b ? a : b);
1250 }
1251 }