## modules/pm/protocol_mirror.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. IS_Q_QUERY
2. IS_G_QUERY
3. IS_PERSISTENT
4. parse_request
5. PM_interact

       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_dictionary.h"
      46 #include "ca_macros.h"
      47 #include "ca_srcAttribs.h"
      48
      49 #include "erroutines.h"
      50
      51 #include "getopt.h"
      52
      53 #define MIN_ARG_LENGTH  6
      54 #define NRTM_DELIM "-:"
      55
      56 #define MAX_OPT_ARG_C 3
      57
      58 #define Q_QUERY      0x00
      59 #define G_QUERY      0x01
      60 #define K_QUERY      0x02
      61
      62 #define IS_Q_QUERY(a)          ((a)&Q_QUERY)
         /* [<][>][^][v][top][bottom][index][help] */
      63 #define IS_G_QUERY(a)          ((a)&G_QUERY)
         /* [<][>][^][v][top][bottom][index][help] */
      64 #define IS_PERSISTENT(a) ((a)&K_QUERY)
         /* [<][>][^][v][top][bottom][index][help] */
      65
      66
      67 /*
      68 * parses input and fills nrtm_q_t structure
      69 *
      70 * Returns:
      71 *  -1 in case of garbage
      72 *  0  in case of -q sources
      73 *  1  in case of valid -g
      74 *  2  in case of -k
      75 */
      76 static int parse_request(char *input, nrtm_q_t *nrtm_q)
         /* [<][>][^][v][top][bottom][index][help] */
      77 {
      78  int res=0, err=0;
      79  int opt_argc;
      80  int c;
      81  gchar **opt_argv;
      82  getopt_state_t *gst = NULL;
      83
      84   /* Create the arguments. */
      85   /* This allows only a maximum of MAX_OPT_ARG_C words in the query. */
      86   opt_argv = g_strsplit(input, " ", MAX_OPT_ARG_C);
      87
      88   /* Determine the number of arguments. */
      89   for (opt_argc=0; opt_argv[opt_argc] != NULL; opt_argc++);
      90
      91   dieif( (gst = mg_new(0)) == NULL );
      92
      93   while ((c = mg_getopt(opt_argc, opt_argv, "kq:g:", gst)) != EOF)
      94   {
      95     switch (c) {
      96             case 'k':
      97                res |= K_QUERY; /* persistent connection */
      98             break;
      99
     100             case 'q':
     101                 if (gst->optarg != NULL) {
     102                 char *token, *cursor = gst->optarg;
     103
     104                    res |= Q_QUERY;
     105                    err=strncmp(cursor, "sources", 7);
     106                    if(err!=0) break;
     107                    cursor+=7;
     108                    g_strchug(cursor);
     109                    token=cursor;
     110                    /* if no sourses are specified - put NULL in nrtm_q->source and list them all */
     111                    if ((*token=='\0') || (*token=='\n') || ((int)*token==13))nrtm_q->source=NULL;
     112                    else {
     113                      cursor=index(token, ' ');
     114                      if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
     115                      else {
     116                        cursor=index(token, 13); /* search for ctrl-M - telnet loves this */
     117                        if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
     118                        else {
     119                          cursor=index(token, '\n');
     120                          if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
     121                          else nrtm_q->source=g_strdup(token);
     122                        }
     123                      }
     124                    }
     125                 } else err=1;
     126             break;
     127
     128             case 'g':
     129                 if (gst->optarg != NULL) {
     130                 char *token, *cursor = gst->optarg;
     131                 char **tokens;
     132
     133                   res |= G_QUERY;
     134                   g_strdelimit(cursor, NRTM_DELIM, ':');
     135                   tokens=g_strsplit(cursor, ":", 4);
     136                   if(tokens==NULL) { err=1; break; }
     137
     138                   if(tokens[0]) {
     139                   /* first token is source name */
     140                      nrtm_q->source=g_strdup(tokens[0]);
     141                      if(tokens[1]) {
     142                     /* second token is version number */
     143                         nrtm_q->version=atoi(tokens[1]);
     144                         if(tokens[2]) {
     145                         /* this is first serial */
     146                            nrtm_q->first=atol(tokens[2]);
     147                            if (nrtm_q->first>0) {
     148                               if(tokens[3]) {
     149                              /* this is last serial */
     150                                  nrtm_q->last=atol(tokens[3]);
     151                                  if (nrtm_q->last==0)
     152                                  if (strncasecmp(tokens[3], "LAST", 4)!=0) err=1;
     153                               } else err=1;
     154                            } else err=1;
     155                         } else err=1;
     156                      } else err=1;
     157                   } else err=1;
     158                   g_strfreev(tokens);
     159
     160                 } else err=1;
     161
     162             break;
     163             default:
     164                 err=1;
     165             break;
     166     } /* switch */
     167   } /* while there are arguments */
     168
     169  free(gst);
     170
     171  if (err) return(-1);
     172  else return(res);
     173
     174 }
     175
     176
     177 /* PM_interact() */
     178 /*++++++++++++++++++++++++++++++++++++++
     179   Interact with the client.
     180
     181   int sock Socket that client is connected to.
     182
     183   More:
     184   +html+ <PRE>
     185   Authors:
     186         ottrey
     187         andrei
     188
     189   +html+ </PRE><DL COMPACT>
     190   +html+ <DT>Online References:
     191   +html+ <DD><UL>
     192   +html+ </UL></DL>
     193
     194   ++++++++++++++++++++++++++++++++++++++*/
     195 void PM_interact(int sock) {
         /* [<][>][^][v][top][bottom][index][help] */
     196   char input[MAX_INPUT_SIZE];
     197   char buff[STR_L];
     198   ca_dbSource_t *source_hdl;
     199   int read_result;
     200   int parse_result;
     201   ip_addr_t address;
     202
     203   char *hostaddress=NULL;
     204   sk_conn_st condat;
     205   nrtm_q_t nrtm_q;
     206   long current_serial;
     207   long oldest_serial;
     208
     209   char *object;
     210   int operation;
     211
     212
     213   char *db_host;
     214   int  db_port;
     215   char *db_name;
     216   char *db_user;
     217   char *db_pswd;
     218
     219   GString *gbuff;
     220
     221   SQ_connection_t *sql_connection;
     222   int persistent_connection;
     223
     224   /* make a record for thread accounting */
     225   TA_add(sock, "nrtm_srv");
     226
     227
     228   /* Get the IP of the client */
     229   hostaddress = SK_getpeername(sock);
     230
     231   /* initialise the connection structure */
     232   memset( &condat, 0, sizeof(sk_conn_st));
     233   /* initialise the nrtm structure */
     234   memset( &nrtm_q, 0, sizeof(nrtm_q_t));
     235   /* set the connection data: both rIP and eIP to real IP */
     236   condat.sock = sock;
     237   condat.ip = hostaddress;
     238   SK_getpeerip(sock, &(condat.rIP));
     239   memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t));
     240
     241
     242   /* Read input */
     243   read_result = SK_cd_gets(&(condat), input, MAX_INPUT_SIZE);
     244
     245   /* read_result < 0 is an error and connection should be closed */
     246   if (read_result < 0 ) {
     247       /* log the fact, rtc was set */
     248   }
     249
     250
     251   parse_result = parse_request(input, &nrtm_q);
     252
     253
     254   if (parse_result < 0 ) {
     255       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Garbage received: %s", hostaddress, input);
     256       /* log the fact and exit */
     257       /* Free the hostaddress */
     258       sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
     259       SK_cd_puts(&condat, buff);
     260       SK_cd_close(&(condat));
     261       free(hostaddress);
     262       free(nrtm_q.source);
     263       return;
     264   }
     265
     266   ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input: [%s]", hostaddress, input);
     267
     268   /* this is -q sources query  - answer and return */
     269   if (IS_Q_QUERY(parse_result)) {
     270
     271       gbuff=PM_get_nrtm_sources(&(condat.rIP), nrtm_q.source);
     272       SK_cd_puts(&condat, gbuff->str);
     273       /* Free allocated memory  */
     274       g_string_free(gbuff, TRUE);
     275       free(hostaddress);
     276       free(nrtm_q.source);
     277       SK_cd_close(&(condat));
     278       return;
     279   }
     280   else if(IS_G_QUERY(parse_result)){
     281      if(IS_PERSISTENT(parse_result))persistent_connection=1; else persistent_connection=0;
     282   }
     283   else {
     284       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Syntax error: %s", hostaddress, input);
     285       /* log the fact and exit */
     286       /* Free the hostaddress */
     287       sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
     288       SK_cd_puts(&condat, buff);
     289       SK_cd_close(&(condat));
     290       free(hostaddress);
     291       free(nrtm_q.source);
     292       return;
     293
     294   }
     295
     296   /* otherwise this is -g query */
     297
     298
     299   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);
     300
     301   source_hdl = ca_get_SourceHandleByName(nrtm_q.source);
     302   if (source_hdl == NULL){
     303      ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Unknown source %s", hostaddress, nrtm_q.source);
     304      sprintf(buff, "\n%%ERROR:4: Unknown source\n\n");
     305      SK_cd_puts(&condat, buff);
     306      free(hostaddress);
     307      free(nrtm_q.source);
     308      SK_cd_close(&(condat));
     309      return;
     310   }
     311
     312   /* check if the client is authorized to mirror */
     313   SK_getpeerip(sock, &address);
     314   if(!AA_can_mirror(&address, nrtm_q.source)){
     315      ER_inf_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Not authorized to mirror the source %s", hostaddress, nrtm_q.source);
     316      sprintf(buff, "\n%%ERROR:3: You are not authorized to mirror the database\n\n");
     317      SK_cd_puts(&condat, buff);
     318      free(hostaddress);
     319      free(nrtm_q.source);
     320      SK_cd_close(&(condat));
     321      return;
     322   }
     323
     324
     325
     326   /* get database */
     327   db_name = ca_get_srcdbname(source_hdl);
     328   /* get database host*/
     329   db_host = ca_get_srcdbmachine(source_hdl);
     330   /* get database port*/
     331   db_port = ca_get_srcdbport(source_hdl);
     332   /* get database user*/
     333   db_user = ca_get_srcdbuser(source_hdl);
     334   /* get database password*/
     335   db_pswd = ca_get_srcdbpassword(source_hdl);
     336
     337   sql_connection = SQ_get_connection(db_host, db_port,db_name, db_user, db_pswd);
     338   if(!sql_connection) {
     339       ER_perror(FAC_PM, PM_NOSQLC," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
     340       return;
     341   }
     342   ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] --  Made SQL connection to %s@%s", hostaddress, db_name, db_host);
     343
     344   /* free copies of the variables */
     345   free(db_host);
     346   free(db_name);
     347   free(db_user);
     348   free(db_pswd);
     349
     350   current_serial=PM_get_current_serial(sql_connection);
     351   oldest_serial=PM_get_oldest_serial(sql_connection);
     352
     353   if((current_serial==-1) || (oldest_serial==-1)) {
     354       ER_perror(FAC_PM, PM_NOSERN," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
     355       /* Free the hostaddress */
     356       SK_cd_close(&(condat));
     357       /* close the connection to SQL server */
     358       SQ_close_connection(sql_connection);
     359       free(hostaddress);
     360       free(nrtm_q.source);
     361       return;
     362   }
     363
     364   /* zero indicates that LAST keyword has been used */
     365   if(nrtm_q.last==0)nrtm_q.last=current_serial;
     366   /* for persistent connections end of range has no meaning */
     367   if(persistent_connection)nrtm_q.last=current_serial;
     368
     369
     370   if((nrtm_q.first>nrtm_q.last) || (nrtm_q.first<oldest_serial) || (nrtm_q.last>current_serial) ||
     371      (nrtm_q.first<=0) || (nrtm_q.last<=0) )
     372   {
     373       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Invalid range: %ld-%ld", hostaddress, nrtm_q.first, nrtm_q.last);
     374       /* write error message back to the client */
     375       sprintf(buff, "\n%%ERROR:2: Invalid range: Not within %ld-%ld\n\n", oldest_serial, current_serial);
     376       SK_cd_puts(&condat, buff);
     377       SK_cd_close(&(condat));
     378
     379       /* close the connection to SQL server */
     380       SQ_close_connection(sql_connection);
     381
     382       /* Free the hostaddress */
     383       free(hostaddress);
     384       free(nrtm_q.source);
     385       return;
     386   }
     387
     388   current_serial=nrtm_q.first;
     389
     390   /* print banner */
     391   {
     392   /* get the header string */
     393   char *resp_header = ca_get_pw_resp_header;
     394 /*  sprintf(buff, "\n%% Rights restricted by copyright. See http://www.ripe.net/ripencc/pub-services/db/copyright.html\n\n"); */
     395   SK_cd_puts(&condat, "\n");
     396   SK_cd_puts(&condat, resp_header);
     397   free(resp_header);
     398   SK_cd_puts(&condat, "\n");
     399   }
     400
     401   sprintf(buff, "%%START Version: %d %s %ld-%ld\n\n", nrtm_q.version, nrtm_q.source, nrtm_q.first, nrtm_q.last);
     402   SK_cd_puts(&condat, buff);
     403
     404   /* make a record for thread accounting */
     405   TA_setactivity(buff);
     406
     407 /*************************** MAIN LOOP ****************************/
     408 /* now start feeding client with data */
     409   do {
     410
     411     object=PM_get_serial_object(sql_connection, current_serial, &operation);
     412     if (operation == OP_ADD) SK_cd_puts(&condat, "ADD\n\n");
     413     else SK_cd_puts(&condat, "DEL\n\n");
     414
     415     SK_cd_puts(&condat, object);
     416
     417     SK_cd_puts(&condat, "\n");
     418
     419     free(object);
     420     current_serial++;
     421
     422 /* for real-time mirroring we need some piece of code */
     423 if(persistent_connection && (condat.rtc == 0) )
     424 {
     425         while(((nrtm_q.last = PM_get_current_serial(sql_connection))<current_serial)
     426                 && (CO_get_do_server()==1))sleep(1);
     427 }
     428
     429   } /* do while there are more serials, connection was not reset and XXX do_server is on*/
     430    while((current_serial<=nrtm_q.last) && (condat.rtc == 0) && (CO_get_do_server()==1));
     431 /*******************************************************************/
     432
     433   sprintf(buff, "%%END %s\n\n\n", nrtm_q.source);
     434   SK_cd_puts(&condat, buff);
     435
     436   ER_inf_va(FAC_PM, ASP_PM_INPUT,"[%s] -- <%s:%ld-%ld (%ld)> ",
     437            hostaddress, nrtm_q.source, nrtm_q.first, nrtm_q.last, nrtm_q.last-nrtm_q.first+1);
     438
     439   /* make a record for thread accounting */
     440   TA_delete();
     441
     442   /* close the connection to SQL server */
     443   SQ_close_connection(sql_connection);
     444   /* Free the hostaddress */
     445   free(hostaddress);
     446   free(nrtm_q.source);
     447
     448
     449
     450 } /* PM_interact() */

/* [<][>][^][v][top][bottom][index][help] */