Source File modules/ac/access_control.c

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