Example #1
0
/**
 * z_proxy_stack_prepare_streams:
 * @self: ZProxy instance
 * @downpair:
 * @uppair:
 *
 **/
static gboolean
z_proxy_stack_prepare_streams(ZProxy *self, gint *downpair, gint *uppair)
{
  z_proxy_enter(self);

  if (socketpair(AF_UNIX, SOCK_STREAM, 0, downpair) == -1)
    {
      /*LOG
        This message indicates that stacking a child proxy failed, because
        creating an AF_UNIX domain socketpair failed on the client side.
       */
      z_proxy_log(self, CORE_ERROR, 1, "Error creating client socketpair for stacked proxy; error='%s'", g_strerror(errno));
      z_proxy_leave(self);
      return FALSE;
    }
  else if (socketpair(AF_UNIX, SOCK_STREAM, 0, uppair) == -1)
    {
      close(downpair[0]);
      close(downpair[1]);
      /*LOG
        This message indicates that stacking a child proxy failed, because
        creating an AF_UNIX domain socketpair failed on the server side.
       */
      z_proxy_log(self, CORE_ERROR, 1, "Error creating server socketpair for stacked proxy; error='%s'", g_strerror(errno));
      z_proxy_leave(self);
      return FALSE;
    }
  z_proxy_leave(self);
  return TRUE;
}
Example #2
0
ZPolicyObj *
smtp_policy_sanitize_address(SmtpProxy *self, ZPolicyObj *args)
{
  gchar *address;
  gchar *final_end;
  GString *sanitized_address;
  ZPolicyObj *res = NULL;

  z_proxy_enter(self);
  if (!z_policy_var_parse_tuple(args, "s", &address))
    {
      z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid arguments");
      z_proxy_leave(self);
      return NULL;
    }

  sanitized_address = g_string_new("");
  if (!smtp_sanitize_address(self, sanitized_address, address, TRUE, &final_end))
    {
      z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid address");
      goto exit;
    }

  res = z_policy_var_build("s", sanitized_address->str);

 exit:
  g_string_free(sanitized_address, TRUE);
  z_proxy_leave(self);
  return res;
}
Example #3
0
/**
 * z_transfer2_read_source:
 * @self: ZTransfer2 instance
 * @endpoint: endpoint to fetch data from
 * @buf: store fetched information into this buffer
 * @error: error details are stored here
 *
 * This function is called to fetch data from the specified endpoint. When
 * it is a proxy-connected stream then the proxy provided callbacks are
 * used to fetch information, otherwise z_stream_read is called directly.
 **/
static GIOStatus
z_transfer2_read_source(ZTransfer2 *self, gint endpoint, ZTransfer2Buffer *buf, GError **error)
{
  ZStream *from = z_transfer2_get_stream(self, endpoint);
  GIOStatus res = G_IO_STATUS_NORMAL;
  GError *local_error = NULL;
  gsize read_len;

  z_proxy_enter(self->owner);
  if (endpoint & ZT2E_STACKED)
    {
      res = z_stream_read(from, &buf->buf[buf->end], buf->size - buf->end, &read_len, &local_error);
    }
  else if (endpoint == ZT2E_SOURCE)
    {
      res = z_transfer2_src_read(self, self->endpoints[endpoint], &buf->buf[buf->end], buf->size - buf->end, &read_len, &local_error);
    }

  if (res == G_IO_STATUS_NORMAL)
    {
      buf->end += read_len;
    }
  if (local_error)
    g_propagate_error(error, local_error);
  z_proxy_leave(self->owner);
  return res;
}
Example #4
0
/**
 * anypy_set_content_hint:
 * @self: AnyPyProxy instance
 * @args: Python args argument
 *
 * sets verdict for the parent proxy
 * args is (verdict,description)
 **/
static ZPolicyObj *
anypy_set_content_hint(AnyPyProxy * self, ZPolicyObj *args)
{
  gint64 length;

  z_proxy_enter(self);

  if (!z_policy_var_parse_tuple(args, "L", &length))
    {
      z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid arguments.");
      z_proxy_leave(self);
      return NULL;
    }

  if (self->super.parent_proxy)
    {
      ZProxyStackIface *iface;
      iface = z_proxy_find_iface(self->super.parent_proxy, Z_CLASS(ZProxyStackIface));
      if (iface)
        {
          z_proxy_stack_iface_set_content_hint(iface, length);
          z_object_unref(&iface->super);
        }
    }

  z_proxy_return(self, z_policy_none_ref());
}
Example #5
0
static gboolean
anypy_stream_init(AnyPyProxy *self)
{
  z_proxy_enter(self);
  if (!self->super.endpoints[EP_CLIENT] || !self->super.endpoints[EP_SERVER])
    {
      z_proxy_log(self, ANYPY_ERROR, 2, "Server side not yet connected, unable to init streams;");
      z_proxy_leave(self);
      return FALSE;
    }
  self->super.endpoints[EP_CLIENT] = z_stream_push(self->super.endpoints[EP_CLIENT], z_stream_line_new(NULL, self->max_line_length[EP_CLIENT], ZRL_EOL_CRLF));
  self->super.endpoints[EP_SERVER] = z_stream_push(self->super.endpoints[EP_SERVER], z_stream_line_new(NULL, self->max_line_length[EP_SERVER], ZRL_EOL_CRLF));

  z_proxy_leave(self);
  return TRUE;
}
Example #6
0
/**
 * z_transfer2_write_dest:
 * @self: ZTransfer2 instance
 * @endpoint: endpoint to send data to
 * @buf: send data from this buffer
 * @error: error details are stored here
 *
 * This function is called to send data to the specified endpoint. When
 * it is a proxy-connected stream then the proxy provided callbacks are
 * used to send information, otherwise z_stream_write is called directly.
 **/
