Source File modules/ac/access_control.c

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