## 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_find_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_l
13. AC_dbopen_admin
14. AC_acl_sql
15. AC_ban_set
16. AC_asc_ban_set
17. AC_asc_all_set
18. AC_asc_acl_command_set
19. AC_asc_set_nodeny
20. AC_commit
21. AC_prune
22. AC_decay_hook
23. AC_decay
24. AC_acc_load
25. AC_build
26. ac_rxwalkhook_print
27. AC_print_access
28. ac_rxwalkhook_print_acl
29. AC_print_acl
30. AC_count_object
31. AC_credit_isdenied
32. AC_get_higher_limit

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

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