static GIOStatus
z_transfer2_write_dest(ZTransfer2 *self, gint endpoint, ZTransfer2Buffer *buf, GError **error)
{
  ZStream *to = z_transfer2_get_stream(self, endpoint);
  GError *local_error = NULL;
  GIOStatus res = G_IO_STATUS_NORMAL;
  gsize bytes_written;

  z_proxy_enter(self->owner);
  if (!z_transfer2_buffer_empty(buf))
    {
      if (endpoint & ZT2E_STACKED)
        res = z_stream_write(to, &buf->buf[buf->ofs], buf->end - buf->ofs, &bytes_written, &local_error);
      else
        res = z_transfer2_dst_write(self, to, &buf->buf[buf->ofs], buf->end - buf->ofs, &bytes_written, &local_error);
      switch (res)
        {
        case G_IO_STATUS_NORMAL:
          buf->ofs += bytes_written;
          if (!z_transfer2_buffer_empty(buf))
            {
              res = G_IO_STATUS_AGAIN;
            }
        default:
          break;
        }
    }
  if (local_error)
    g_propagate_error(error, local_error);
  z_proxy_leave(self->owner);
  return res;
}
Example #7
0
/**
 * anypy_config_set_defaults:
 * @self: AnyPyProxy instance
 *
 * This function initializes various attributes exported to the Python layer
 * for possible modification.
 **/
static void
anypy_config_set_defaults(AnyPyProxy *self)
{
  z_proxy_enter(self);

  self->max_line_length[EP_CLIENT] = 4096;
  self->max_line_length[EP_SERVER] = 4096;

  z_proxy_leave(self);
}
Example #8
0
void
ftp_policy_feature_hash_handle_insert(struct _FtpProxy *self, GHashTable *features)
{
  z_proxy_enter(self);

  z_policy_lock(self->super.thread);
  g_hash_table_foreach(self->policy_features, ftp_policy_feature_hash_foreach_cb, features);
  z_policy_unlock(self->super.thread);

  z_proxy_leave(self);
}
Example #9
0
/**
 * z_transfer2_timeout:
 * @user_data: ZTransfer2 instance passed as a generic pointer
 *
 * This function is a timeout-callback registered to terminate the
 * transfer loop when a specified time elapses.
 **/
static gboolean
z_transfer2_timeout(gpointer user_data)
{
  ZTransfer2 *self = Z_CAST(user_data, ZTransfer2);

  z_proxy_enter(self->owner);
  /*LOG
    This message indicates the data transfer timed out.
   */
  z_proxy_log(self->owner, CORE_ERROR, 3, "Data transfer timed out; timeout='%ld'", self->timeout);
  z_transfer2_update_status(self, ZT2S_TIMEDOUT+ZT2S_FAILED+ZT2S_FINISHED, TRUE);
  z_proxy_leave(self->owner);
  return FALSE;
}
Example #10
0
static gboolean
z_proxy_stack_fds(ZProxy *self, gint client_fd, gint server_fd, gint control_fd, ZStackedProxy **stacked, guint32 flags)
{
  ZStream *client_upstream, *server_upstream, *control_stream = NULL;

  z_proxy_enter(self);
  client_upstream = z_stream_fd_new(client_fd, "");
  server_upstream = z_stream_fd_new(server_fd, "");
  if (control_fd != -1)
    control_stream = z_stream_fd_new(control_fd, "");

  *stacked = z_stacked_proxy_new(client_upstream, server_upstream, control_stream, self, NULL, flags);
  
  z_proxy_leave(self);
  return TRUE;
}
Example #11
0
/**
 * z_transfer2_eof:
 * @self: ZTransfer2 instance
 *
 * This function is called when transfer encounters an EOF one of the
 * endpoints. It updates self->status end also terminates the poll loop
 * by setting ZT2S_FINISHED when the transfer supposedly finished.
 **/
