1 | /***************************************
2 | $Revision: 1.25 $
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 | er_ret_t err;
102 |
103 | /* Get the IP of the client */
104 | hostaddress = SK_getpeername(sock);
105 | ER_dbg_va(FAC_PW, 1, "connection from %s", hostaddress);
106 |
107 | /* Initialize the query environment. */
108 | qe = QC_environ_new(hostaddress, sock);
109 |
110 | /* init to zeros */
111 | memset( &(qe->condat), 0, sizeof(sk_conn_st));
112 |
113 | /* set the connection data: both rIP and eIP to real IP */
114 | qe->condat.sock = sock;
115 | qe->condat.ip = hostaddress;
116 | SK_getpeerip(sock, &(qe->condat.rIP));
117 | qe->condat.eIP = qe->condat.rIP;
118 |
119 | /* see if we should be talking at all */
120 | /* check the acl using the realIP, get a copy applicable to this IP */
121 | AC_check_acl( &(qe->condat.rIP), NULL, &acl_rip);
122 | if( acl_rip.deny ) {
123 | permanent_ban=1;
124 | }
125 |
126 | /* XXX log new connection here ?*/
127 |
128 | do {
129 | /* Read input */
130 | read_result = SK_cd_gets(&(qe->condat), input, MAX_INPUT_SIZE);
131 |
132 |
133 | gettimeofday(&begintime, NULL);
134 |
135 | /* read_result < 0 is an error and connection should be closed */
136 | if (read_result < 0 ) {
137 | /* XXX log the fact, rtc was set */
138 | /* EMPTY */
139 | }
140 |
141 | qc = QC_create(input, qe);
142 |
143 | /* ADDRESS PASSING: check if -V option has passed IP in it */
144 | if( ! STRUCT_EQUAL(qe->pIP,IP_ADDR_UNSPEC)) {
145 | if(acl_rip.trustpass) {
146 | acc_st pass_acc;
147 |
148 | /* accounting */
149 | memset(&pass_acc, 0, sizeof(acc_st));
150 | pass_acc.addrpasses=1;
151 | AC_commit( &qe->condat.rIP, &pass_acc, &acl_rip);
152 |
153 | /* set eIP to this IP */
154 | qe->condat.eIP = qe->pIP;
155 | }
156 | else {
157 | /* XXX shall we deny such user ? Now we can... */
158 | ER_inf_va(FAC_PW, ASP_PWI_PASSUN,
159 | "unauthorised address passing by %s", hostaddress);
160 | }
161 | }
162 |
163 |
164 | /* start setting counters in the connection acc from here on
165 | decrement the credit counter (needed to prevent QI_execute from
166 | returning too many results */
167 |
168 | /* check ACL. Get the proper acl record. Calculate credit */
169 | AC_check_acl( &(qe->condat.eIP), &acc_credit, &acl_eip);
170 | /* save the original credit, later check how much was used */
171 | copy_credit = acc_credit;
172 |
173 | if( acl_eip.deny ) {
174 | permanent_ban = 1;
175 | }
176 |
177 | if( qe->condat.rtc == 0 ) {
178 | print_hello_banner(qe);
179 |
180 | if( permanent_ban ) {
181 | SK_cd_puts(&(qe->condat),
182 | "% Sorry, access from your host has been permanently denied\n"
183 | "% because of a repeated abusive behaviour.\n"
184 | "% Please contact <ripe-dbm@ripe.net> for unblocking\n");
185 |
186 | ER_inf_va(FAC_PW, ASP_PWI_DENTRY,
187 | "connection from host %s DENIED", hostaddress);
188 |
189 | }
190 | else {
191 | switch( qc->query_type ) {
192 | case QC_ERROR:
193 | SK_cd_puts(&(qe->condat), USAGE);
194 | break;
195 | case QC_NOKEY:
196 | /* some operational stuff, like -k */
197 | break;
198 | case QC_EMPTY:
199 |
200 | /* The user didn't specify a key, so
201 | - print moron banner
202 | - force disconnection of the user. */
203 | SK_cd_puts(&(qe->condat), "% No search key specified\n");
204 | qe->condat.rtc = SK_NOTEXT;
205 | break;
206 | case QC_HELP:
207 | SK_cd_puts(&(qe->condat), "% Nothing can help you anymore...:-)\n");
208 | break;
209 | case QC_TEMPLATE:
210 | if (qc->q >= 0) {
211 | SK_cd_puts(&(qe->condat), DF_get_server_query(qc->q));
212 | }
213 | if (qc->t >= 0) {
214 | SK_cd_puts(&(qe->condat), DF_get_class_template(qc->t));
215 | }
216 | if (qc->v >= 0) {
217 | SK_cd_puts(&(qe->condat), DF_get_class_template_v(qc->v));
218 | }
219 | break;
220 |
221 | case QC_FILTERED:
222 | 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");
223 |
224 | /* FALLTROUGH */
225 | case QC_REAL:
226 | qis = QI_new(qc,qe);
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 | err = QI_execute(qitem->data, qis, qe, &acc_credit, &acl_eip );
235 |
236 | if( !NOERR(err) ) {
237 | if( err == QI_CANTDB ) {
238 | SK_cd_puts(&(qe->condat), "% WARNING: Failed to make connection to ");
239 | SK_cd_puts(&(qe->condat), (char *)qitem->data);
240 | SK_cd_puts(&(qe->condat), " database.\n\n");
241 | }
242 |
243 | break; /* quit the loop after any error */
244 | }/* if */
245 |
246 | }/* for */
247 |
248 | /* end-of-result -> one extra line */
249 | SK_cd_puts(&(qe->condat), "\n");
250 |
251 | QI_free(qis);
252 | copy_credit.queries ++;
253 |
254 | if( acc_credit.denials != 0 ) {
255 | SK_cd_puts(&(qe->condat),
256 | "% You have reached the limit of returned contact information objects.\n"
257 | "% This connection will be terminated now.\n"
258 | "% This is a mechanism to prevent abusive use of contact data in the RIPE Database.\n"
259 | "% You will not be allowed to query for more CONTACT information for a while.\n"
260 | "% Continued attempts to return excessive amounts of contact\n"
261 | "% information will result in permanent denial of service.\n"
262 | "% Please do not try to use CONTACT information information in the\n"
263 | "% RIPE Database for non-operational purposes.\n"
264 | "% Refer to http://www.ripe.net/db/dbcopyright.html for more information.\n"
265 | );
266 | }
267 |
268 | break;
269 | default: die;
270 | }
271 | /* calc. the credit used, result into copy_credit */
272 | AC_acc_addup(©_credit, &acc_credit, ACC_MINUS);
273 |
274 | {
275 | char *qrystat = AC_credit_to_string(©_credit);
276 | float elapsed;
277 | char *qrytypestr =
278 | qc->query_type == QC_REAL ? "" : QC_get_qrytype(qc->query_type);
279 |
280 | gettimeofday(&endtime, NULL);
281 |
282 | elapsed = ( endtime.tv_sec - begintime.tv_sec ) +
283 | 1e-6 * ( endtime.tv_usec - begintime.tv_usec ) ;
284 |
285 | /* log the connection/query/#results/time/denial to file */
286 | ER_inf_va(FAC_PW, ASP_PWI_QRYLOG,
287 | "<%s> %s %.2fs [%s] -- %s",
288 | qrystat, qrytypestr,
289 | elapsed, hostaddress, input
290 | );
291 | wr_free(qrystat);
292 | }
293 |
294 | }/* if denied ... else */
295 |
296 | QC_free(qc);
297 |
298 | if( new_connection ) {
299 | copy_credit.connections = 1;
300 | new_connection = 0;
301 | }
302 |
303 | if( copy_credit.denials != 0 ) {
304 | acc_deny = 1;
305 | }
306 |
307 | /* Commit the credit. This will deny if bonus limit hit */
308 | AC_commit(&(qe->condat.eIP), ©_credit, &acl_eip);
309 |
310 | } /* if still considered connected */
311 |
312 | } /* do */
313 | while( qe->k && qe->condat.rtc == 0 && acc_deny == 0
314 | && CO_get_whois_suspended() == 0);
315 |
316 | /* Free the hostaddress */
317 | wr_free(hostaddress);
318 |
319 | SK_cd_close(&(qe->condat));
320 |
321 | /* Free the query_environ */
322 | QC_environ_free(qe);
323 |
324 | } /* PW_interact() */