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