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() */