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