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