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