modules/pw/protocol_whois.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- print_hello_banner
- strchop
- pw_log_query
- PW_process_qc
- PW_interact
1 /***************************************
2 $Revision: 1.37 $
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) {
/* [<][>][^][v][top][bottom][index][help] */
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
79 void
80 strchop(char *input)
/* [<][>][^][v][top][bottom][index][help] */
81 {
82 char *co = strchr(input, '\0');
83 while( co != input && (isspace(*co) || *co == '\0') ) {
84 *co = '\0';
85 co--;
86 }
87 }
88
89
90 static
91 void pw_log_query( Query_environ *qe,
/* [<][>][^][v][top][bottom][index][help] */
92 Query_command *qc,
93 acc_st *copy_credit,
94 ut_timer_t begintime,
95 ut_timer_t endtime,
96 char *hostaddress,
97 char *input)
98 {
99 char *qrystat = AC_credit_to_string(copy_credit);
100 float elapsed;
101 char *qrytypestr =
102 qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
103
104
105 elapsed = UT_timediff( &begintime, &endtime);
106
107 /* log the connection/query/#results/time/denial to file */
108 ER_inf_va(FAC_PW, ASP_PWI_QRYLOG,
109 "<%s> %s%s %.2fs [%s] -- %s",
110 qrystat,
111 qe->condat.rtc ? "INT " : "",
112 qrytypestr,
113 elapsed, hostaddress, input
114 );
115 wr_free(qrystat);
116 }
117
118
119
120
121 er_ret_t PW_process_qc(Query_environ *qe,
/* [<][>][^][v][top][bottom][index][help] */
122 Query_command *qc,
123 acc_st *acc_credit,
124 acl_st *acl_eip )
125 {
126 GList *qitem;
127 Query_instructions *qis=NULL;
128 er_ret_t err;
129
130 switch( qc->query_type ) {
131 case QC_SYNERR:
132 SK_cd_puts(&(qe->condat), USAGE);
133 /* FALLTHROUGH */
134 case QC_PARERR:
135 /* parameter error. relevant error message is already printed */
136
137 /* force disconnection on error */
138 qe->k = 0;
139 break;
140 case QC_NOKEY:
141 /* no key (this is OK for some operational stuff, like -k) */
142 break;
143 case QC_EMPTY:
144
145 /* The user didn't specify a key, so
146 - print moron banner
147 - force disconnection of the user. */
148 SK_cd_puts(&(qe->condat), "% No search key specified\n");
149 qe->condat.rtc = SK_NOTEXT;
150 break;
151 case QC_HELP:
152 SK_cd_puts(&(qe->condat), "% Nothing can help you anymore...:-)\n");
153 break;
154 case QC_TEMPLATE:
155 switch(qc->q) {
156 case QC_Q_SOURCES:
157 /* print source & mirroring info */
158 {
159 GString *srcs = PM_get_nrtm_sources( & qe->condat.rIP, NULL);
160 SK_cd_puts(&(qe->condat), srcs->str);
161 g_string_free (srcs, TRUE);
162 }
163 break;
164 case QC_Q_VERSION:
165 SK_cd_puts(&(qe->condat), "% RIP version " VERSION "\n");
166 break;
167 default:
168 /* EMPTY */;
169 } /* -q */
170
171 if (qc->t >= 0) {
172 SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t));
173 }
174 if (qc->v >= 0) {
175 SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v));
176 }
177 break;
178
179 case QC_FILTERED:
180 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");
181
182 /* FALLTROUGH */
183 case QC_REAL:
184 qis = QI_new(qc,qe);
185
186 /* stop as soon as further action considered meaningless */
187 for( qitem = g_list_first(qe->sources_list);
188 qitem != NULL && qe->condat.rtc == 0;
189 qitem = g_list_next(qitem)) {
190
191 /* QI will decrement the credit counters */
192 err = QI_execute(qitem->data, qis, qe, acc_credit, acl_eip );
193
194 if( !NOERR(err) ) {
195 if( err == QI_CANTDB ) {
196 SK_cd_puts(&(qe->condat), "% WARNING: Failed to make connection to ");
197 SK_cd_puts(&(qe->condat), (char *)qitem->data);
198 SK_cd_puts(&(qe->condat), " database.\n\n");
199 }
200
201 break; /* quit the loop after any error */
202 }/* if */
203
204 }/* for every source */
205
206 QI_free(qis);
207
208 if( AC_credit_isdenied(acc_credit) ) {
209 SK_cd_puts(&(qe->condat),
210 "% You have reached the limit of returned contact information objects.\n"
211 "% This connection will be terminated now.\n"
212 "% This is a mechanism to prevent abusive use of contact data in the RIPE Database.\n"
213 "% You will not be allowed to query for more CONTACT information for a while.\n"
214 "% Continued attempts to return excessive amounts of contact\n"
215 "% information will result in permanent denial of service.\n"
216 "% Please do not try to use CONTACT information in the\n"
217 "% RIPE Database for non-operational purposes.\n"
218 "% Refer to http://www.ripe.net/db/dbcopyright.html for more information.\n"
219 );
220 }
221
222 break;
223 default: die;
224 }
225
226 return err;
227 }
228
229 /* PW_interact() */
230 /*++++++++++++++++++++++++++++++++++++++
231 Interact with the client.
232
233 int sock Socket that client is connected to.
234
235 More:
236 +html+ <PRE>
237 Authors:
238 ottrey (original CP/M version)
239 marek
240
241 +html+ </PRE><DL COMPACT>
242 +html+ <DT>Online References:
243 +html+ <DD><UL>
244 +html+ </UL></DL>
245
246 ++++++++++++++++++++++++++++++++++++++*/
247 void PW_interact(int sock) {
/* [<][>][^][v][top][bottom][index][help] */
248 char input[MAX_INPUT_SIZE];
249 int read_result;
250 char *hostaddress=NULL;
251 acl_st acl_rip, acl_eip;
252 acc_st acc_credit, copy_credit;
253 Query_environ *qe=NULL;
254 Query_command *qc=NULL;
255 ut_timer_t begintime, endtime;
256
257
258 /* Get the IP of the client */
259 hostaddress = SK_getpeername(sock);
260 ER_dbg_va(FAC_PW, 1, "connection from %s", hostaddress);
261
262 /* Initialize the query environment. */
263 qe = QC_environ_new(hostaddress, sock);
264
265 /* init to zeros */
266 memset( &(qe->condat), 0, sizeof(sk_conn_st));
267
268 /* set the connection data: both rIP and eIP to real IP */
269 qe->condat.sock = sock;
270 qe->condat.ip = hostaddress;
271 SK_getpeerip(sock, &(qe->condat.rIP));
272 qe->condat.eIP = qe->condat.rIP;
273
274 qe->condat.rd_timeout.tv_sec = 180; /* read timeout */
275
276 /* see if we should be talking at all */
277 /* check the acl using the realIP, get a copy applicable to this IP */
278 AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
279
280 do {
281 int unauth_pass=0;
282
283 TA_setactivity("waiting for query");
284 /* Read input */
285 read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
286 /* trash trailing whitespaces(including \n) */
287 strchop(input);
288
289 TA_setactivity(input);
290 TA_increment();
291
292 UT_timeget( &begintime );
293
294 qc = QC_create(input, qe);
295
296 print_hello_banner(qe);
297
298 /* ADDRESS PASSING: check if -V option has passed IP in it */
299 if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
300 if(acl_rip.trustpass) {
301 acc_st pass_acc;
302
303 /* accounting */
304 memset(&pass_acc, 0, sizeof(acc_st));
305 pass_acc.addrpasses=1;
306 AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
307
308 /* set eIP to this IP */
309 qe->condat.eIP = qe->pIP;
310 }
311 else {
312 /* XXX shall we deny such user ? Now we can... */
313 ER_inf_va(FAC_PW, ASP_PWI_PASSUN,
314 "unauthorised address passing by %s", hostaddress);
315 unauth_pass = 1; /* keep in mind ... */
316 }
317 } /* if an address was passed */
318
319 /* start setting counters in the connection acc from here on
320 decrement the credit counter (needed to prevent QI_execute from
321 returning too many results */
322
323 /* check ACL. Get the proper acl record. Calculate credit */
324 AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
325 /* save the original credit, later check how much was used */
326 copy_credit = acc_credit;
327
328 copy_credit.connections ++;
329
330 /* printing notices */
331 if( unauth_pass && ! acl_rip.deny ) {
332 SK_cd_puts(&(qe->condat), /* print only if not yet completely denied */
333 "% Sorry, you are not allowed to pass addresses on the query line.\n"
334 "% Please contact us for such permission. For the moment, continuing\n"
335 "% this will cause permanent denial of the access\n");
336 }
337 if( acl_eip.deny || acl_rip.deny ) {
338 SK_cd_puts(&(qe->condat),
339
340 "% Sorry, access from your host has been permanently denied\n"
341 "% because of a repeated abusive behaviour.\n"
342 "% Please contact <ripe-dbm@ripe.net> for unblocking\n");
343 }
344
345 if( acl_eip.deny || acl_rip.deny || unauth_pass ) {
346 copy_credit.denials ++;
347 }
348 else {
349 /************ ACTUAL PROCESSING IS HERE ***********/
350 PW_process_qc(qe, qc, &acc_credit, &acl_eip);
351
352 if( qc->query_type == QC_REAL ) {
353 copy_credit.queries ++;
354 }
355 }/* if denied ... else */
356
357 /* calc. the credit used, result into copy_credit
358 This step MUST NOT be forgotten. It must complement
359 the initial calculation of a credit, otherwise accounting
360 will go bgzzzzzt.
361 */
362 AC_acc_addup(©_credit, &acc_credit, ACC_MINUS);
363
364 /* now we can check how many results there were, etc. */
365
366 /* can say 'nothing found' only if:
367 - the query did not just cause denial
368 - was a 'real' query
369 - nothing was returned
370 */
371
372 if( ! AC_credit_isdenied(©_credit)
373 && (qc->query_type == QC_REAL || qc->query_type == QC_FILTERED)
374 && copy_credit.private_objects + copy_credit.public_objects
375 + copy_credit.referrals == 0 ) {
376 SK_cd_puts(&(qe->condat),
377 "% No entries found for the selected source(s).\n"
378 "%\n"
379 "% If you would like to search on arbitrary strings,\n"
380 "% please see the Database page on the RIPE NCC\n"
381 "% web-site at http://www.ripe.net/ripencc/pub-services/db/\n"
382 "% This will only work for RIPE data.\n"
383 "%\n"
384 "% Please note that the RIPE whoisd service temporarily\n"
385 "% mirrors only ARIN and APNIC databases.\n");
386 }
387
388 UT_timeget(&endtime);
389 /* query logging */
390 pw_log_query(qe, qc, ©_credit, begintime, endtime,
391 hostaddress, input);
392
393 /* Commit the credit. This will deny if bonus limit hit
394 and clear the copy */
395 AC_commit(&(qe->condat.eIP), ©_credit, &acl_eip);
396
397 /* end-of-result -> one extra line */
398 SK_cd_puts(&(qe->condat), "\n");
399
400 QC_free(qc);
401 } /* do */
402 while( qe->k && qe->condat.rtc == 0
403 && AC_credit_isdenied( ©_credit ) == 0
404 && CO_get_whois_suspended() == 0);
405
406 /* Free the hostaddress */
407 wr_free(hostaddress);
408
409 SK_cd_close(&(qe->condat));
410
411 /* Free the query_environ */
412 QC_environ_free(qe);
413
414 } /* PW_interact() */