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