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