## modules/ac/access_control.c

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

## FUNCTIONS

This source file includes following functions.

1. AC_to_string_header
2. AC_to_string
3. AC_credit_to_string
4. AC_acl_to_string_header
5. AC_acl_to_string
6. AC_findexless_acl_l
7. AC_findcreate_acl_l
8. AC_findcreate_account_l
9. AC_fetch_acc
10. AC_check_acl
11. AC_acc_addup
12. AC_commit_credit
13. AC_dbopen_admin
14. AC_acl_sql
15. AC_ban_set
16. AC_asc_ban_set
17. AC_asc_all_set
18. AC_asc_acl_command_set
19. AC_commit
20. AC_decay_hook
21. AC_decay
22. AC_acc_load
23. AC_build
24. AC_rxwalkhook_print
25. AC_rxwalkhook_print_acl
26. AC_count_object
27. AC_credit_isdenied
28. AC_get_higher_limit

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

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