## 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] */