## modules/pw/protocol_whois.c

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

## FUNCTIONS

This source file includes following functions.

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

       1 /***************************************
       2   $Revision: 1.44 $
       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
      11                         marek@ripe.net
      12   OSs Tested          : Solaris
      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_dictSyms.h"
      51 #include "ca_macros.h"
      52 #include "ca_srcAttribs.h"
      53
      54 #include "protocol_mirror.h"
      55
      56 #include "ta.h"
      57 #include "timediff.h"
      58
      59 /* open a file and display its contents to the connection (condat) */
      60 static void
      61 display_file(sk_conn_st *condat, char *filename)
         /* [<][>][^][v][top][bottom][index][help] */
      62 {
      63   FILE *fp;
      64 #define READBUFSIZE 148
      65   char buffer[READBUFSIZE+1];
      66   int bytes;
      67
      68   if( (fp=fopen( filename, "r" )) == NULL ) {
      69     ER_perror( FAC_PW, PW_CNTOPN, "%s : %s (%d)",
      70                filename, strerror(errno), errno);
      71   }
      72   else {
      73     while( (bytes=fread(buffer, 1, READBUFSIZE, fp)) > 0 ) {
      74       buffer[bytes] = 0;
      75       SK_cd_puts(condat, buffer);
      76     }
      77     fclose(fp);
      78   }
      79 }
      80
      81 void
      82 strchop(char *input)
         /* [<][>][^][v][top][bottom][index][help] */
      83 {
      84   unsigned char *co = (unsigned char *)strchr(input, '\0');
      85
      86   while( co != (unsigned char *)input && (isspace(*co) || *co == '\0') ) {
      87     *co = '\0';
      88     co--;
      89   }
      90 }
      91
      92
      93 static
      94 void pw_log_query( Query_environ *qe,
         /* [<][>][^][v][top][bottom][index][help] */
      95                    Query_command *qc,
      96                    acc_st *copy_credit,
      97                    ut_timer_t begintime,
      98                    ut_timer_t endtime,
      99                    char *hostaddress,
     100                    char *input)
     101 {
     102   char *qrystat = AC_credit_to_string(copy_credit);
     103   float elapsed;
     104   char *qrytypestr =
     105     qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
     106
     107
     108   elapsed = UT_timediff( &begintime, &endtime);
     109
     110   /* log the connection/query/#results/time/denial to file */
     111   ER_inf_va(FAC_PW, ASP_PW_I_QRYLOG,
     112             "<%s> %s%s %.2fs [%s] --  %s",
     113             qrystat,
     114             qe->condat.rtc ? "INT " : "",
     115             qrytypestr,
     116             elapsed, hostaddress, input
     117             );
     118   wr_free(qrystat);
     119 }
     120
     121
     122
     123
     124 er_ret_t PW_process_qc(Query_environ *qe,
         /* [<][>][^][v][top][bottom][index][help] */
     125                    Query_command *qc,
     126                    acc_st *acc_credit,
     127                    acl_st *acl_eip )
     128 {
     129   GList *qitem;
     130   Query_instructions *qis=NULL;
     131   er_ret_t err;
     132
     133   switch( qc->query_type ) {
     134   case QC_SYNERR:
     135     SK_cd_puts(&(qe->condat), USAGE);
     136     /* FALLTHROUGH */
     137   case QC_PARERR:
     138     /* parameter error. relevant error message is already printed */
     139
     140     /* force disconnection on error */
     141     qe->k = 0;
     142     break;
     143   case QC_NOKEY:
     144     /* no key (this is OK for some operational stuff, like -k) */
     145     break;
     146   case QC_EMPTY:
     147     /* The user didn't specify a key, so
     148        - print moron banner
     149        - force disconnection of the user. */
     150     {
     151       char *rep = ca_get_pw_err_nokey ;
     152       SK_cd_puts(&(qe->condat), rep);
     153       wr_free(rep);
     154     }
     155     qe->condat.rtc = SK_NOTEXT;
     156     break;
     157   case QC_HELP:
     158     {
     159       char *rep = ca_get_pw_help_file ;
     160       display_file( &(qe->condat), rep);
     161       wr_free(rep);
     162     }
     163     break;
     164   case QC_TEMPLATE:
     165     switch(qc->q) {
     166     case QC_Q_SOURCES:
     167       /* print source & mirroring info */
     168       {
     169         GString *srcs = PM_get_nrtm_sources( & qe->condat.rIP, NULL);
     170         SK_cd_puts(&(qe->condat), srcs->str);
     171         g_string_free (srcs, TRUE);
     172       }
     173       break;
     174     case QC_Q_VERSION:
     175       SK_cd_puts(&(qe->condat), "% RIP version " VERSION "\n\n");
     176       break;
     177     default:
     178       /* EMPTY */;
     179     } /* -q */
     180
     181     if (qc->t >= 0) {
     182       SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t));
     183     }
     184     if (qc->v >= 0) {
     185       SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v));
     186     }
     187     break;
     188
     189   case QC_FILTERED:
     190     {
     191       char *rep = ca_get_pw_k_filter ;
     192       SK_cd_puts(&(qe->condat), rep);
     193       wr_free(rep);
     194     }
     195     /* FALLTROUGH */
     196   case QC_REAL:
     197     {
     198       char *rep = ca_get_pw_resp_header;
     199       SK_cd_puts(&(qe->condat), rep);
     200       wr_free(rep);
     201       SK_cd_puts(&(qe->condat), "\n");
     202     }
     203
     204     qis = QI_new(qc,qe);
     205
     206     /* stop as soon as further action considered meaningless */
     207     for( qitem = g_list_first(qe->sources_list);
     208          qitem != NULL && qe->condat.rtc == 0;
     209          qitem = g_list_next(qitem)) {
     210
     211       /* QI will decrement the credit counters */
     212       err = QI_execute(qitem->data, qis, qe, acc_credit, acl_eip );
     213
     214       if( !NOERR(err) ) {
     215         if( err == QI_CANTDB ) {
     216           SK_cd_puts(&(qe->condat), "% WARNING: Failed to make connection to ");
     217           SK_cd_puts(&(qe->condat), (char *)qitem->data);
     218           SK_cd_puts(&(qe->condat), " database.\n\n");
     219         }
     220
     221         break; /* quit the loop after any error */
     222       }/* if */
     223
     224     }/* for every source */
     225
     226     QI_free(qis);
     227
     228     if( AC_credit_isdenied(acc_credit) ) {
     229       /* host reached the limit of returned contact information */
     230       char *rep = ca_get_pw_limit_reached ;
     231       SK_cd_puts(&(qe->condat), rep);
     232       wr_free(rep);
     233     }
     234
     235     break;
     236   default: die;
     237   }
     238
     239   return err;
     240 }
     241
     242 /* PW_interact() */
     243 /*++++++++++++++++++++++++++++++++++++++
     244   Interact with the client.
     245
     246   int sock Socket that client is connected to.
     247
     248   More:
     249   +html+ <PRE>
     250   Authors:
     251         ottrey (original CP/M version)
     252         marek
     253
     254   +html+ </PRE><DL COMPACT>
     255   +html+ <DT>Online References:
     256   +html+ <DD><UL>
     257   +html+ </UL></DL>
     258
     259   ++++++++++++++++++++++++++++++++++++++*/
     260 void PW_interact(int sock) {
         /* [<][>][^][v][top][bottom][index][help] */
     261   char input[MAX_INPUT_SIZE];
     262   int read_result;
     263   char *hostaddress=NULL;
     264   acl_st acl_rip,   acl_eip;
     265   acc_st acc_credit, copy_credit;
     266   Query_environ *qe=NULL;
     267   Query_command *qc=NULL;
     268   ut_timer_t begintime, endtime;
     269
     270
     271   /* Get the IP of the client */
     272   hostaddress = SK_getpeername(sock);
     273   ER_dbg_va(FAC_PW, ASP_PW_CONN, "connection from %s", hostaddress);
     274
     275   /* Initialize the query environment. */
     276   qe = QC_environ_new(hostaddress, sock);
     277
     278   /* init to zeros */
     279   memset( &(qe->condat), 0, sizeof(sk_conn_st));
     280   TA_setcondat(&(qe->condat));
     281
     282   /* set the connection data: both rIP and eIP to real IP */
     283   qe->condat.sock = sock;
     284   qe->condat.ip = hostaddress;
     285   SK_getpeerip(sock, &(qe->condat.rIP));
     286   qe->condat.eIP = qe->condat.rIP;
     287
     288   qe->condat.rd_timeout.tv_sec = ca_get_keepopen; /* read timeout */
     289
     290   /* see if we should be talking at all */
     291   /* check the acl using the realIP, get a copy applicable to this IP */
     292   AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
     293
     294   do {
     295     int unauth_pass=0;
     296
     297     TA_setactivity("waiting for query");
     298     /* Read input */
     299     read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
     300     /* trash trailing whitespaces(including \n) */
     301     strchop(input);
     302
     303     TA_setactivity(input);
     304     TA_increment();
     305
     306     UT_timeget( &begintime );
     307
     308     qc = QC_create(input, qe);
     309
     310     {
     311       /* print the greeting text before the query */
     312       char *rep = ca_get_pw_banner ;
     313       SK_cd_puts(&(qe->condat), rep);
     314       wr_free(rep);
     315       SK_cd_puts(&(qe->condat), "\n");
     316     }
     317
     318     /* ADDRESS PASSING: check if -V option has passed IP in it */
     319     if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
     320       if(acl_rip.trustpass) {
     321         acc_st pass_acc;
     322
     323         /* accounting */
     324         memset(&pass_acc, 0, sizeof(acc_st));
     325         pass_acc.addrpasses=1;
     326         AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
     327
     328         /* set eIP to this IP */
     329         qe->condat.eIP = qe->pIP;
     330       }
     331       else {
     332         /* XXX shall we deny such user ? Now we can... */
     333         ER_inf_va(FAC_PW, ASP_PW_I_PASSUN,
     334                   "unauthorised address passing by %s", hostaddress);
     335         unauth_pass = 1; /* keep in mind ... */
     336       }
     337     } /* if an address was passed */
     338
     339     /* start setting counters in the connection acc from here on
     340        decrement the credit counter (needed to prevent QI_execute from
     341        returning too many results */
     342
     343     /* check ACL. Get the proper acl record. Calculate credit */
     344     AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
     345     /* save the original credit, later check how much was used */
     346     copy_credit = acc_credit;
     347
     348     copy_credit.connections ++;
     349
     350     /* printing notices */
     351     if( unauth_pass && ! acl_rip.deny ) {
     352       /* host not authorised to pass addresses with -V */
     353       char *rep = ca_get_pw_acl_addrpass ;
     354       SK_cd_puts(&(qe->condat), rep);
     355       wr_free(rep);
     356     }
     357     if( acl_eip.deny || acl_rip.deny ) {
     358       /* access from host has been permanently denied */
     359       char *rep = ca_get_pw_acl_permdeny ;
     360       SK_cd_puts(&(qe->condat), rep);
     361       wr_free(rep);
     362     }
     363
     364     if( acl_eip.deny || acl_rip.deny || unauth_pass ) {
     365       copy_credit.denials ++;
     366     }
     367     else {
     368       /************ ACTUAL PROCESSING IS HERE ***********/
     369       PW_process_qc(qe, qc, &acc_credit, &acl_eip);
     370
     371       if( qc->query_type == QC_REAL ) {
     372         copy_credit.queries ++;
     373       }
     374     }/* if denied ... else */
     375
     376     /* calc. the credit used, result  into copy_credit
     377        This step MUST NOT be forgotten. It must complement
     378        the initial calculation of a credit, otherwise accounting
     379        will go bgzzzzzt.
     380     */
     381     AC_acc_addup(&copy_credit, &acc_credit, ACC_MINUS);
     382
     383     /* now we can check how many results there were, etc. */
     384
     385     /* can say 'nothing found' only if:
     386        - the query did not just cause denial
     387        - was a 'real' query
     388        - nothing was returned
     389     */
     390
     391     if(  ! AC_credit_isdenied(&copy_credit)
     392          && (qc->query_type == QC_REAL || qc->query_type == QC_FILTERED)
     393          && copy_credit.private_objects + copy_credit.public_objects
     394          + copy_credit.referrals == 0 ) {
     395
     396       /* now: if the rtc flag is zero, the query ran to completion */
     397       if( qe->condat.rtc == 0 ) {
     398         char *rep = ca_get_pw_notfound ;
     399         SK_cd_puts(&(qe->condat), rep);
     400         wr_free(rep);
     401       }
     402       else {
     403         /* something happened. Hope for working socket and display message
     404            (won't hurt even if socket not operable)
     405         */
     406         char *rep = ca_get_pw_connclosed ;
     407         SK_cd_puts(&(qe->condat), rep);
     408         wr_free(rep);
     409       }
     410     }
     411
     412
     413     UT_timeget(&endtime);
     414     /* query logging */
     415     pw_log_query(qe, qc, &copy_credit, begintime, endtime,
     416                  hostaddress, input);
     417
     418     /* Commit the credit. This will deny if bonus limit hit
     419        and clear the copy */
     420     AC_commit(&(qe->condat.eIP), &copy_credit, &acl_eip);
     421
     422     /* end-of-result -> two empty lines */
     423     SK_cd_puts(&(qe->condat), "\n\n");
     424
     425     QC_free(qc);
     426   } /* do */
     427   while( qe->k && qe->condat.rtc == 0
     428          && AC_credit_isdenied( &copy_credit ) == 0
     429          && CO_get_whois_suspended() == 0);
     430
     431   /* Free the hostaddress */
     432   wr_free(hostaddress);
     433
     434   /* Free the query_environ */
     435   QC_environ_free(qe);
     436
     437 } /* PW_interact() */

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