static void
z_transfer2_eof(ZTransfer2 *self, gint endpoint)
{
  guint32 eof_status = endpoint == ZT2E_SOURCE ? ZT2S_EOF_SOURCE : ZT2S_EOF_DEST;

  z_proxy_enter(self->owner);
  if (!z_transfer2_get_status(self, eof_status))
    {
      if (self->stacked)
        {
          if (endpoint == ZT2E_SOURCE)
            {
              z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), FALSE);
              z_transfer2_src_shutdown(self, z_transfer2_get_stream(self, ZT2E_SOURCE), NULL);
              z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), TRUE);

              z_stream_shutdown(z_transfer2_get_stream(self, ZT2E_DOWN_SOURCE), SHUT_WR, NULL);
            }
          else
            {
              z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), FALSE);
              z_stream_shutdown(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), SHUT_RD, NULL);
              z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), TRUE);
              z_transfer2_dst_shutdown(self, z_transfer2_get_stream(self, ZT2E_DEST), NULL);
            }
        }
      else
        {
          z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), FALSE);
          z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DEST), FALSE);
          z_transfer2_src_shutdown(self, z_transfer2_get_stream(self, ZT2E_SOURCE), NULL);
          z_transfer2_dst_shutdown(self, z_transfer2_get_stream(self, ZT2E_DEST), NULL);
          z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DEST), TRUE);
          z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), TRUE);

          eof_status = ZT2S_EOF_SOURCE+ZT2S_EOF_DEST;
        }

      z_transfer2_update_status(self, eof_status, TRUE);
    }
  if ((self->status & (ZT2S_EOF_SOURCE+ZT2S_EOF_DEST)) == (ZT2S_EOF_SOURCE+ZT2S_EOF_DEST))
    {
      z_transfer2_update_status(self, ZT2S_FINISHED, TRUE);
    }
  z_proxy_leave(self->owner);
}
Example #12
0
void
plug_config_set_defaults(PlugProxy *self)
{
  z_proxy_enter(self);

  self->session_data.copy_to_server = TRUE;
  self->session_data.copy_to_client = TRUE;
  self->session_data.timeout = 600000;
  self->session_data.buffer_size = PLUG_DEFAULT_BUFSIZE;
  self->session_data.packet_stats = plug_packet_stat_event;
  self->session_data.finish = plug_finish;
  self->session_data.timeout_cb = plug_timeout;
  
  if (self->super.parent_proxy)
    self->session_data.shutdown_soft = TRUE;

  z_proxy_leave(self);
}
Example #13
0
/**
 * z_transfer2_update_cond:
 * @self: ZTransfer2 instance
 *
 * This function is called after a chunk of data was transferred to update
 * the stream read/write conditions. It works based on the bits
 * stored in self->status.
 **/
static void
z_transfer2_update_cond(ZTransfer2 *self)
{
  gint i;

  z_proxy_enter(self->owner);
  for (i = 0; i <= ZT2E_MAX; i++)
    {
      if ((i & ZT2E_STACKED) == 0 || self->stacked)
        {
          z_stream_set_cond(z_transfer2_get_stream(self, i), G_IO_IN, FALSE);
          z_stream_set_cond(z_transfer2_get_stream(self, i), G_IO_OUT, FALSE);
        }
    }
  if (self->stacked)
    {
      if (!z_transfer2_get_status(self, ZT2S_EOF_SOURCE))
        {
          if (z_transfer2_buffer_empty(&self->buffers[0]) && !z_transfer2_get_status(self, ZT2S_PROXY_OUT))
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_SOURCE), G_IO_IN, TRUE);
          else
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DOWN_SOURCE), G_IO_OUT, TRUE);
        }
      if (!z_transfer2_get_status(self, ZT2S_EOF_DEST))
        {
          if (z_transfer2_buffer_empty(&self->buffers[1]))
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), G_IO_IN, TRUE);
          else
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DEST), G_IO_OUT, TRUE);
        }
    }
  else
    {
      /* no stacking */
      if (!z_transfer2_get_status(self, ZT2S_EOF_SOURCE))
        {
          if ((z_transfer2_buffer_empty(&self->buffers[0]) || z_transfer2_get_status(self, ZT2S_EOF_DEST) != 0) && !z_transfer2_get_status(self, ZT2S_PROXY_OUT))
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_SOURCE), G_IO_IN, TRUE);
          else
            z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DEST), G_IO_OUT, TRUE);
        }
    }
  z_proxy_leave(self->owner);
}
Example #14
0
static void
anypy_main(ZProxy * s)
{
  AnyPyProxy *self = Z_CAST(s, AnyPyProxy);
  ZPolicyObj *res;
  gboolean called;

  z_proxy_enter(self);
  if (!z_proxy_connect_server(&self->super, NULL, 0) || !anypy_stream_init(self))
    {
      z_proxy_leave(self);
      return;
    }
  z_policy_lock(self->super.thread);  
  res = z_policy_call(self->super.handler, "proxyThread", NULL, &called, self->super.session_id);
  z_policy_var_unref(res);
  z_policy_unlock(self->super.thread);
  z_proxy_return(self);
}
Example #15
0
/**
 * z_transfer2_timed_progress:
 * @user_data: ZTransfer2 instance passed as a generic pointer
 *
 * This function is the timeout callback registered to be called when the
 * interval specified by the timeout_progress variable elapses.  This is
 * used for example to generate NOOPs in SMTP while transfer is downloading
 * data to the virus checking proxy.
 **/
