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