modules/ac/access_control.c

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

DEFINITIONS

This source file includes following functions.
  1. ac_decay_data_t
  2. ac_to_string_header
  3. ac_to_string
  4. AC_credit_to_string
  5. ac_acl_to_string_header
  6. ac_acl_to_string
  7. ac_find_acl_l
  8. AC_findcreate_acl_l
  9. AC_findcreate_account_l
  10. AC_fetch_acc
  11. AC_check_acl
  12. AC_decay_leaf_l
  13. AC_acc_addup
  14. AC_commit_credit_l
  15. AC_dbopen_admin
  16. AC_acl_sql
  17. AC_ban_set
  18. AC_asc_ban_set
  19. AC_asc_all_set
  20. AC_asc_acl_command_set
  21. AC_asc_set_nodeny
  22. AC_commit
  23. AC_prune
  24. AC_prunable
  25. AC_decay_hook
  26. AC_decay
  27. AC_acc_load
  28. AC_build
  29. ac_rxwalkhook_print
  30. AC_print_access
  31. ac_rxwalkhook_print_acl
  32. AC_print_acl
  33. AC_count_object
  34. AC_credit_isdenied
  35. AC_get_higher_limit

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

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