modules/ac/access_control.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. AC_to_string_header
  2. AC_to_string
  3. AC_credit_to_string
  4. AC_acl_to_string_header
  5. AC_acl_to_string
  6. AC_findexless_acl_l
  7. AC_findcreate_acl_l
  8. AC_findcreate_account_l
  9. AC_fetch_acc
  10. AC_check_acl
  11. AC_acc_addup
  12. AC_commit_credit
  13. AC_acl_sql
  14. AC_ban_set
  15. AC_asc_ban_set
  16. AC_commit
  17. AC_decay_hook
  18. AC_decay
  19. AC_acc_load
  20. AC_build
  21. AC_rxwalkhook_print
  22. AC_rxwalkhook_print_acl
  23. AC_count_object
  24. AC_credit_isdenied
  25. AC_get_higher_limit

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

/* [<][>][^][v][top][bottom][index][help] */