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