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