static gboolean
z_transfer2_timed_progress(gpointer user_data)
{
  ZTransfer2 *self = Z_CAST(user_data, ZTransfer2);

  z_proxy_enter(self->owner);
  if (!z_transfer2_progress(self))
    {
      /*LOG
        This message indicates that the data-transfer is interrupted by a timed
	progress callback and Zorp is closing the date-transfer channels.
       */
      z_proxy_log(self->owner, CORE_ERROR, 3, "Data transfer interrupted by progress;");
      z_transfer2_update_status(self, ZT2S_FAILED+ZT2S_FINISHED, TRUE);
    }
  z_timeout_source_set_timeout(self->progress_source, self->progress_interval);

  z_proxy_leave(self->owner);
  return TRUE;
}
Example #16
0
static void
anypy_register_vars(AnyPyProxy *self)
{
  z_proxy_enter(self);
  /* method for setting the proxy verdict. It should be used before the first write */
  z_proxy_var_new(&self->super, "set_verdict",
	Z_VAR_TYPE_METHOD | Z_VAR_GET,
	self,anypy_set_verdict);
  /* method for setting the content hint. It should be used before the first write */
  z_proxy_var_new(&self->super, "set_content_hint",
        Z_VAR_TYPE_METHOD | Z_VAR_GET,
        self, anypy_set_content_hint);
  /* size of line buffer of the client stream */
  z_proxy_var_new(&self->super, "client_max_line_length",
	Z_VAR_TYPE_INT | Z_VAR_GET | Z_VAR_SET_CONFIG | Z_VAR_GET_CONFIG,
	&self->max_line_length[EP_CLIENT]);
  /* size of line buffer of the server stream */
  z_proxy_var_new(&self->super, "server_max_line_length",
	Z_VAR_TYPE_INT | Z_VAR_GET | Z_VAR_SET_CONFIG | Z_VAR_GET_CONFIG,
	&self->max_line_length[EP_SERVER]);
  z_proxy_leave(self);
}
Example #17
0
/**
 * z_proxy_stack_program:
 * @self: proxy instance
 * @program: path to program to execute
 *
 * This function is called to start a program as a filtering child proxy.
 **/
