1    | /***************************************
2    |   $Revision: 1.24 $
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 "objects.h"
46   | */
47   | #include "access_control.h"
48   | #include "socket.h"
49   | #include "stubs.h"
50   | 
51   | #include  <sys/time.h> /* in Solaris, or time.h in BSD, 
52   | 			    wrrrr... the fun begins... */
53   | 
54   | void print_hello_banner(Query_environ *qe) { 
55   |   SK_cd_puts(&(qe->condat), CVS_NAME);
56   |   SK_cd_puts(&(qe->condat), "% Rights restricted by copyright. \n% See http://www.ripe.net/ripencc/pub-services/db/copyright.html\n");
57   | 
58   | #if 0
59   |   /* Send the environment aswell. */
60   |   SK_cd_puts(&(qe->condat), "% Environment={");
61   |   str1 = QC_environ_to_string(*qe);
62   |   SK_cd_puts(&(qe->condat), str1);
63   |   wr_free(str1);
64   |   SK_cd_puts(&(qe->condat), "}\n");
65   | #endif
66   | 
67   |   SK_cd_puts(&(qe->condat), "\n");
68   | }
69   | 
70   | /* PW_interact() */
71   | /*++++++++++++++++++++++++++++++++++++++
72   |   Interact with the client.
73   | 
74   |   int sock Socket that client is connected to.
75   | 
76   |   More:
77   |   +html+ <PRE>
78   |   Authors:
79   |         ottrey
80   | 
81   |   +html+ </PRE><DL COMPACT>
82   |   +html+ <DT>Online References:
83   |   +html+ <DD><UL>
84   |   +html+ </UL></DL>
85   | 
86   |   ++++++++++++++++++++++++++++++++++++++*/
87   | void PW_interact(int sock) {
88   |   char input[MAX_INPUT_SIZE];
89   |   int read_result;
90   |   char *hostaddress=NULL;
91   |   acl_st acl_rip,   acl_eip;
92   |   acc_st acc_credit, copy_credit;
93   |   int permanent_ban=0;  
94   |   Query_environ *qe=NULL;
95   |   Query_instructions *qis=NULL;
96   |   Query_command *qc=NULL;
97   |   GList *qitem;
98   |   int new_connection=1;
99   |   int acc_deny=0;
100  |   struct timeval begintime, endtime;
101  |   
102  |   /* Get the IP of the client */
103  |   hostaddress = SK_getpeername(sock);	  
104  |   ER_dbg_va(FAC_PW, 1, "connection from %s", hostaddress);
105  |   
106  |   /* Initialize the query environment. */
107  |   qe = QC_environ_new(hostaddress, sock);
108  |   
109  |   /* init to zeros */
110  |   memset( &(qe->condat), 0, sizeof(sk_conn_st));
111  | 
112  |   /* set the connection data: both rIP and eIP to real IP */
113  |   qe->condat.sock = sock;
114  |   qe->condat.ip = hostaddress;
115  |   SK_getpeerip(sock, &(qe->condat.rIP));
116  |   qe->condat.eIP = qe->condat.rIP;
117  | 
118  |   /* see if we should be talking at all */
119  |   /* check the acl using the realIP, get a copy applicable to this IP */
120  |   AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
121  |   if( acl_rip.deny ) {
122  |     permanent_ban=1;
123  |   }
124  |   
125  |   /* XXX log new connection here ?*/
126  |   
127  |   do {
128  |     /* Read input */
129  |     read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
130  | 
131  | 
132  |     gettimeofday(&begintime, NULL);
133  |     
134  |     /* read_result < 0 is an error and connection should be closed */
135  |     if (read_result < 0 ) {
136  |       /*  XXX log the fact, rtc was set */
137  |       /* EMPTY */
138  |     }
139  |     
140  |     qc = QC_create(input, qe);
141  | 
142  |     /* ADDRESS PASSING: check if -V option has passed IP in it */
143  |     if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
144  |       if(acl_rip.trustpass) {     
145  | 	acc_st pass_acc;
146  | 
147  | 	/* accounting */
148  | 	memset(&pass_acc, 0, sizeof(acc_st));
149  | 	pass_acc.addrpasses=1;
150  | 	AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
151  | 
152  | 	/* set eIP to this IP */
153  | 	qe->condat.eIP = qe->pIP;                 
154  |       }
155  |       else {
156  | 	/* XXX shall we deny such user ? Now we can... */
157  | 	ER_inf_va(FAC_PW, ASP_PWI_PASSUN, 
158  | 		  "unauthorised address passing by %s", hostaddress);
159  |       }
160  |     }
161  |     
162  |     
163  |     /* start setting counters in the connection acc from here on 
164  |        decrement the credit counter (needed to prevent QI_execute from
165  |        returning too many results */
166  |     
167  |     /* check ACL. Get the proper acl record. Calculate credit */
168  |     AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
169  |     /* save the original credit, later check how much was used */
170  |     copy_credit = acc_credit;
171  | 
172  |     if( acl_eip.deny ) {
173  |       permanent_ban = 1;
174  |     }
175  |     
176  |     if( qe->condat.rtc == 0 ) {
177  |       print_hello_banner(qe);
178  | 
179  |       if( permanent_ban ) {
180  |         SK_cd_puts(&(qe->condat), 
181  | "% Sorry, access from your host has been permanently denied\n"
182  | "% because of a repeated abusive behaviour.\n"
183  | "% Please contact <ripe-dbm@ripe.net> for unblocking\n");
184  | 
185  | 	ER_inf_va(FAC_PW, ASP_PWI_DENTRY,
186  | 		  "connection from host %s DENIED", hostaddress);
187  | 	
188  |       }
189  |       else {
190  | 	switch( qc->query_type ) {
191  | 	case QC_ERROR:
192  | 	  SK_cd_puts(&(qe->condat), USAGE);
193  | 	  break;
194  | 	case QC_NOKEY:
195  | 	  /* some operational stuff, like -k */
196  | 	  break;
197  |         case QC_EMPTY:
198  |         
199  |           /* The user didn't specify a key, so
200  |              - print moron banner
201  |              - force disconnection of the user. */
202  |           SK_cd_puts(&(qe->condat), "% No search key specified\n");
203  |           qe->condat.rtc = SK_NOTEXT;
204  |           break;
205  |         case QC_HELP:
206  |           SK_cd_puts(&(qe->condat), "% Nothing can help you anymore...:-)\n");
207  |           break;
208  |         case QC_TEMPLATE:
209  |           if (qc->q >= 0) {
210  |             SK_cd_puts(&(qe->condat), DF_get_server_query(qc->q)); 
211  |           }
212  |           if (qc->t >= 0) {
213  |             SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t)); 
214  |           }
215  |           if (qc->v >= 0) {
216  |             SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v)); 
217  |           }
218  |           break;
219  | 
220  | 	case QC_FILTERED:
221  | 	  SK_cd_puts(&(qe->condat), "% Note: this output has been filtered.\n% Only primary keys will be visible.\n% Contact information will not be shown\n\n");
222  | 	  
223  | 	  /* FALLTROUGH */
224  |         case QC_REAL:
225  |           qis = QI_new(qc,qe);
226  | 
227  | 	  
228  | 	  /* stop as soon as further action considered meaningless */
229  |           for( qitem = g_list_first(qe->sources_list);
230  |                qitem != NULL && qe->condat.rtc == 0;
231  |                qitem = g_list_next(qitem)) {
232  |             
233  |             /* QI will decrement the credit counters */
234  |             QI_execute(qitem->data, qis, qe, &acc_credit, &acl_eip );
235  |             
236  |           }
237  |           QI_free(qis);
238  | 	  copy_credit.queries ++;
239  | 
240  | 	  if( acc_credit.denials != 0 ) {
241  | 	    SK_cd_puts(&(qe->condat),
242  |  "% You have reached the limit of returned contact information objects.\n"
243  |  "% This connection will be terminated now.\n"
244  |  "% This is a mechanism to prevent abusive use of contact data in the RIPE Database.\n"
245  |  "% You will not be allowed to query for more CONTACT information for a while.\n"
246  |  "% Continued attempts to return excessive amounts of contact\n"
247  |  "% information will result in permanent denial of service.\n"
248  |  "% Please do not try to use CONTACT information information in the\n"
249  |  "% RIPE Database for non-operational purposes.\n"
250  |  "% Refer to http://www.ripe.net/db/dbcopyright.html for more information.\n"
251  | 		       );
252  | 	  }
253  | 
254  |           break;
255  |         default: die;
256  |         }
257  | 	/* calc. the credit used, result  into copy_credit */
258  | 	AC_acc_addup(&copy_credit, &acc_credit, ACC_MINUS);
259  | 	
260  | 	{
261  | 	  char *qrystat = AC_credit_to_string(&copy_credit);
262  | 	  float elapsed;	  
263  | 	  char *qrytypestr =
264  | 	    qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
265  | 
266  | 	  gettimeofday(&endtime, NULL);
267  | 
268  | 	  elapsed = ( endtime.tv_sec - begintime.tv_sec ) +
269  | 	    1e-6 * ( endtime.tv_usec - begintime.tv_usec ) ;
270  | 
271  | 	  /* log the connection/query/#results/time/denial to file */ 
272  | 	  ER_inf_va(FAC_PW, ASP_PWI_QRYLOG,
273  | 		    "<%s> %s %.2fs [%s] --  %s",
274  | 		    qrystat, qrytypestr,
275  | 		    elapsed, hostaddress, input
276  | 		    );
277  | 	  wr_free(qrystat);
278  | 	}
279  | 	
280  |       }/* if denied ... else */
281  |       
282  |       QC_free(qc);      
283  |       
284  |       if( new_connection ) {
285  | 	copy_credit.connections = 1;
286  | 	new_connection = 0;
287  |       }      
288  |       
289  |       if( copy_credit.denials != 0 ) {
290  | 	acc_deny = 1;
291  |       }
292  |       
293  |       /* Commit the credit. This will deny if bonus limit hit */ 
294  |       AC_commit(&(qe->condat.eIP), &copy_credit, &acl_eip); 
295  | 
296  |     } /* if still considered connected */
297  | 
298  |   } /* do */
299  |   while( qe->k && qe->condat.rtc == 0 && acc_deny == 0
300  | 	 && CO_get_whois_suspended() == 0);
301  | 
302  |   /* Free the hostaddress */
303  |   wr_free(hostaddress);
304  | 
305  |   SK_cd_close(&(qe->condat));
306  |   
307  |   /* Free the query_environ */
308  |   QC_environ_free(qe);
309  | 
310  | } /* PW_interact() */