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_asc_set_nodeny
  20. AC_commit
  21. AC_decay_hook
  22. AC_decay
  23. AC_acc_load
  24. AC_build
  25. AC_rxwalkhook_print
  26. AC_rxwalkhook_print_acl
  27. AC_count_object
  28. AC_credit_isdenied
  29. AC_get_higher_limit

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

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