## modules/pw/protocol_whois.c

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

## FUNCTIONS

This source file includes following functions.

1. display_file
2. pw_log_query
3. PW_process_qc
4. PW_interact

       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)
         /* [<][>][^][v][top][bottom][index][help] */
      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,
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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() */

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