modules/pw/protocol_whois.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- display_file
- pw_log_query
- PW_process_qc
- PW_interact
1 /***************************************
2 $Revision: 1.50 $
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 - framework and draft implementation
11 marek@ripe.net - rewritten and extended.
12 OSs Tested : Solaris 2.6
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_macros.h"
51 #include "ca_srcAttribs.h"
52
53 #include "protocol_mirror.h"
54
55 #include "ta.h"
56 #include "timediff.h"
57
58 #ifndef VERSION
59 #define VERSION "3"
60 #endif
61
62 /*++++++++++++++++++++++++++++++++++++++
63
64 void
65 display_file opens a file and displays its contents to the
66 connection described in conn. structure.
67
68
69 sk_conn_st *condat pointer to connection structure
70
71 char *filename file name
72
73 ++++++++++++++++++++++++++++++++++++++*/
74 static void
75 display_file(sk_conn_st *condat, char *filename)
/* [<][>][^][v][top][bottom][index][help] */
76 {
77 FILE *fp;
78 #define READBUFSIZE 148
79 char buffer[READBUFSIZE+1];
80 int bytes;
81
82 if( (fp=fopen( filename, "r" )) == NULL ) {
83 ER_perror( FAC_PW, PW_CNTOPN, "%s : %s (%d)",
84 filename, strerror(errno), errno);
85 }
86 else {
87 while( (bytes=fread(buffer, 1, READBUFSIZE, fp)) > 0 ) {
88 buffer[bytes] = 0;
89 SK_cd_puts(condat, buffer);
90 }
91 fclose(fp);
92 }
93 }/* display_file */
94
95
96 /*++++++++++++++++++++++++++++++++++++++
97
98 static void
99 pw_log_query logs the query to a file after it has finished.
100 Takes many parameters to have access to as much
101 information as possible, including the original
102 query, accounting, response time, status of the
103 client connection, etc.
104
105
106 Query_environ *qe query environment
107
108 Query_command *qc query command structure
109
110 acc_st *copy_credit numbers of objects returned / referrals made
111 during this query
112 (calculated as original credit assigned before
113 the query minus what's left after the query).
114
115 ut_timer_t begintime time the processing began
116
117 ut_timer_t endtime time the processing finished
118
119 char *hostaddress text address of the real IP
120
121 char *input original query (trailing whitespaces chopped off)
122
123 ++++++++++++++++++++++++++++++++++++++*/
124 static
125 void pw_log_query( Query_environ *qe,
/* [<][>][^][v][top][bottom][index][help] */
126 Query_command *qc,
127 acc_st *copy_credit,
128 ut_timer_t begintime,
129 ut_timer_t endtime,
130 char *hostaddress,
131 char *input)
132 {
133 char *qrystat = AC_credit_to_string(copy_credit);
134 float elapsed;
135 char *qrytypestr =
136 qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
137
138
139 elapsed = UT_timediff( &begintime, &endtime);
140
141 /* log the connection/query/#results/time/denial to file */
142 ER_inf_va(FAC_PW, ASP_PW_I_QRYLOG,
143 "<%s> %s%s %.2fs [%s] -- %s",
144 qrystat,
145 qe->condat.rtc ? "INT " : "",
146 qrytypestr,
147 elapsed, hostaddress, input
148 );
149 wr_free(qrystat);
150 } /* pw_log_query */
151
152
153
154
155 /*++++++++++++++++++++++++++++++++++++++
156
157 void
158 PW_process_qc processes the query commands determined in QC,
159 This is where all the real action of the query
160 part is invoked.
161
162 Query_environ *qe query environment
163
164 Query_command *qc query command structure
165
166 acc_st *acc_credit credit assigned to this IP
167
168 acl_st *acl_eip current acl record applicable to this IP
169
170 ++++++++++++++++++++++++++++++++++++++*/
171 void PW_process_qc(Query_environ *qe,
/* [<][>][^][v][top][bottom][index][help] */
172 Query_command *qc,
173 acc_st *acc_credit,
174 acl_st *acl_eip )
175 {
176 GList *qitem;
177 Query_instructions *qis=NULL;
178 er_ret_t err;
179
180 switch( qc->query_type ) {
181 case QC_SYNERR:
182 SK_cd_puts(&(qe->condat), USAGE);
183 /* FALLTHROUGH */
184 case QC_PARERR:
185 /* parameter error. relevant error message is already printed */
186
187 /* force disconnection on error */
188 qe->k = 0;
189 break;
190 case QC_NOKEY:
191 /* no key (this is OK for some operational stuff, like -k) */
192 break;
193 case QC_EMPTY:
194 /* The user didn't specify a key, so
195 - print moron banner
196 - force disconnection of the user. */
197 {
198 char *rep = ca_get_pw_err_nokey ;
199 SK_cd_puts(&(qe->condat), rep);
200 wr_free(rep);
201 }
202 qe->condat.rtc = SK_NOTEXT;
203 break;
204 case QC_HELP:
205 {
206 char *rep = ca_get_pw_help_file ;
207 display_file( &(qe->condat), rep);
208 wr_free(rep);
209 }
210 break;
211 case QC_TEMPLATE:
212 switch(qc->q) {
213 case QC_Q_SOURCES:
214 /* print source & mirroring info */
215 {
216 GString *srcs = PM_get_nrtm_sources( & qe->condat.rIP, NULL);
217 SK_cd_puts(&(qe->condat), srcs->str);
218 g_string_free (srcs, TRUE);
219 }
220 break;
221 case QC_Q_VERSION:
222 SK_cd_puts(&(qe->condat), "% RIP version " VERSION "\n\n");
223 break;
224 default:
225 /* EMPTY */;
226 } /* -q */
227
228 if (qc->t >= 0) {
229 SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t));
230 }
231 if (qc->v >= 0) {
232 SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v));
233 }
234 break;
235
236 case QC_FILTERED:
237 {
238 char *rep = ca_get_pw_k_filter ;
239 SK_cd_puts(&(qe->condat), rep);
240 wr_free(rep);
241 }
242 /* FALLTROUGH */
243 case QC_REAL:
244 {
245 char *rep = ca_get_pw_resp_header;
246 SK_cd_puts(&(qe->condat), rep);
247 wr_free(rep);
248 SK_cd_puts(&(qe->condat), "\n");
249 }
250
251 #if 1
252
253 qis = QI_new(qc,qe);
254
255 /* go through all sources,
256 stop if connection broken - further action is meaningless */
257 for( qitem = g_list_first(qe->sources_list);
258 qitem != NULL && qe->condat.rtc == 0;
259 qitem = g_list_next(qitem)) {
260
261
262 /* QI will decrement the credit counters */
263 err = QI_execute(qitem->data, qis, qe, acc_credit, acl_eip );
264 if( !NOERR(err) ) {
265 if( err == QI_CANTDB ) {
266 SK_cd_puts(&(qe->condat), "% WARNING: Failed to make connection to ");
267 SK_cd_puts(&(qe->condat), (char *)qitem->data);
268 SK_cd_puts(&(qe->condat), " database.\n\n");
269 }
270 break; /* quit the loop after any error */
271 }/* if error*/
272
273 }/* for every source */
274
275 QI_free(qis);
276
277 #else
278 /* test mode: do not run a query, make up some accounting values */
279 {
280 int i, m = random() & 0x0f;
281 for( i=0 ; i<m ; i++ ) {
282 AC_count_object( acc_credit, acl_eip, random() & 0x01 );
283 }
284 }
285
286 #endif
287
288 if( AC_credit_isdenied(acc_credit) ) {
289 /* host reached the limit of returned contact information */
290 char *rep = ca_get_pw_limit_reached ;
291 SK_cd_puts(&(qe->condat), rep);
292 wr_free(rep);
293 }
294
295 break;
296 default: die;
297 }
298 } /* PW_process_qc */
299
300
301
302
303 /*++++++++++++++++++++++++++++++++++++++
304
305 void
306 PW_interact Main loop for interaction with a single client.
307 The function sets up the accounting for the client,
308 invokes parsing, execution, logging and accounting
309 of the query.
310
311 int sock Socket that client is connected to.
312
313 ++++++++++++++++++++++++++++++++++++++*/
314 void PW_interact(int sock) {
/* [<][>][^][v][top][bottom][index][help] */
315 char input[MAX_INPUT_SIZE];
316 int read_result;
317 char *hostaddress=NULL;
318 acl_st acl_rip, acl_eip;
319 acc_st acc_credit, copy_credit;
320 Query_environ *qe=NULL;
321 Query_command *qc=NULL;
322 ut_timer_t begintime, endtime;
323
324 /* Get the IP of the client */
325 hostaddress = SK_getpeername(sock);
326 ER_dbg_va(FAC_PW, ASP_PW_CONN, "connection from %s", hostaddress);
327
328 /* Initialize the query environment. */
329 qe = QC_environ_new(hostaddress, sock);
330
331 /* init the connection structure, set timeout for reading the query */
332 SK_cd_make( &(qe->condat), sock, (unsigned) ca_get_keepopen);
333
334 TA_setcondat(&(qe->condat));
335
336 /* see if we should be talking at all */
337 /* check the acl using the realIP, get a copy applicable to this IP */
338 AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
339
340 do {
341 int unauth_pass=0;
342
343 TA_setactivity("waiting for query");
344 /* Read input */
345 read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
346 /* trash trailing whitespaces(including \n) */
347 ut_string_chop(input);
348
349 TA_setactivity(input);
350 TA_increment();
351
352 UT_timeget( &begintime );
353
354 qc = QC_create(input, qe);
355
356 {
357 /* print the greeting text before the query */
358 char *rep = ca_get_pw_banner ;
359 SK_cd_puts(&(qe->condat), rep);
360 wr_free(rep);
361 SK_cd_puts(&(qe->condat), "\n");
362 }
363
364 /* ADDRESS PASSING: check if -V option has passed IP in it */
365 if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
366 if(acl_rip.trustpass) {
367 acc_st pass_acc;
368
369 /* accounting */
370 memset(&pass_acc, 0, sizeof(acc_st));
371 pass_acc.addrpasses=1;
372 AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
373
374 /* set eIP to this IP */
375 qe->condat.eIP = qe->pIP;
376 }
377 else {
378 /* XXX shall we deny such user ? Now we can... */
379 ER_inf_va(FAC_PW, ASP_PW_I_PASSUN,
380 "unauthorised address passing by %s", hostaddress);
381 unauth_pass = 1; /* keep in mind ... */
382 }
383 } /* if an address was passed */
384
385 /* start setting counters in the connection acc from here on
386 decrement the credit counter (needed to prevent QI_execute from
387 returning too many results */
388
389 /* check ACL. Get the proper acl record. Calculate credit */
390 AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
391 /* save the original credit, later check how much was used */
392 copy_credit = acc_credit;
393
394 copy_credit.connections ++;
395
396 /* printing notices */
397 if( unauth_pass && ! acl_rip.deny ) {
398 /* host not authorised to pass addresses with -V */
399 char *rep = ca_get_pw_acl_addrpass ;
400 SK_cd_puts(&(qe->condat), rep);
401 wr_free(rep);
402 }
403 if( acl_eip.deny || acl_rip.deny ) {
404 /* access from host has been permanently denied */
405 char *rep = ca_get_pw_acl_permdeny ;
406 SK_cd_puts(&(qe->condat), rep);
407 wr_free(rep);
408 }
409
410 if( acl_eip.deny || acl_rip.deny || unauth_pass ) {
411 copy_credit.denials ++;
412 }
413 else {
414 /************ ACTUAL PROCESSING IS HERE ***********/
415 PW_process_qc(qe, qc, &acc_credit, &acl_eip);
416
417 if( qc->query_type == QC_REAL ) {
418 copy_credit.queries ++;
419 }
420 }/* if denied ... else */
421
422 /* calc. the credit used, result into copy_credit
423 This step MUST NOT be forgotten. It must complement
424 the initial calculation of a credit, otherwise accounting
425 will go bgzzzzzt.
426 */
427 AC_acc_addup(©_credit, &acc_credit, ACC_MINUS);
428
429 /* now we can check how many results there were, etc. */
430
431 /* can say 'nothing found' only if:
432 - the query did not just cause denial
433 - was a 'real' query
434 - nothing was returned
435 */
436
437 if( ! AC_credit_isdenied(©_credit)
438 && (qc->query_type == QC_REAL || qc->query_type == QC_FILTERED)
439 && copy_credit.private_objects + copy_credit.public_objects
440 + copy_credit.referrals == 0 ) {
441
442 /* now: if the rtc flag is zero, the query ran to completion */
443 if( qe->condat.rtc == 0 ) {
444 char *rep = ca_get_pw_notfound ;
445 SK_cd_puts(&(qe->condat), rep);
446 wr_free(rep);
447 }
448 else {
449 /* something happened. Hope for working socket and display message
450 (won't hurt even if socket not operable)
451 */
452 char *rep = ca_get_pw_connclosed ;
453 SK_cd_puts(&(qe->condat), rep);
454 wr_free(rep);
455 }
456 }
457
458
459 UT_timeget(&endtime);
460 /* query logging */
461 pw_log_query(qe, qc, ©_credit, begintime, endtime,
462 hostaddress, input);
463
464 /* Commit the credit. This will deny if bonus limit hit
465 and clear the copy */
466 AC_commit(&(qe->condat.eIP), ©_credit, &acl_eip);
467
468 /* end-of-result -> two empty lines */
469 SK_cd_puts(&(qe->condat), "\n\n");
470
471 QC_free(qc);
472 } /* do */
473 while( qe->k && qe->condat.rtc == 0
474 && AC_credit_isdenied( ©_credit ) == 0
475 && CO_get_whois_suspended() == 0);
476
477 /* Free the hostaddress */
478 wr_free(hostaddress);
479 /* Free the connection struct's dynamic data */
480 SK_cd_free(&(qe->condat));
481 /* Free the query_environ */
482 QC_environ_free(qe);
483
484 } /* PW_interact() */