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] */