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

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