## 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

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

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