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_find_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_l
  13. AC_dbopen_admin
  14. AC_acl_sql
  15. AC_ban_set
  16. AC_asc_ban_set
  17. AC_asc_all_set
  18. AC_asc_acl_command_set
  19. AC_asc_set_nodeny
  20. AC_commit
  21. AC_prune
  22. AC_decay_hook
  23. AC_decay
  24. AC_acc_load
  25. AC_build
  26. ac_rxwalkhook_print
  27. AC_print_access
  28. ac_rxwalkhook_print_acl
  29. AC_print_acl
  30. AC_count_object
  31. AC_credit_isdenied
  32. AC_get_higher_limit

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

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