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