## 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_acl_sql
14. AC_ban_set
15. AC_asc_ban_set
16. AC_commit
17. AC_decay_hook
18. AC_decay
19. AC_acc_load
20. AC_build
21. AC_rxwalkhook_print
22. AC_rxwalkhook_print_acl
23. AC_count_object
24. AC_credit_isdenied
25. AC_get_higher_limit

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

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