static gboolean
z_proxy_stack_program(ZProxy *self, const gchar *program, ZStackedProxy **stacked)
{
  int downpair[2], uppair[2], controlpair[2];
  pid_t pid;
  
  z_proxy_enter(self);

  if (!z_proxy_stack_prepare_streams(self, downpair, uppair))
    {
      z_proxy_leave(self);
      return FALSE;
    }

  if (socketpair(AF_UNIX, SOCK_STREAM, 0, controlpair) < 0)
    {
      close(downpair[0]);
      close(downpair[1]);
      close(uppair[0]);
      close(uppair[1]);
      close(controlpair[0]);
      close(controlpair[1]);
      /*LOG
        This message indicates that stacking a child proxy failed, because
        creating an AF_UNIX domain socketpair failed for the control
        channel.
       */
      z_proxy_log(self, CORE_ERROR, 1, "Error creating control socketpair for stacked proxy; error='%s'", g_strerror(errno));
      z_proxy_leave(self);
      return FALSE;
    }
  
  /*LOG
    This message reports that Zorp is about to stack a program
    with the given fds as communication channels.
   */
  z_proxy_log(self, CORE_DEBUG, 6, "Stacking program; client='%d:%d', server='%d:%d', control='%d:%d', program='%s'", 
              downpair[0], downpair[1], uppair[0], uppair[1], controlpair[0], controlpair[1], program);
 
  pid = fork();

  if (pid == 0)
    {
      int i;
      /* child */
      
      dup2(downpair[1], 0);
      dup2(uppair[1], 1);
      /* standard error is inherited */
      dup2(controlpair[1], 3);
      
      for (i = 4; i < sysconf(_SC_OPEN_MAX); i++)
        close(i);
      execl("/bin/sh", "/bin/sh", "-c", program, NULL);
      fprintf(stderr, "Error starting program; program='%s', error='%s'", program, strerror(errno));
      exit(127);
    }
  else if (pid < 0)
    {
      z_proxy_log(self, CORE_ERROR, 2, "Program stacking failed, fork returned error; program='%s', error='%s'", program, g_strerror(errno));

      close(downpair[0]);
      close(downpair[1]);
      close(uppair[0]);
      close(uppair[1]);
      close(controlpair[0]);
      close(controlpair[1]);
      z_proxy_leave(self);
      return FALSE;
    }

  close(downpair[1]);
  close(uppair[1]);
  close(controlpair[1]);
  if (!z_proxy_stack_fds(self, downpair[0], uppair[0], controlpair[0], stacked, 0))
    {
      z_proxy_leave(self);
      return FALSE;
    }
  z_proxy_leave(self);
  return TRUE;
}
Example #18
0
guint
Pop3AnswerParseNum_One(Pop3Proxy *self)
{
  long int arg;
  gchar *err;
  gchar newline[self->max_reply_length];

  z_proxy_enter(self);
  if (!strcmp(self->response->str, "-ERR"))
    z_proxy_return(self, POP3_RSP_ACCEPT);

  arg = strtol(self->response_param->str, &err, 10);
  if ( err == self->response_param->str )
    {
      /*LOG
        This message indicates that the numerical parameter of the response is missing and Zorp
	aborts the connection.
       */
      z_proxy_log(self, POP3_RESPONSE, 3, "The required numerical parameter of the response is missing; req='%s', rsp_prm='%s'",
	self->command->str, self->response_param->str);
      z_proxy_return(self, POP3_RSP_ABORT);
    }

  if (errno == ERANGE)
    {
      /*LOG
        This message indicates that the numerical parameter of the response is not in the given range and
	Zorp aborts the connection.
       */
      z_proxy_log(self, POP3_RESPONSE, 3, "The numerical parameter of the response is not in the given range; req='%s', rsp_prm='%s'",
	self->command->str, self->response_param->str);
      z_proxy_return(self, POP3_RSP_ABORT);
    }

  if (arg < 0)
    {
      /*LOG
        This message indicates that the numerical parameter of the response is a negative number which is invalid and
	Zorp aborts the connection.
       */
      z_proxy_log(self, POP3_RESPONSE, 3, "The numerical parameter of the response is a negative number; req='%s', rsp_prm='%s'",
	  self->command->str, self->response_param->str);
      z_proxy_return(self, POP3_RSP_ABORT);
    }

  if (*err != 0)
    {
      /*LOG
        This message indicates that the numerical parameter of the response contains junk characters after the number but
	Zorp ignores and truncates the junk.
       */
      z_proxy_log(self, POP3_RESPONSE, 4, "The numerical parameter of the response contains junk after the number; req='%s', rsp_prm='%s'",
	  self->command->str, self->response_param->str);
    }

  g_snprintf(newline, sizeof(newline), "%ld", arg);

  g_string_assign(self->response_param, newline);

  z_proxy_leave(self);
  return POP3_RSP_ACCEPT;
}
Example #19
0
/**
 * z_transfer2_copy_data:
 * @self: ZTransfer2 instance
 * @ep_from: source endpoint
 * @ep_to: destination endpoint
 * @error: error details are stored here
 *
 * This function is the central copy-loop of ZTransfer2 and is called by I/O
 * callbacks assigned to various streams. It copies data while:
 * 1) data is available (e.g. G_IO_STATUS_NORMAL is returned)
 * 2) have not copied MAX_READ_AT_A_TIME chunks yet
 * 3) data can be flushed to destination (e.g. G_IO_STATUS_NORMAL is returned)
 *
 * when any of the conditions become FALSE, z_transfer2_copy_data returns,
 * but the operation can simply be restarted by calling it again.
 * Information stored in internal buffers are automatically reused in the
 * next invocation.
 *
 * This function also updates the timeout timer to indicate that some I/O
 * has happened, thus the timeout callback does not need to be called.
 **/
