Source File modules/pw/protocol_whois.c

    1    | /***************************************
    2    |   $Revision: 1.50 $
    3    |
    4    |   Protocol whois module (pw).  Whois protocol.
    5    |
    6    |   Status: NOT REVUED, TESTED
    7    |
    8    |   ******************/ /******************
    9    |   Filename            : protocol_whois.c
    10   |   Authors             : ottrey@ripe.net - framework and draft implementation
    11   |                         marek@ripe.net - rewritten and extended.
    12   |   OSs Tested          : Solaris 2.6
    13   |   ******************/ /******************
    14   |   Copyright (c) 1999                              RIPE NCC
    15   |
    16   |   All Rights Reserved
    17   |
    18   |   Permission to use, copy, modify, and distribute this software and its
    19   |   documentation for any purpose and without fee is hereby granted,
    20   |   provided that the above copyright notice appear in all copies and that
    21   |   both that copyright notice and this permission notice appear in
    22   |   supporting documentation, and that the name of the author not be
    23   |   used in advertising or publicity pertaining to distribution of the
    24   |   software without specific, written prior permission.
    25   |
    26   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    27   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    28   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    29   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    30   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    31   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    32   |   ***************************************/
    33   | #include <stdio.h>
    34   | #include <glib.h>
    35   |
    36   | #include "NAME"
    37   |
    38   | #include "defs.h"
    39   | #include "protocol_whois.h"
    40   | #include "mysql_driver.h"
    41   | #include "query_command.h"
    42   | #include "query_instructions.h"
    43   | #include "constants.h"
    44   |
    45   | #include "access_control.h"
    46   | #include "sk.h"
    47   | #include "stubs.h"
    48   |
    49   | #include "ca_configFns.h"
    50   | #include "ca_macros.h"
    51   | #include "ca_srcAttribs.h"
    52   |
    53   | #include "protocol_mirror.h"
    54   |
    55   | #include "ta.h"
    56   | #include "timediff.h"
    57   |
    58   | #ifndef VERSION
    59   | #define VERSION "3"
    60   | #endif
    61   |
    62   | /*++++++++++++++++++++++++++++++++++++++
    63   |
    64   | void
    65   | display_file        opens a file and displays its contents to the
    66   |                     connection described in conn. structure.
    67   |
    68   |
    69   | sk_conn_st *condat  pointer to connection structure
    70   |
    71   | char *filename      file name
    72   |
    73   |   ++++++++++++++++++++++++++++++++++++++*/
    74   | static void
    75   | display_file(sk_conn_st *condat, char *filename)
    76   | {
    77   |   FILE *fp;
    78   | #define READBUFSIZE 148
    79   |   char buffer[READBUFSIZE+1];
    80   |   int bytes;
    81   |
    82   |   if( (fp=fopen( filename, "r" )) == NULL ) {
    83   |     ER_perror( FAC_PW, PW_CNTOPN, "%s : %s (%d)",
    84   | 	       filename, strerror(errno), errno);
    85   |   }
    86   |   else {
    87   |     while( (bytes=fread(buffer, 1, READBUFSIZE, fp)) > 0 ) {
    88   |       buffer[bytes] = 0;
    89   |       SK_cd_puts(condat, buffer);
    90   |     }
    91   |     fclose(fp);
    92   |   }
    93   | }/* display_file */
    94   |
    95   |
    96   | /*++++++++++++++++++++++++++++++++++++++
    97   |
    98   |   static void
    99   |   pw_log_query              logs the query to a file after it has finished.
    100  |                             Takes many parameters to have access to as much
    101  | 			    information as possible, including the original
    102  | 			    query, accounting, response time, status of the
    103  | 			    client connection, etc.
    104  |
    105  |
    106  |   Query_environ *qe       query environment
    107  |
    108  |   Query_command *qc       query command structure
    109  |
    110  |   acc_st *copy_credit     numbers of objects returned / referrals made
    111  |                           during this query
    112  |                           (calculated as original credit assigned before
    113  | 			  the query minus what's left after the query).
    114  |
    115  |   ut_timer_t begintime    time the processing began
    116  |
    117  |   ut_timer_t endtime      time the processing finished
    118  |
    119  |   char *hostaddress       text address of the real IP
    120  |
    121  |   char *input             original query (trailing whitespaces chopped off)
    122  |
    123  |   ++++++++++++++++++++++++++++++++++++++*/
    124  | static
    125  | void pw_log_query( Query_environ *qe,
    126  | 		   Query_command *qc,
    127  | 		   acc_st *copy_credit,
    128  | 		   ut_timer_t begintime,
    129  | 		   ut_timer_t endtime,
    130  | 		   char *hostaddress,
    131  | 		   char *input)
    132  | {
    133  |   char *qrystat = AC_credit_to_string(copy_credit);
    134  |   float elapsed;
    135  |   char *qrytypestr =
    136  |     qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
    137  |
    138  |
    139  |   elapsed = UT_timediff( &begintime, &endtime);
    140  |
    141  |   /* log the connection/query/#results/time/denial to file */
    142  |   ER_inf_va(FAC_PW, ASP_PW_I_QRYLOG,
    143  | 	    "<%s> %s%s %.2fs [%s] --  %s",
    144  | 	    qrystat,
    145  | 	    qe->condat.rtc ? "INT " : "",
    146  | 	    qrytypestr,
    147  | 	    elapsed, hostaddress, input
    148  | 	    );
    149  |   wr_free(qrystat);
    150  | } /* pw_log_query */
    151  |
    152  |
    153  |
    154  |
    155  | /*++++++++++++++++++++++++++++++++++++++
    156  |
    157  |   void
    158  |   PW_process_qc          processes the query commands determined in QC,
    159  |                          This is where all the real action of the query
    160  | 			 part is invoked.
    161  |
    162  |   Query_environ *qe      query environment
    163  |
    164  |   Query_command *qc      query command structure
    165  |
    166  |   acc_st *acc_credit     credit assigned to this IP
    167  |
    168  |   acl_st *acl_eip        current acl record applicable to this IP
    169  |
    170  |   ++++++++++++++++++++++++++++++++++++++*/
    171  | void PW_process_qc(Query_environ *qe,
    172  | 		   Query_command *qc,
    173  | 		   acc_st *acc_credit,
    174  | 		   acl_st *acl_eip )
    175  | {
    176  |   GList *qitem;
    177  |   Query_instructions *qis=NULL;
    178  |   er_ret_t err;
    179  |
    180  |   switch( qc->query_type ) {
    181  |   case QC_SYNERR:
    182  |     SK_cd_puts(&(qe->condat), USAGE);
    183  |     /* FALLTHROUGH */
    184  |   case QC_PARERR:
    185  |     /* parameter error. relevant error message is already printed */
    186  |
    187  |     /* force disconnection on error */
    188  |     qe->k = 0;
    189  |     break;
    190  |   case QC_NOKEY:
    191  |     /* no key (this is OK for some operational stuff, like -k) */
    192  |     break;
    193  |   case QC_EMPTY:
    194  |     /* The user didn't specify a key, so
    195  |        - print moron banner
    196  |        - force disconnection of the user. */
    197  |     {
    198  |       char *rep = ca_get_pw_err_nokey ;
    199  |       SK_cd_puts(&(qe->condat), rep);
    200  |       wr_free(rep);
    201  |     }
    202  |     qe->condat.rtc = SK_NOTEXT;
    203  |     break;
    204  |   case QC_HELP:
    205  |     {
    206  |       char *rep = ca_get_pw_help_file ;
    207  |       display_file( &(qe->condat), rep);
    208  |       wr_free(rep);
    209  |     }
    210  |     break;
    211  |   case QC_TEMPLATE:
    212  |     switch(qc->q) {
    213  |     case QC_Q_SOURCES:
    214  |       /* print source & mirroring info */
    215  |       {
    216  | 	GString *srcs = PM_get_nrtm_sources( & qe->condat.rIP, NULL);
    217  | 	SK_cd_puts(&(qe->condat), srcs->str);
    218  | 	g_string_free (srcs, TRUE);
    219  |       }
    220  |       break;
    221  |     case QC_Q_VERSION:
    222  |       SK_cd_puts(&(qe->condat), "% RIP version " VERSION "\n\n");
    223  |       break;
    224  |     default:
    225  |       /* EMPTY */;
    226  |     } /* -q */
    227  |
    228  |     if (qc->t >= 0) {
    229  |       SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t));
    230  |     }
    231  |     if (qc->v >= 0) {
    232  |       SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v));
    233  |     }
    234  |     break;
    235  |
    236  |   case QC_FILTERED:
    237  |     {
    238  |       char *rep = ca_get_pw_k_filter ;
    239  |       SK_cd_puts(&(qe->condat), rep);
    240  |       wr_free(rep);
    241  |     }
    242  |     /* FALLTROUGH */
    243  |   case QC_REAL:
    244  |     {
    245  |       char *rep = ca_get_pw_resp_header;
    246  |       SK_cd_puts(&(qe->condat), rep);
    247  |       wr_free(rep);
    248  |       SK_cd_puts(&(qe->condat), "\n");
    249  |     }
    250  |
    251  | #if 1
    252  |
    253  |     qis = QI_new(qc,qe);
    254  |
    255  |     /* go through all sources,
    256  |        stop if connection broken - further action is meaningless */
    257  |     for( qitem = g_list_first(qe->sources_list);
    258  | 	 qitem != NULL && qe->condat.rtc == 0;
    259  | 	 qitem = g_list_next(qitem)) {
    260  |
    261  |
    262  |       /* QI will decrement the credit counters */
    263  |       err = QI_execute(qitem->data, qis, qe, acc_credit, acl_eip );
    264  |       if( !NOERR(err) ) {
    265  | 	if( err == QI_CANTDB ) {
    266  | 	  SK_cd_puts(&(qe->condat), "% WARNING: Failed to make connection to ");
    267  | 	  SK_cd_puts(&(qe->condat), (char *)qitem->data);
    268  | 	  SK_cd_puts(&(qe->condat), " database.\n\n");
    269  | 	}
    270  | 	break; /* quit the loop after any error */
    271  |       }/* if error*/
    272  |
    273  |     }/* for every source */
    274  |
    275  |     QI_free(qis);
    276  |
    277  | #else
    278  |     /* test mode: do not run a query, make up some accounting values */
    279  |     {
    280  |       int i, m = random() & 0x0f;
    281  |       for( i=0 ; i<m ; i++ ) {
    282  | 	AC_count_object( acc_credit, acl_eip, random() & 0x01 );
    283  |       }
    284  |     }
    285  |
    286  | #endif
    287  |
    288  |     if( AC_credit_isdenied(acc_credit) ) {
    289  |       /* host reached the limit of returned contact information */
    290  |       char *rep = ca_get_pw_limit_reached ;
    291  |       SK_cd_puts(&(qe->condat), rep);
    292  |       wr_free(rep);
    293  |     }
    294  |
    295  |     break;
    296  |   default: die;
    297  |   }
    298  | } /* PW_process_qc */
    299  |
    300  |
    301  |
    302  |
    303  | /*++++++++++++++++++++++++++++++++++++++
    304  |
    305  |   void
    306  |   PW_interact             Main loop for interaction with a single client.
    307  |                           The function sets up the accounting for the client,
    308  | 			  invokes parsing, execution, logging and accounting
    309  | 			  of the query.
    310  |
    311  |   int sock                Socket that client is connected to.
    312  |
    313  |   ++++++++++++++++++++++++++++++++++++++*/
    314  | void PW_interact(int sock) {
    315  |   char input[MAX_INPUT_SIZE];
    316  |   int read_result;
    317  |   char *hostaddress=NULL;
    318  |   acl_st acl_rip,   acl_eip;
    319  |   acc_st acc_credit, copy_credit;
    320  |   Query_environ *qe=NULL;
    321  |   Query_command *qc=NULL;
    322  |   ut_timer_t begintime, endtime;
    323  |
    324  |     /* Get the IP of the client */
    325  |   hostaddress = SK_getpeername(sock);
    326  |   ER_dbg_va(FAC_PW, ASP_PW_CONN, "connection from %s", hostaddress);
    327  |
    328  |   /* Initialize the query environment. */
    329  |   qe = QC_environ_new(hostaddress, sock);
    330  |
    331  |   /* init the connection structure, set timeout for reading the query */
    332  |   SK_cd_make( &(qe->condat), sock, (unsigned) ca_get_keepopen);
    333  |
    334  |   TA_setcondat(&(qe->condat));
    335  |
    336  |   /* see if we should be talking at all */
    337  |   /* check the acl using the realIP, get a copy applicable to this IP */
    338  |   AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
    339  |
    340  |   do {
    341  |     int unauth_pass=0;
    342  |
    343  |     TA_setactivity("waiting for query");
    344  |     /* Read input */
    345  |     read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
    346  |     /* trash trailing whitespaces(including \n) */
    347  |     ut_string_chop(input);
    348  |
    349  |     TA_setactivity(input);
    350  |     TA_increment();
    351  |
    352  |     UT_timeget( &begintime );
    353  |
    354  |     qc = QC_create(input, qe);
    355  |
    356  |     {
    357  |       /* print the greeting text before the query */
    358  |       char *rep = ca_get_pw_banner ;
    359  |       SK_cd_puts(&(qe->condat), rep);
    360  |       wr_free(rep);
    361  |       SK_cd_puts(&(qe->condat), "\n");
    362  |     }
    363  |
    364  |     /* ADDRESS PASSING: check if -V option has passed IP in it */
    365  |     if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
    366  |       if(acl_rip.trustpass) {
    367  | 	acc_st pass_acc;
    368  |
    369  | 	/* accounting */
    370  | 	memset(&pass_acc, 0, sizeof(acc_st));
    371  | 	pass_acc.addrpasses=1;
    372  | 	AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
    373  |
    374  | 	/* set eIP to this IP */
    375  | 	qe->condat.eIP = qe->pIP;
    376  |       }
    377  |       else {
    378  | 	/* XXX shall we deny such user ? Now we can... */
    379  | 	ER_inf_va(FAC_PW, ASP_PW_I_PASSUN,
    380  | 		  "unauthorised address passing by %s", hostaddress);
    381  | 	unauth_pass = 1; /* keep in mind ... */
    382  |       }
    383  |     } /* if an address was passed */
    384  |
    385  |     /* start setting counters in the connection acc from here on
    386  |        decrement the credit counter (needed to prevent QI_execute from
    387  |        returning too many results */
    388  |
    389  |     /* check ACL. Get the proper acl record. Calculate credit */
    390  |     AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
    391  |     /* save the original credit, later check how much was used */
    392  |     copy_credit = acc_credit;
    393  |
    394  |     copy_credit.connections ++;
    395  |
    396  |     /* printing notices */
    397  |     if( unauth_pass && ! acl_rip.deny ) {
    398  |       /* host not authorised to pass addresses with -V */
    399  |       char *rep = ca_get_pw_acl_addrpass ;
    400  |       SK_cd_puts(&(qe->condat), rep);
    401  |       wr_free(rep);
    402  |     }
    403  |     if( acl_eip.deny || acl_rip.deny ) {
    404  |       /* access from host has been permanently denied */
    405  |       char *rep = ca_get_pw_acl_permdeny ;
    406  |       SK_cd_puts(&(qe->condat), rep);
    407  |       wr_free(rep);
    408  |     }
    409  |
    410  |     if( acl_eip.deny || acl_rip.deny || unauth_pass ) {
    411  |       copy_credit.denials ++;
    412  |     }
    413  |     else {
    414  |       /************ ACTUAL PROCESSING IS HERE ***********/
    415  |       PW_process_qc(qe, qc, &acc_credit, &acl_eip);
    416  |
    417  |       if( qc->query_type == QC_REAL ) {
    418  | 	copy_credit.queries ++;
    419  |       }
    420  |     }/* if denied ... else */
    421  |
    422  |     /* calc. the credit used, result  into copy_credit
    423  |        This step MUST NOT be forgotten. It must complement
    424  |        the initial calculation of a credit, otherwise accounting
    425  |        will go bgzzzzzt.
    426  |     */
    427  |     AC_acc_addup(&copy_credit, &acc_credit, ACC_MINUS);
    428  |
    429  |     /* now we can check how many results there were, etc. */
    430  |
    431  |     /* can say 'nothing found' only if:
    432  |        - the query did not just cause denial
    433  |        - was a 'real' query
    434  |        - nothing was returned
    435  |     */
    436  |
    437  |     if(  ! AC_credit_isdenied(&copy_credit)
    438  | 	 && (qc->query_type == QC_REAL || qc->query_type == QC_FILTERED)
    439  | 	 && copy_credit.private_objects + copy_credit.public_objects
    440  | 	 + copy_credit.referrals == 0 ) {
    441  |
    442  |       /* now: if the rtc flag is zero, the query ran to completion */
    443  |       if( qe->condat.rtc == 0 ) {
    444  | 	char *rep = ca_get_pw_notfound ;
    445  | 	SK_cd_puts(&(qe->condat), rep);
    446  | 	wr_free(rep);
    447  |       }
    448  |       else {
    449  | 	/* something happened. Hope for working socket and display message
    450  | 	   (won't hurt even if socket not operable)
    451  | 	*/
    452  | 	char *rep = ca_get_pw_connclosed ;
    453  | 	SK_cd_puts(&(qe->condat), rep);
    454  | 	wr_free(rep);
    455  |       }
    456  |     }
    457  |
    458  |
    459  |     UT_timeget(&endtime);
    460  |     /* query logging */
    461  |     pw_log_query(qe, qc, &copy_credit, begintime, endtime,
    462  | 		 hostaddress, input);
    463  |
    464  |     /* Commit the credit. This will deny if bonus limit hit
    465  |        and clear the copy */
    466  |     AC_commit(&(qe->condat.eIP), &copy_credit, &acl_eip);
    467  |
    468  |     /* end-of-result -> two empty lines */
    469  |     SK_cd_puts(&(qe->condat), "\n\n");
    470  |
    471  |     QC_free(qc);
    472  |   } /* do */
    473  |   while( qe->k && qe->condat.rtc == 0
    474  | 	 && AC_credit_isdenied( &copy_credit ) == 0
    475  | 	 && CO_get_whois_suspended() == 0);
    476  |
    477  |   /* Free the hostaddress */
    478  |   wr_free(hostaddress);
    479  |   /* Free the connection struct's dynamic data */
    480  |   SK_cd_free(&(qe->condat));
    481  |   /* Free the query_environ */
    482  |   QC_environ_free(qe);
    483  |
    484  | } /* PW_interact() */