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(©_credit, &acc_credit, ACC_MINUS);
259 |
260 | {
261 | char *qrystat = AC_credit_to_string(©_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), ©_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() */