static GIOStatus
z_transfer2_copy_data(ZTransfer2 *self, gint ep_from, gint ep_to, GError **error)
{
  GError *local_error = NULL;
  ZTransfer2Buffer *buf = &self->buffers[ep_from & ~ZT2E_STACKED];
  gint pkt_count = 0;
  GIOStatus res = G_IO_STATUS_NORMAL;
  gboolean leave_while = FALSE;

  z_proxy_enter(self->owner);
  if (self->timeout_source)
    z_timeout_source_set_timeout(self->timeout_source, self->timeout);

  while (pkt_count < MAX_READ_AT_A_TIME && !leave_while)
    {
      if (!z_transfer2_get_status(self, ZT2S_COPYING_TAIL))
        {
          res = z_transfer2_write_dest(self, ep_to, buf, &local_error);
          if (res == G_IO_STATUS_NORMAL)
            {
              if (!z_transfer2_buffer_empty(buf))
                break;
            }
          else if (res == G_IO_STATUS_AGAIN)
            {
              break;
            }
          else
            {
              z_transfer2_update_status(self, ZT2S_FAILED, TRUE);
              if (self->flags & ZT2F_COMPLETE_COPY)
                {
                  z_transfer2_update_status(self, ZT2S_COPYING_TAIL, TRUE);
                }
              else
                {
                  z_transfer2_update_status(self, ZT2S_FINISHED, TRUE);
                }
              break;
            }
        }
      else
        {
          buf->ofs = buf->end = 0;
        }

      if (z_transfer2_buffer_empty(buf))
        {
          buf->ofs = buf->end = 0;
        }

      while (pkt_count < MAX_READ_AT_A_TIME && !z_transfer2_buffer_full(buf))
        {
          guint eof_status = ep_from == ZT2E_SOURCE ? ZT2S_SOFT_EOF_SOURCE : ZT2S_SOFT_EOF_DEST;

          if (!z_transfer2_get_status(self, eof_status))
            {
              res = z_transfer2_read_source(self, ep_from, buf, &local_error);
              if (res == G_IO_STATUS_NORMAL)
                {
                  ;
                }
              else if (res == G_IO_STATUS_AGAIN)
                {
                  leave_while = TRUE;
                  break;
                }
              else if (res == G_IO_STATUS_EOF)
                {
                  if (z_transfer2_buffer_empty(buf))
                    {
                      z_transfer2_eof(self, ep_from);
                      leave_while = TRUE;
                      break;
                    }
                  else
                    {
                      z_transfer2_update_status(self, eof_status, TRUE);
                      break;
                    }
                }
              else
                {
                  z_transfer2_update_status(self, ZT2S_FINISHED + ZT2S_ABORTED, TRUE);
                  z_transfer2_eof(self, ep_from);
                  leave_while = TRUE;
                  break;
                }
              pkt_count++;
            }
          else
            {
              if (z_transfer2_buffer_empty(buf))
                {
                  z_transfer2_eof(self, ep_from);
                  leave_while = TRUE;
                }
              break;
            }
        }
    }

  z_transfer2_update_cond(self);
  if (local_error)
    g_propagate_error(error, local_error);

  z_proxy_leave(self->owner);
  return res;
}
Example #20
0
/**
 * z_proxy_stack_proxy:
 * @self: proxy instance
 * @proxy_class: a Python class to be instantiated as the child proxy
 *
 * This function is called to start a child proxy.
 **/
gboolean
z_proxy_stack_proxy(ZProxy *self, ZPolicyObj *proxy_class, ZStackedProxy **stacked, ZPolicyDict *stack_info)
{
  int downpair[2], uppair[2];
  ZPolicyObj *res, *client_stream, *server_stream, *stack_info_obj;
  ZStream *tmpstream;
  ZStream *client_upstream, *server_upstream;
  
  z_proxy_enter(self);
  if (proxy_class == z_policy_none)
    { 
      z_policy_var_unref(proxy_class);
      z_proxy_leave(self);
      return FALSE;
    }
  
  if (!z_proxy_stack_prepare_streams(self, downpair, uppair))
    {
      z_policy_var_unref(proxy_class);
      z_proxy_leave(self);
      return FALSE;
    }
  
  /*LOG
    This message reports that Zorp is about to stack a proxy class
    with the given fds as communication channels.
   */
  z_proxy_log(self, CORE_DEBUG, 6, "Stacking subproxy; client='%d:%d', server='%d:%d'", downpair[0], downpair[1], uppair[0], uppair[1]);
  
  tmpstream = z_stream_fd_new(downpair[1], "");
  client_stream = z_policy_stream_new(tmpstream);
  z_stream_unref(tmpstream);
  
  tmpstream = z_stream_fd_new(uppair[1], "");
  server_stream = z_policy_stream_new(tmpstream);
  z_stream_unref(tmpstream);

  if (stack_info)
    {
      stack_info_obj = z_policy_struct_new(stack_info, Z_PST_SHARED);
    }
  else
    {
      Py_XINCREF(Py_None);
      stack_info_obj = Py_None;
    }

  res = z_policy_call(self->handler, "stackProxy", z_policy_var_build("(OOOO)", client_stream, server_stream, proxy_class, stack_info_obj),
                        NULL, self->session_id);
  
  z_policy_var_unref(client_stream);
  z_policy_var_unref(server_stream);
  z_policy_var_unref(stack_info_obj);
  
  if (!res || res == z_policy_none || !z_policy_proxy_check(res))
    {
      z_proxy_log(self, CORE_ERROR, 3, "Error stacking subproxy;");
      close(downpair[0]);
      close(downpair[1]);
      close(uppair[0]);
      close(uppair[1]);
      z_policy_var_unref(res);
      z_proxy_leave(self);
      return FALSE;
    }

  client_upstream = z_stream_fd_new(downpair[0], "");
  server_upstream = z_stream_fd_new(uppair[0], "");
  *stacked = z_stacked_proxy_new(client_upstream, server_upstream, NULL, self, z_policy_proxy_get_proxy(res), 0);
  z_policy_var_unref(res);
  
  z_proxy_leave(self);
  return TRUE;
}
Example #21
0
/**
 * telnet_process_buf:
 * @self: 
 * @buf: 
 * @dbuf: 
 * @odbuf: 
 * @ep: 
 *
 * 
 *
 * Returns:
 * 
 */
