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