modules/ac/access_control.c

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

FUNCTIONS

This source file includes following functions.
  1. AC_to_string_header
  2. AC_to_string
  3. AC_credit_to_string
  4. AC_acl_to_string_header
  5. AC_acl_to_string
  6. AC_findexless_acl_l
  7. AC_findcreate_acl_l
  8. AC_findcreate_account_l
  9. AC_fetch_acc
  10. AC_check_acl
  11. AC_acc_addup
  12. AC_commit_credit
  13. AC_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_commit
  20. AC_decay_hook
  21. AC_decay
  22. AC_acc_load
  23. AC_build
  24. AC_rxwalkhook_print
  25. AC_rxwalkhook_print_acl
  26. AC_count_object
  27. AC_credit_isdenied
  28. AC_get_higher_limit

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

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