static gboolean
telnet_process_buf(TelnetProxy *self, ZIOBuffer *buf, ZIOBufferDyn *dbuf, ZIOBufferDyn *odbuf, guint ep)
{
  guint         ptr;
  guint         res;
  guchar        byte;
  ZIOBuffer     *sbuf = &self->suboptions[ep];
  ZIOBuffer     tbuf;

  z_proxy_enter(self);
  z_proxy_trace(self, "telnet_process_buf called side='%s'", WHICH_EP(ep));
  dbuf->ofs = dbuf->end = 0;
  ptr = buf->ofs;
  while (ptr < buf->end)
    {   
      z_proxy_log(self, TELNET_DEBUG, 7, "Processing buffer; state='%d'", self->state[ep]);
      switch (self->state[ep])
        {
        case TELNET_DATA:
          while (ptr < buf->end && buf->buf[ptr] != TELNET_IAC)
            ptr++;
          /* if not in urgent mode, write out data */
          res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs);
                                 
          if (!res)
            {
              z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep)));
              z_proxy_return(self, FALSE);
            }
          else if (ptr >= buf->end)
              buf->ofs = ptr; /* set buffer offset pointer as if data was written */

          if (ptr < buf->end)
            {
              self->state[ep] = TELNET_GOT_IAC;
              ptr++;
            }
          break;

        case TELNET_GOT_IAC:
          self->command[ep] = buf->buf[ptr++];
          /* telnet option negotiation */
          if (self->command[ep] == TELNET_CMD_WILL ||
              self->command[ep] == TELNET_CMD_WONT ||
              self->command[ep] == TELNET_CMD_DO ||
              self->command[ep] == TELNET_CMD_DONT)
            {
              self->state[ep] = TELNET_GOT_OPNEG;
            }
          /* telnet suboption negotiation */
          else if (self->command[ep] == TELNET_CMD_SB)
            {
              self->state[ep] = TELNET_GOT_SB;
            }
          /* telnet datamark */
          else if (self->command[ep] == TELNET_CMD_DATAMARK)
            {
              self->state[ep] = TELNET_DATA;
            }
          /* invalid commands in this state, drop them */
          else if (self->command[ep] == TELNET_CMD_SE)
            {
              self->state[ep] = TELNET_DATA;
              z_proxy_log(self, TELNET_VIOLATION, 2, "Illegal command in stream; command='%d'", self->command[ep]);
            }
          /* else send it to the other side */
          else
            {
              res = telnet_process_command(self, ep);
              self->state[ep] = TELNET_DATA;
              if (res == TELNET_CHECK_OK)
                {
                  res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs);
                  if (!res)
                    {
                      z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep)));
                      z_proxy_return(self, FALSE);
                    }
                }
              else
                {
                  buf->ofs = ptr;
                  z_proxy_log(self, TELNET_VIOLATION, 2, "Illegal command; command='%d'", self->command[ep]);
                }
            }
          z_proxy_log(self, TELNET_DEBUG, 6, "Processing command; state='TELNET_GOT_IAC', cmd='%d'", self->command[ep]);
          break;

        case TELNET_GOT_OPNEG:
          /* get option number from buffer */
          self->opneg_option[ep] = buf->buf[ptr++];
          z_proxy_log(self, TELNET_DEBUG, 6, "Processing option negotiation; state='TELNET_GOT_OPNEG', option='%d'", self->opneg_option[ep]);

          /* check if valid and allowed */
          res = telnet_process_opneg(self, ep);
          switch (res)
            {
            case TELNET_CHECK_OK:
              res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs);
              if (!res)
                {
                  z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep)));
                  z_proxy_return(self, FALSE);
                }
              break;

            case TELNET_CHECK_REJECT:
              /* create a temporary buffer */
              tbuf.ofs = 0; tbuf.end = 3; 
              tbuf.buf[0] = buf->buf[buf->ofs];
              tbuf.buf[1] = buf->buf[buf->ofs + 1];
              tbuf.buf[2] = buf->buf[buf->ofs + 2];
              switch (buf->buf[buf->ofs + 1])
                {
                case TELNET_CMD_WILL:
                  tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_DONT;
                  buf->buf[buf->ofs + 1] = TELNET_CMD_WONT;
                  z_proxy_log(self, TELNET_DEBUG, 6, "WILL rejected;");
                  break;

                case TELNET_CMD_WONT:
                  tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_DONT;
                  z_proxy_log(self, TELNET_DEBUG, 6, "WONT passed through;");
                  break;

                case TELNET_CMD_DO:
                  tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_WONT;
                  buf->buf[buf->ofs + 1] = TELNET_CMD_DONT;
                  z_proxy_log(self, TELNET_DEBUG, 6, "DO rejected;");
                  break;

                case TELNET_CMD_DONT:
                  tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_WONT;
                  z_proxy_log(self, TELNET_DEBUG, 6, "DONT passed through;");
                  break;
                }
              res = telnet_copy_buf(odbuf, &tbuf, tbuf.end);
              if (res)
                res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs);
              if (!res)
                {
                  z_proxy_log(self, TELNET_DEBUG, 6, "Output buffer full; side='%s'", WHICH_EP(ep));
                  z_proxy_return(self, FALSE);
                }
              break;

            case TELNET_CHECK_ABORT:
              z_proxy_log(self, TELNET_POLICY, 2, "Session aborted during option negotiation;");
              z_proxy_return(self, FALSE);

            case TELNET_CHECK_DROP:
            default:
              z_proxy_log(self, TELNET_POLICY, 3, "Option negotiation sequence dropped;");
              break;
            }
          /* next state */
          self->state[ep] = TELNET_DATA;
          break;

        case TELNET_GOT_SB:
          /* get option number from buffer */
          self->opneg_option[ep] = buf->buf[ptr++];
          z_proxy_log(self, TELNET_DEBUG, 6, "Processing suboptions; state='TELNET_GOT_SB', option='%d'", self->opneg_option[ep]);
          /* initialize suboption buffer */
          self->suboptions[ep].ofs = 0; self->suboptions[ep].end = 0;
          self->state[ep] = TELNET_IN_SB;
          break;

        case TELNET_IN_SB:
          /* while not end of buffer and no IAC found */
          while (ptr < buf->end && buf->buf[ptr] != TELNET_IAC)
            {
              /* if the suboption buffer is already full */
              if (sbuf->end == TELNET_SUBOPTION_SIZE)
                {
                  z_proxy_log(self, TELNET_DEBUG, 6, "Suboption buffer full; side='%s'", WHICH_EP(ep));
                  z_proxy_return(self, FALSE);
                }
              /* copy byte to suboption buffer */
              sbuf->buf[sbuf->end++] = buf->buf[ptr++];
            }
          /* if IAC found, next state is TELNET_GOT_SB_IAC */
          if (ptr < buf->end)
            {
              self->state[ep] = TELNET_GOT_SB_IAC;
              ptr++;
            }
          else
            {
              self->state[ep] = TELNET_DATA;
            }
          break;

        case TELNET_GOT_SB_IAC:
          /* if suboption negotiation end found */
          if ((byte = buf->buf[ptr++]) == TELNET_CMD_SE)
            {
              res = telnet_check_suboption(self, ep);
              if (res == TELNET_CHECK_OK)
                {
                  res = telnet_copy_buf(dbuf, buf, 3);
                  if (res) telnet_copy_buf(dbuf, sbuf, sbuf->end - sbuf->ofs);
                  buf->ofs = ptr - 2;
                  if (res) telnet_copy_buf(dbuf, buf, 2);
                  if (!res)
                    {
                      z_proxy_log(self, TELNET_VIOLATION, 6, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep)));
                      z_proxy_leave(self);
                      return FALSE;
                    }
                }
              else
                {
                  z_proxy_log(self, TELNET_POLICY, 3, "Suboption denied by policy;");
                }
              /* data comes... */
              buf->ofs = ptr;
              self->state[ep] = TELNET_DATA;
            }
          /* otherwise it was just suboption data */
          else 
            {
              /* check if there's room for two bytes in suboption  buffer */
              if (sbuf->end + 2 > TELNET_SUBOPTION_SIZE)
                {
                  z_proxy_log(self, TELNET_ERROR, 3, "Suboption buffer full; side='%s'", WHICH_EP(ep));
                  z_proxy_return(self, FALSE);
                }
              /* put two bytes in the buffer */
              sbuf->buf[sbuf->end++] = TELNET_IAC;
              sbuf->buf[sbuf->end++] = byte;
              /* suboption negotiation data follows... */
              self->state[ep] = TELNET_IN_SB;
            }
          break;

        default:
          z_proxy_log(self, TELNET_ERROR, 2, "Internal error, unknown state;");
          z_proxy_return(self, FALSE);
        }
    }
  z_proxy_return(self, TRUE);
}