1 | /*************************************** 2 | 3 | Protocol mirror module (pw). 4 | 5 | Status: NOT REVUED, NOT TESTED 6 | 7 | ******************/ /****************** 8 | Filename : protocol_mirror.c 9 | Author : andrei 10 | OSs Tested : Solaris 11 | ******************/ /****************** 12 | Copyright (c) 2000 RIPE NCC 13 | 14 | All Rights Reserved 15 | 16 | Permission to use, copy, modify, and distribute this software and its 17 | documentation for any purpose and without fee is hereby granted, 18 | provided that the above copyright notice appear in all copies and that 19 | both that copyright notice and this permission notice appear in 20 | supporting documentation, and that the name of the author not be 21 | used in advertising or publicity pertaining to distribution of the 22 | software without specific, written prior permission. 23 | 24 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 25 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 26 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 27 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 28 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 29 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30 | ***************************************/ 31 | #include <stdio.h> 32 | #include <glib.h> 33 | 34 | #include "protocol_mirror.h" 35 | #include "mysql_driver.h" 36 | #include "constants.h" 37 | 38 | //#include "access_control.h" 39 | #include "sk.h" 40 | #include "stubs.h" 41 | #include "ud.h" 42 | #include "ta.h" 43 | 44 | #include "ca_configFns.h" 45 | #include "ca_dictSyms.h" 46 | #include "ca_macros.h" 47 | #include "ca_srcAttribs.h" 48 | 49 | #include "erroutines.h" 50 | 51 | #define MIN_ARG_LENGTH 6 52 | #define NRTM_DELIM "-:" 53 | /* 54 | * parses input and fills nrtm_q_t structure 55 | * 56 | * Returns: 57 | * -1 in case of garbage 58 | * 0 in case of valid -g 59 | * 1 in case of -q sources 60 | * 61 | */ 62 | static int parse_request(char *input, nrtm_q_t *nrtm_q) 63 | { 64 | char *ptr=input; 65 | char *token; 66 | char **tokens; 67 | char **tokens2; 68 | int res=0; 69 | 70 | // return(-1); 71 | 72 | if(strlen(input)<MIN_ARG_LENGTH) return(-1); 73 | g_strchug(input); 74 | res=strncmp(input, "-g", 2); 75 | if(res!=0) { 76 | /* may be this is -q source query */ 77 | res=strncmp(input, "-q", 2); 78 | if(res!=0)return(-1); 79 | ptr+=2; 80 | g_strchug(ptr); 81 | res=strncmp(ptr, "sources", 7); 82 | if(res!=0)return(-1); 83 | ptr+=7; 84 | g_strchug(ptr); 85 | token=ptr; 86 | if ((*token=='\0') || (*token=='\n'))nrtm_q->source=NULL; 87 | else { 88 | ptr=index(token, ' '); 89 | if (ptr) nrtm_q->source=g_strndup(token, (ptr-token)); 90 | else { 91 | ptr=index(token, 13); /* search for ctrl-M - telnet loves this */ 92 | if (ptr) nrtm_q->source=g_strndup(token, (ptr-token)); 93 | else { 94 | ptr=index(token, '\n'); 95 | if (ptr) nrtm_q->source=g_strndup(token, (ptr-token)); 96 | else 97 | nrtm_q->source=g_strdup(token); 98 | } 99 | } 100 | } 101 | return(1); 102 | } 103 | 104 | /* this is -q query */ 105 | ptr+=2; 106 | 107 | 108 | g_strchug(ptr); 109 | g_strdelimit(ptr, NRTM_DELIM, ':'); 110 | tokens=g_strsplit(ptr, ":", 4); 111 | if(tokens==NULL) return(-1); 112 | 113 | if(tokens[0]) { 114 | /* first token is source name */ 115 | nrtm_q->source=g_strdup(tokens[0]); 116 | if(tokens[1]) { 117 | /* second token is version number */ 118 | nrtm_q->version=atoi(tokens[1]); 119 | if(tokens[2]) { 120 | /* this is first serial */ 121 | nrtm_q->first=atol(tokens[2]); 122 | if (nrtm_q->first>0) { 123 | if(tokens[3]) { 124 | /* this is last serial */ 125 | nrtm_q->last=atol(tokens[3]); 126 | if (nrtm_q->last==0) 127 | if (strncasecmp(tokens[3], "LAST", 4)!=0) res=-1; 128 | } else res=-1; 129 | } else res=-1; 130 | } else res=-1; 131 | } else res=-1; 132 | } else res=-1; 133 | g_strfreev(tokens); 134 | 135 | return(res); 136 | } 137 | 138 | 139 | /* PM_interact() */ 140 | /*++++++++++++++++++++++++++++++++++++++ 141 | Interact with the client. 142 | 143 | int sock Socket that client is connected to. 144 | 145 | More: 146 | +html+ <PRE> 147 | Authors: 148 | ottrey 149 | andrei 150 | 151 | +html+ </PRE><DL COMPACT> 152 | +html+ <DT>Online References: 153 | +html+ <DD><UL> 154 | +html+ </UL></DL> 155 | 156 | ++++++++++++++++++++++++++++++++++++++*/ 157 | void PM_interact(int sock) { 158 | char input[MAX_INPUT_SIZE]; 159 | char buff[STR_L]; 160 | ca_dbSource_t *source_hdl; 161 | int read_result; 162 | int parse_result; 163 | ip_addr_t address; 164 | 165 | char *hostaddress=NULL; 166 | sk_conn_st condat; 167 | nrtm_q_t nrtm_q; 168 | long current_serial; 169 | long oldest_serial; 170 | 171 | char *object; 172 | int operation; 173 | 174 | 175 | char *db_host; 176 | int db_port; 177 | char *db_name; 178 | char *db_user; 179 | char *db_pswd; 180 | 181 | GString *gbuff; 182 | 183 | SQ_connection_t *sql_connection; 184 | 185 | /* make a record for thread accounting */ 186 | TA_add(sock, "nrtm_srv"); 187 | 188 | 189 | /* Get the IP of the client */ 190 | hostaddress = SK_getpeername(sock); 191 | 192 | /* initialise the connection structure */ 193 | memset( &condat, 0, sizeof(sk_conn_st)); 194 | /* initialise the nrtm structure */ 195 | memset( &nrtm_q, 0, sizeof(nrtm_q_t)); 196 | /* set the connection data: both rIP and eIP to real IP */ 197 | condat.sock = sock; 198 | condat.ip = hostaddress; 199 | SK_getpeerip(sock, &(condat.rIP)); 200 | memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t)); 201 | 202 | 203 | /* Read input */ 204 | read_result = SK_cd_gets(&(condat), input, MAX_INPUT_SIZE); 205 | 206 | /* read_result < 0 is an error and connection should be closed */ 207 | if (read_result < 0 ) { 208 | /* log the fact, rtc was set */ 209 | } 210 | 211 | 212 | parse_result = parse_request(input, &nrtm_q); 213 | 214 | 215 | if (parse_result < 0 ) { 216 | ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Garbage received: %s", hostaddress, input); 217 | /* log the fact and exit */ 218 | /* Free the hostaddress */ 219 | sprintf(buff, "\n%%ERROR:1: Syntax error\n\n"); 220 | SK_cd_puts(&condat, buff); 221 | SK_cd_close(&(condat)); 222 | free(hostaddress); 223 | free(nrtm_q.source); 224 | return; 225 | } 226 | 227 | ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input: [%s]", hostaddress, input); 228 | 229 | if (parse_result == 1 ) { 230 | 231 | gbuff=PM_get_nrtm_sources(&(condat.rIP), nrtm_q.source); 232 | SK_cd_puts(&condat, gbuff->str); 233 | /* Free allocated memory */ 234 | g_string_free(gbuff, TRUE); 235 | free(hostaddress); 236 | free(nrtm_q.source); 237 | SK_cd_close(&(condat)); 238 | return; 239 | } 240 | 241 | ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input parsed: %s:%d:%ld-%ld", hostaddress, nrtm_q.source, nrtm_q.version, nrtm_q.first, nrtm_q.last); 242 | 243 | source_hdl = ca_get_SourceHandleByName(nrtm_q.source); 244 | if (source_hdl == NULL){ 245 | ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Unknown source %s", hostaddress, nrtm_q.source); 246 | sprintf(buff, "\n%%ERROR:4: Unknown source\n\n"); 247 | SK_cd_puts(&condat, buff); 248 | free(hostaddress); 249 | free(nrtm_q.source); 250 | SK_cd_close(&(condat)); 251 | return; 252 | } 253 | 254 | /* check if the client is authorized to mirror */ 255 | SK_getpeerip(sock, &address); 256 | if(!AA_can_mirror(&address, nrtm_q.source)){ 257 | ER_inf_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Not authorized to mirror the source %s", hostaddress, nrtm_q.source); 258 | sprintf(buff, "\n%%ERROR:3: You are not authorized to mirror the database\n\n"); 259 | SK_cd_puts(&condat, buff); 260 | free(hostaddress); 261 | free(nrtm_q.source); 262 | SK_cd_close(&(condat)); 263 | return; 264 | } 265 | 266 | 267 | 268 | /* get database */ 269 | db_name = ca_get_srcdbname(source_hdl); 270 | /* get database host*/ 271 | db_host = ca_get_srcdbmachine(source_hdl); 272 | /* get database port*/ 273 | db_port = ca_get_srcdbport(source_hdl); 274 | /* get database user*/ 275 | db_user = ca_get_srcdbuser(source_hdl); 276 | /* get database password*/ 277 | db_pswd = ca_get_srcdbpassword(source_hdl); 278 | 279 | sql_connection = SQ_get_connection(db_host, db_port,db_name, db_user, db_pswd); 280 | if(!sql_connection) { 281 | ER_perror(FAC_PM, PM_NOSQLC," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection)); 282 | return; 283 | } 284 | ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- Made SQL connection to %s@%s", hostaddress, db_name, db_host); 285 | 286 | /* free copies of the variables */ 287 | free(db_host); 288 | free(db_name); 289 | free(db_user); 290 | free(db_pswd); 291 | 292 | current_serial=PM_get_current_serial(sql_connection); 293 | oldest_serial=PM_get_oldest_serial(sql_connection); 294 | 295 | if((current_serial==-1) || (oldest_serial==-1)) { 296 | ER_perror(FAC_PM, PM_NOSERN," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection)); 297 | /* Free the hostaddress */ 298 | SK_cd_close(&(condat)); 299 | /* close the connection to SQL server */ 300 | SQ_close_connection(sql_connection); 301 | free(hostaddress); 302 | free(nrtm_q.source); 303 | return; 304 | } 305 | 306 | /* zero indicates that LAST keyword has been used */ 307 | if(nrtm_q.last==0)nrtm_q.last=current_serial; 308 | 309 | 310 | if((nrtm_q.first>nrtm_q.last) || (nrtm_q.first<oldest_serial) || (nrtm_q.last>current_serial) || 311 | (nrtm_q.first<=0) || (nrtm_q.last<=0) ) 312 | { 313 | ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Invalid range: %ld-%ld", hostaddress, nrtm_q.first, nrtm_q.last); 314 | /* write error message back to the client */ 315 | sprintf(buff, "\n%%ERROR:2: Invalid range: Not within %ld-%ld\n\n", oldest_serial, current_serial); 316 | SK_cd_puts(&condat, buff); 317 | SK_cd_close(&(condat)); 318 | 319 | /* close the connection to SQL server */ 320 | SQ_close_connection(sql_connection); 321 | 322 | /* Free the hostaddress */ 323 | free(hostaddress); 324 | free(nrtm_q.source); 325 | return; 326 | } 327 | 328 | current_serial=nrtm_q.first; 329 | 330 | /* print banner */ 331 | { 332 | /* get the header string */ 333 | char *resp_header = ca_get_pw_resp_header; 334 | /* sprintf(buff, "\n%% Rights restricted by copyright. See http://www.ripe.net/ripencc/pub-services/db/copyright.html\n\n"); */ 335 | SK_cd_puts(&condat, resp_header); 336 | free(resp_header); 337 | SK_cd_puts(&condat, "\n"); 338 | } 339 | 340 | sprintf(buff, "%%START Version: %d %s %ld-%ld\n", nrtm_q.version, nrtm_q.source, nrtm_q.first, nrtm_q.last); 341 | SK_cd_puts(&condat, buff); 342 | 343 | /* make a record for thread accounting */ 344 | TA_setactivity(buff); 345 | 346 | /* now start feeding client with data */ 347 | do { 348 | 349 | object=PM_get_serial_object(sql_connection, current_serial, &operation); 350 | if (operation == OP_ADD) SK_cd_puts(&condat, "\nADD\n\n"); 351 | else SK_cd_puts(&condat, "\nDEL\n\n"); 352 | 353 | SK_cd_puts(&condat, object); 354 | 355 | free(object); 356 | current_serial++; 357 | 358 | 359 | } /* do while there are more serials, connection was not reset and XXX do_server is on*/ 360 | while((current_serial<=nrtm_q.last) && (condat.rtc == 0)); 361 | 362 | 363 | sprintf(buff, "\n%%END %s\n\n", nrtm_q.source); 364 | SK_cd_puts(&condat, buff); 365 | 366 | ER_inf_va(FAC_PM, ASP_PM_INPUT,"[%s] -- <%s:%ld-%ld (%ld)> ", 367 | hostaddress, nrtm_q.source, nrtm_q.first, nrtm_q.last, nrtm_q.last-nrtm_q.first+1); 368 | 369 | /* make a record for thread accounting */ 370 | TA_delete(); 371 | 372 | SK_cd_close(&(condat)); 373 | 374 | /* close the connection to SQL server */ 375 | SQ_close_connection(sql_connection); 376 | /* Free the hostaddress */ 377 | free(hostaddress); 378 | free(nrtm_q.source); 379 | 380 | 381 | 382 | } /* PM_interact() */