## modules/ac/access_control.c

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

## DEFINITIONS

This source file includes following functions.

1. ac_decay_data_t
2. ac_to_string_header
3. ac_to_string
4. AC_credit_to_string
5. ac_acl_to_string_header
6. ac_acl_to_string
7. ac_find_acl_l
8. AC_findcreate_acl_l
9. AC_findcreate_account_l
10. AC_fetch_acc
11. AC_check_acl
12. AC_decay_leaf_l
13. AC_acc_addup
14. AC_commit_credit_l
15. AC_dbopen_admin
16. AC_acl_sql
17. AC_ban_set
18. AC_asc_ban_set
19. AC_asc_all_set
20. AC_asc_acl_command_set
21. AC_asc_set_nodeny
22. AC_commit
23. AC_prune
24. AC_prunable
25. AC_decay_hook
26. AC_decay
27. AC_acc_load
28. AC_build
29. ac_rxwalkhook_print
30. AC_print_access
31. ac_rxwalkhook_print_acl
32. AC_print_acl
33. AC_count_object
34. AC_credit_isdenied
35. AC_get_higher_limit

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

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