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

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