1    | /***************************************
2    | 
3    |   Protocol mirror module (pw).  Whois protocol.
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) 1999                              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 "socket.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  |   
166  | 
167  |   char *hostaddress=NULL;
168  | //  acl_st acl_rip,   acl_eip;
169  |   
170  |   sk_conn_st condat;
171  |   nrtm_q_t nrtm_q;
172  |   long current_serial;
173  |   long oldest_serial;
174  |   
175  |   char *object;
176  |   int operation;
177  |   
178  |   
179  |   const char *db_host;
180  |   int  db_port;
181  |   const char *db_name;
182  |   const char *db_user;
183  |   const char *db_pswd;
184  | 
185  |   GString *gbuff;
186  |   
187  |   SQ_connection_t *sql_connection;     
188  | 
189  |   /* make a record for thread accounting */
190  |   TA_add(sock, "nrtm_srv");
191  | 
192  |   
193  |   /* Get the IP of the client */
194  |   hostaddress = SK_getpeername(sock);
195  |   fprintf(stderr,"SK address: %s\n", hostaddress);
196  |   
197  |   /* initialise the connection structure */
198  |   memset( &condat, 0, sizeof(sk_conn_st));
199  |   /* initialise the nrtm structure */
200  |   memset( &nrtm_q, 0, sizeof(nrtm_q_t));
201  |   /* set the connection data: both rIP and eIP to real IP */
202  |   condat.sock = sock;
203  |   condat.ip = hostaddress;
204  |   SK_getpeerip(sock, &(condat.rIP));
205  |   memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t));
206  | 
207  | 
208  |   /* Read input */
209  |   read_result = SK_cd_gets(&(condat), input, MAX_INPUT_SIZE);
210  |     
211  |   /* read_result < 0 is an error and connection should be closed */
212  |   if (read_result < 0 ) {
213  |       /* log the fact, rtc was set */
214  | //not yet, SK_... returns arb number      return; 
215  |   }
216  | 
217  |     
218  |   parse_result = parse_request(input, &nrtm_q);
219  | 
220  |   
221  |   if (parse_result < 0 ) {
222  | /*      fprintf(stderr, "Garbage received: %s\n", input);*/
223  |       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Garbage received: %s", hostaddress, input);
224  |       /* log the fact and exit */
225  |       /* Free the hostaddress */
226  |       sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
227  |       SK_cd_puts(&condat, buff);
228  |       SK_cd_close(&(condat));
229  |       free(hostaddress);
230  |       free(nrtm_q.source);
231  |       return;
232  |   }
233  |   
234  |   ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input: [%s]", hostaddress, input); 
235  |     
236  |   if (parse_result == 1 ) {
237  | 	  
238  |      fprintf(stderr, "-q sources\n"); 
239  |      gbuff=PM_get_nrtm_sources(&(condat.rIP), nrtm_q.source);
240  |      SK_cd_puts(&condat, gbuff->str);
241  |      /* Free allocated memory  */
242  |      g_string_free(gbuff, TRUE);
243  |      free(hostaddress);
244  |      free(nrtm_q.source);
245  |      SK_cd_close(&(condat));
246  |      return;
247  |   }
248  |  
249  |   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);
250  |    
251  |   source_hdl = ca_get_SourceHandleByName(nrtm_q.source); 
252  |   if (source_hdl == NULL){
253  |  /*    fprintf(stderr, "%%ERROR:4: Unknown source %s\n", nrtm_q.source); */
254  |      ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Unknown source %s", hostaddress, nrtm_q.source);
255  |      sprintf(buff, "\n%%ERROR:4: Unknown source\n\n");
256  |      SK_cd_puts(&condat, buff);
257  |      free(hostaddress);
258  |      free(nrtm_q.source);
259  |      SK_cd_close(&(condat));
260  |      return;
261  |   }
262  | 	 
263  |   /* check if the client is authorized to mirror */
264  |   SK_getpeerip(sock, &address);
265  |   if(!AA_can_mirror(&address, nrtm_q.source)){
266  | /*     fprintf(stderr, "%%ERROR:3: You are not authorized to mirror the database\n");*/
267  |      ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Not authorized to mirror the database", hostaddress);
268  |      sprintf(buff, "\n%%ERROR:3: You are not authorized to mirror the database\n\n");
269  |      SK_cd_puts(&condat, buff);
270  |      free(hostaddress);
271  |      free(nrtm_q.source);
272  |      SK_cd_close(&(condat));
273  |      return;
274  |   }
275  | 
276  |       
277  |     
278  |   /* get database */
279  | /*  db_name=CO_get_database(); */
280  |   db_name = ca_get_srcdbname(source_hdl);
281  |       
282  |   /* get database host*/
283  | /*  db_host=CO_get_host();*/
284  |   db_host = ca_get_srcdbmachine(source_hdl);      
285  |   /* get database port*/
286  | /*  db_port=CO_get_database_port();*/
287  |   db_port = ca_get_srcdbport(source_hdl);        
288  |   /* get database user*/
289  | /*  db_user=CO_get_user(); */
290  |   db_user = ca_get_srcdbuser(source_hdl);          
291  |   /* get database password*/
292  | /*  db_pswd=CO_get_password(); */
293  |   db_pswd = ca_get_srcdbpassword(source_hdl);
294  |   
295  | /*  fprintf(stderr, "D: Making SQL connection to %s@%s ...", db_name, db_host);*/
296  |   sql_connection = SQ_get_connection(db_host, db_port,db_name, db_user, db_pswd);
297  |   if(!sql_connection) {
298  | /*      fprintf(stderr, "E: ERROR: no SQL connection\n");*/
299  |       ER_perror(FAC_PM, PM_NOSQLC," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
300  |       return;
301  |   }
302  | /*  fprintf(stderr, "OK\n"); */
303  |    ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] --  Made SQL connection to %s@%s", hostaddress, db_name, db_host); 
304  | 
305  |   /* free copies of the variables */
306  |   free(db_host);
307  |   free(db_name);
308  |   free(db_user);
309  |   free(db_pswd);
310  |                                                         
311  |   current_serial=PM_get_current_serial(sql_connection);
312  |   oldest_serial=PM_get_oldest_serial(sql_connection);
313  |     
314  |   if((current_serial==-1) || (oldest_serial==-1)) {
315  | /*      fprintf(stderr, "E: ERROR: cannot get serial #\n");*/
316  |       ER_perror(FAC_PM, PM_NOSERN," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
317  |       /* Free the hostaddress */
318  |       SK_cd_close(&(condat));
319  |       /* close the connection to SQL server */
320  |       SQ_close_connection(sql_connection); 
321  |       free(hostaddress);
322  |       free(nrtm_q.source);
323  |       return;
324  |   }
325  |   
326  |   /* zero indicates that LAST keyword has been used */    
327  |   if(nrtm_q.last==0)nrtm_q.last=current_serial;
328  |   
329  |     
330  |   if((nrtm_q.first>nrtm_q.last) || (nrtm_q.first<oldest_serial) || (nrtm_q.last>current_serial) ||
331  |      (nrtm_q.first<=0) || (nrtm_q.last<=0) ) 
332  |   {
333  |      /* if(nrtm_q.first<oldest_serial) nrtm_q.last=oldest_serial-1;
334  |       if(nrtm_q.last>current_serial) nrtm_q.first=current_serial+1; */
335  | /*      fprintf(stderr, "E: ERROR: invalid range: %ld-%ld\n",  nrtm_q.first, nrtm_q.last);*/
336  |       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Invalid range: %ld-%ld", hostaddress, nrtm_q.first, nrtm_q.last);
337  |       /* write error message back to the client */
338  | /*      sprintf(buff, "%%ERROR:2: Invalid range: serial(s) %ld-%ld don't exist\n", nrtm_q.first, nrtm_q.last); */
339  |       sprintf(buff, "\n%%ERROR:2: Invalid range: Not within %ld-%ld\n\n", oldest_serial, current_serial);
340  |       SK_cd_puts(&condat, buff);
341  |       SK_cd_close(&(condat));
342  |       
343  |       /* close the connection to SQL server */
344  |       SQ_close_connection(sql_connection); 
345  | 
346  |       /* Free the hostaddress */
347  |       free(hostaddress);
348  |       free(nrtm_q.source);
349  |       return;
350  |   }
351  |   
352  |   current_serial=nrtm_q.first;
353  |   /* print banner */
354  |   
355  |   sprintf(buff, "%%START Version:%d %s %ld-%ld\n", nrtm_q.version, nrtm_q.source, nrtm_q.first, nrtm_q.last);
356  |   SK_cd_puts(&condat, buff);
357  | 
358  |   /* make a record for thread accounting */
359  |   TA_setactivity(buff);
360  |   
361  | /* now start feeding client with data */    
362  |   do {    
363  | 
364  |     object=PM_get_serial_object(sql_connection, current_serial, &operation);
365  |     if (operation == OP_ADD) SK_cd_puts(&condat, "\nADD\n\n");
366  |     else SK_cd_puts(&condat, "\nDEL\n\n");
367  |     
368  |     SK_cd_puts(&condat, object);
369  |       
370  |     free(object);
371  |     current_serial++;
372  | 
373  | 
374  |   } /* do */
375  |    while((current_serial<=nrtm_q.last) && (condat.rtc == 0));
376  | 
377  |   
378  |   sprintf(buff, "\n%%END %s\n\n", nrtm_q.source);
379  |   SK_cd_puts(&condat, buff);
380  | 
381  |   ER_inf_va(FAC_PM, ASP_PM_INPUT,"[%s] -- <%s:%ld-%ld (%ld)> ", 
382  |            hostaddress, nrtm_q.source, nrtm_q.first, nrtm_q.last, nrtm_q.last-nrtm_q.first+1); 
383  | 
384  |   /* make a record for thread accounting */
385  |   TA_delete();
386  | 
387  |   SK_cd_close(&(condat));
388  | 
389  |   /* close the connection to SQL server */
390  |   SQ_close_connection(sql_connection); 
391  |   /* Free the hostaddress */
392  |   free(hostaddress);
393  |   free(nrtm_q.source);
394  | 
395  |   
396  |   
397  | } /* PM_interact() */