Esempio n. 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;
}
Esempio n. 2
0
static gboolean
z_proxy_ssl_host_iface_check_wildcard(ZProxy *s, const gchar *host_name, const gchar *pattern)
{
  gchar **pattern_parts, **hostname_parts;
  gboolean success = FALSE;
  gint i;

  z_proxy_log(s, CORE_DEBUG, 6, "Checking certificate subject; host='%s', pattern='%s'", host_name, pattern);
  pattern_parts = g_strsplit(pattern, ".", 0);
  hostname_parts = g_strsplit(host_name, ".", 0);
  for (i = 0; pattern_parts[i]; i++)
    {
      if (!hostname_parts[i])
        {
          /* number of dot separated entries is not the same in the hostname and the pattern spec */
          goto exit;
        }
      if (!g_pattern_match_simple(pattern_parts[i], hostname_parts[i]))
        goto exit;
    }
  if (!hostname_parts[i])       /* if hostname_parts doesn't continue beyond pattern_parts */
    success = TRUE;
 exit:
  g_strfreev(pattern_parts);
  g_strfreev(hostname_parts);
  if (!success)
    {
      z_proxy_log(s, CORE_VIOLATION, 2, "Certificate subject does not match; host='%s', pattern='%s'",
                  host_name, pattern);
    }
  return success;
}
Esempio n. 3
0
/**
 * telnet_process_command:
 * @self: 
 * @ep: 
 *
 * 
 *
 * Returns:
 * 
 */
static guint
telnet_process_command(TelnetProxy *self, guint ep)
{
  ZPolicyObj    *res = NULL;
  guint         option_needed;
  gchar         cmd_str[5];
  guint         ret_status;

  z_proxy_enter(self);
  /* 
   * allow commands defined in RFC 854
   * these are important, and must be implemented
   */
  
  /* NOTE: this triggers a warning in gcc as the second part of the
   * condition is always TRUE as guchar is always less-or-equal than 255,
   * this is true, but I leave the condition intact as in the possible case
   * command is changed to int the condition might be perfectly valid
   */
  if (self->command[ep] >= 240)
    z_proxy_return(self, TELNET_CHECK_OK);
  /* 
   * allow negotiated commands
   * these were allowed during a negotiation
   */
  g_snprintf(cmd_str, sizeof(cmd_str), "%hhu", self->command[ep]);
  z_policy_lock(self->super.thread);
  res = g_hash_table_lookup(self->negotiation, cmd_str);
  if (res != NULL)
    {
      if (!z_policy_var_parse(res, "i", &option_needed))
        {
          z_proxy_log(self, TELNET_POLICY, 2, "Value in negotiation table bad; command='%d'", self->command[ep]);
          z_policy_unlock(self->super.thread);
          z_proxy_return(self, TELNET_CHECK_REJECT); 
        }
      z_proxy_trace(self, "Changed needed negotiated option; command='%s', option='%d'", cmd_str, option_needed);
    }
  else
    {
      option_needed = self->command[ep];
    }
  z_policy_unlock(self->super.thread);
  ret_status = TELNET_CHECK_REJECT;
  if (option_needed == 255)
    {
      ret_status = TELNET_CHECK_OK;
    }
  else if (option_needed > 255)
    {
      z_proxy_log(self, TELNET_POLICY, 2, "Value in negotation table out of range; command='%d', value='%d'", self->command[ep], option_needed);
    }
  else
    {
      z_proxy_trace(self, "Option state check; option='%d', state='%d:%d'", option_needed, self->options[option_needed][ep], self->options[option_needed][OTHER_EP(ep)]);
      if (self->options[option_needed][ep] & (SENT_WILL | GOT_DO))
        ret_status = TELNET_CHECK_OK;
    } /* reject everything else */
  z_proxy_return(self, ret_status);
} 
Esempio n. 4
0
/**
 * finger_query_policy:
 * @self: FingerProxy instance
 *
 * Check the policy about the current request.
 **/
static gboolean
finger_query_policy(FingerProxy *self)
{
    char *errmsg = "Policy violation, request denied.\r\n";
    gsize bytes_written;
    gint res;

    z_proxy_enter(self);
    z_policy_lock(self->super.thread);
    res = z_policy_event(self->super.handler, "fingerRequest", z_policy_var_build("(ss)", self->username->str, self->hostnames->str), self->super.session_id);
    switch (res)
    {
    case FINGER_REQ_UNSPEC:
    case FINGER_REQ_REJECT:
    case FINGER_REQ_ABORT:
        /*LOG
          This message is about administrator decision to reject the
          finger session.
         */
        z_proxy_log(self, FINGER_POLICY, 2, "Policy violation, abort session;");
        z_stream_write(self->super.endpoints[EP_CLIENT],
                       errmsg,
                       strlen(errmsg),
                       &bytes_written,
                       NULL);
    /* fallthrough */

    case FINGER_REQ_DROP:
        if (res == ZV_DROP)
        {
            /*LOG
              This message is about administrator decision to drop
              finger session.
             */
            z_proxy_log(self, FINGER_POLICY, 2, "Policy violation, drop session;");
        }
        z_policy_unlock(self->super.thread);
        z_proxy_return(self, FALSE);

    case FINGER_REQ_ACCEPT:
    default:
        break;
    }
    z_policy_unlock(self->super.thread);
    z_proxy_return(self, TRUE);
}
Esempio n. 5
0
/**
 * http_ftp_login:
 * @self: HttpProxy instance
 * @user: username to log in with
 * @passwd: password for @user
 *
 * Log in to the FTP server using credentials in @user and @passwd.
 **/
static gboolean
http_ftp_login(HttpProxy *self, const gchar *user, const gchar *passwd)
{
  gchar response_msg[1024];
  gint status;

  if (!http_ftp_communicate(self, "USER", user, &status, response_msg, sizeof(response_msg)))
    return FALSE;

  if (status == 230)
    {
      /* no password required */
      return TRUE;
    }
  else if (status != 331)
    {
      /* no password required */
      g_string_sprintf(self->error_info, "Unhandled status code returned to login request (%d, %s)", status, response_msg);
      /*LOG
        This message indicates that the FTP server returned an unknown
        status code in response to our login request.
      */
      z_proxy_log(self, HTTP_ERROR, 4, "FTP server returned an unhandled status code for the login request; ftp_status='%d'", status);
      return FALSE;
    }

  if (!http_ftp_communicate(self, "PASS", passwd, &status, response_msg, sizeof(response_msg)))
    return FALSE;

  if (status == 230)
    {
      /* logged in */
      return TRUE;
    }
  else
    {
      g_string_sprintf(self->error_info, "Error logging in (%d, %s)", status, response_msg);
      /*LOG
        This message indicates that the FTP refused our authentication
        attempt.
      */
      z_proxy_log(self, HTTP_ERROR, 4, "Error logging in; user='******', ftp_status='%d', ftp_response='%s'", user, status, response_msg);
      return FALSE;
    }
}
Esempio n. 6
0
guint
Pop3ParseAPOP(Pop3Proxy *self)
{
  gchar username[self->max_username_length + 1];
  guint i;
  gchar *buf = self->command_param->str;

  z_proxy_enter(self);
  for (i = 0; i < self->max_username_length && buf[i] != 0 && buf[i] != ' '; i++)
    username[i] = buf[i];
  username[i] = 0;

  if (buf[i] != ' ')
    {
      /*LOG
        This message indicates that the username parameter is too long or the digest missing after the
        username and Zorp rejects the request.
       */
      z_proxy_log(self, POP3_REQUEST, 3, "The username parameter is too long or the digest parameter is missing; req='APOP', req_prm='%s'",
                  self->command_param->str);
      z_proxy_return(self, POP3_REQ_REJECT);
    }

  g_string_assign(self->username, username);
  while (buf[i] == 32)
    i++;
  buf = &buf[i];

  for (i = 0; i < 32 && buf[i] != 0 &&
       ((buf[i] >= '0' && buf[i] <= '9') ||
        (buf[i] >= 'a' && buf[i] <= 'f') ||
        (buf[i] >= 'A' && buf[i] <= 'F')); i++)
    ;

  if (i < 32)
    {
      /*LOG
        This message indicates that the MD5 digest parameter of the request is invalid and
        Zorp rejects the request.
       */
      z_proxy_log(self, POP3_REQUEST, 3, "Error parsing the MD5 digest; req='APOP', req_prm='%s'", self->command_param->str);
      z_proxy_return(self, POP3_REQ_REJECT);
    }
  z_proxy_return(self, POP3_REQ_ACCEPT);
}
Esempio n. 7
0
guint
ftp_policy_feature_hash_search(struct _FtpProxy *self, const gchar *feature)
{
  ZPolicyObj *res;
  guint verdict;
  gboolean valid;

  z_proxy_enter(self);

  res = g_hash_table_lookup(self->policy_features, feature);
  if (!res)
    res = g_hash_table_lookup(self->policy_features, "*");

  if (!res)
    {
      /*LOG
        This message indicates that the policy does not contain any setting for the given
        feature and Zorp drops the feature. Check the 'features' attribute.
       */
      z_proxy_log(self, FTP_POLICY, 5, "Policy does not contain this feature, dropping; feature='%s'", feature);
      z_proxy_return(self, FTP_FEATURE_DROP);
    }

  z_policy_lock(self->super.thread);
  valid = ftp_hash_get_type(res, &verdict);
  z_policy_unlock(self->super.thread);

  if (!valid)
    {
      /*LOG
        This message indicates that the policy type is invalid for the given feature and
        thus Zorp drops the feature.
       */
      z_proxy_log(self, FTP_POLICY, 1, "Policy value invalid; feature='%s'", feature);
      z_proxy_return(self, FTP_FEATURE_DROP);
    }

  z_proxy_return(self, verdict);
}
Esempio n. 8
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;
}
Esempio n. 9
0
static inline void
z_transfer2_update_status(ZTransfer2 *self, guint32 status_bit, gint enable)
{
  guint32 old_mask = self->status & ZT2S_EOF_BITS;
  if (enable)
    self->status |= status_bit;
  else
    self->status &= ~status_bit;

  /*LOG
    This message reports that the data-transfer to or from some endpoint is closed.
   */
  z_proxy_log(self->owner, CORE_DEBUG, 7, "Eofmask is updated; old_mask='%04x', eof_mask='%04x'", old_mask, self->status & ZT2S_EOF_BITS);
}
Esempio n. 10
0
guint
Pop3ParseNoarg(Pop3Proxy *self)
{
  z_proxy_enter(self);
  if (self->command_param->len > 0)
    /*LOG
      This message indicates that the request must not have any parameter and Zorp
      is going to drop the parameter.
     */
    z_proxy_log(self, POP3_REQUEST, 4, "Dropping request parameter, no parameter allowed; req='%s', req_prm='%s'",
	self->command->str, self->command_param->str);

  g_string_assign(self->command_param, "");
  z_proxy_return(self, POP3_REQ_ACCEPT);
}
Esempio n. 11
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;
}
Esempio n. 12
0
/**
 * telnet_process_opneg:
 * @self: 
 * @ep: 
 *
 * 
 *
 * Returns:
 * 
 */
static guint
telnet_process_opneg(TelnetProxy *self, guint ep)
{
  guint         res;

  z_proxy_enter(self);
  /*
   * ask policy if option is enabled
   */
  res = telnet_policy_option(self);
  if (res == TELNET_CHECK_OK)
    {
      switch (self->command[ep])   
        {
        case TELNET_CMD_WILL:
          /* set flag which means this side has sent a WILL */
          self->options[self->opneg_option[ep]][ep] |= SENT_WILL;
          break;

        case TELNET_CMD_WONT:
          /* set flag which means this side has sent a WONT */
          self->options[self->opneg_option[ep]][ep] &= ~GOT_DO;
          break;

        case TELNET_CMD_DO:
          /* set the other side's flag, indicating that
           * its WILL was accepted by the other side */
          self->options[self->opneg_option[ep]][OTHER_EP(ep)] |= GOT_DO;
          break;

        case TELNET_CMD_DONT:
          /* clear the other side's WILL flag, indicating that
           * its WILL was refused */
          self->options[self->opneg_option[ep]][OTHER_EP(ep)] &= ~SENT_WILL;
          break;

        default:
          z_proxy_log(self, TELNET_VIOLATION, 2, "Unknown command; command='%d'", self->command[ep]);
          break;
        }
    }
  z_proxy_return(self, res);
}
Esempio n. 13
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;
}
Esempio n. 14
0
static gboolean
z_proxy_stack_tuple(ZProxy *self, ZPolicyObj *tuple, ZStackedProxy **stacked, ZPolicyDict *stack_info_dict)
{
  guint stack_method;
  ZPolicyObj *arg = NULL;
  gboolean success = FALSE;
  
  if (!z_policy_tuple_get_verdict(tuple, &stack_method) ||
      z_policy_seq_length(tuple) < 2)
    goto invalid_tuple;

  arg = z_policy_seq_getitem(tuple, 1);
  switch (stack_method)
    {
    case Z_STACK_PROXY:
      if (z_policy_seq_length(tuple) != 2)
        goto invalid_tuple;

      success = z_proxy_stack_proxy(self, arg, stacked, stack_info_dict);
      break;
    case Z_STACK_PROGRAM:
      if (!z_policy_str_check(arg))
        goto invalid_tuple;

      success = z_proxy_stack_program(self, z_policy_str_as_string(arg), stacked);
      break;

    default:
      break;
    }
    
 exit:
  if (arg)
    z_policy_var_unref(arg);
  return success;

 invalid_tuple:
  z_proxy_log(self, CORE_POLICY, 1, "Invalid stack tuple;");
  success = FALSE;
  goto exit;
}
Esempio n. 15
0
guint
Pop3ParsePASS(Pop3Proxy *self)
{
  gchar password[self->max_password_length + 1];

  z_proxy_enter(self);
  if (self->command_param->len <= self->max_password_length)
    {
      g_strlcpy(password, self->command_param->str, self->max_password_length + 1);
      g_string_assign(self->password, password);
      z_proxy_return(self, POP3_REQ_ACCEPT);
    }

  /*LOG
    This message indicates that the password parameter of the request is too long and Zorp
    rejects the request. Check the 'max_password_length' attribute.
   */
  z_proxy_log(self, POP3_POLICY, 2, "Password is too long; max_password_length='%d', password_length='%d'",
              self->max_password_length, (gint) self->command_param->len);
  z_proxy_return(self, POP3_REQ_REJECT);
}
Esempio n. 16
0
guint
Pop3ParseUSER(Pop3Proxy *self)
{
  gchar username[self->max_username_length + 1];

  z_proxy_enter(self);
  if (self->command_param->len <= self->max_username_length)
    {
      g_strlcpy(username, self->command_param->str, self->max_username_length + 1);
      g_string_assign(self->username, username);
      z_proxy_return(self, POP3_REQ_ACCEPT);
    }

  /*LOG
    This message indicates that the username parameter of the request is too long and Zorp
    rejects the request. Check the 'max_username_length' attribute.
   */
  z_proxy_log(self, POP3_POLICY, 2, "Username is too long; max_username_length='%d', username_length='%" G_GSIZE_FORMAT "', username='******'",
              self->max_username_length, self->command_param->len, self->command_param->str);
  z_proxy_return(self, POP3_REQ_REJECT);
}
Esempio n. 17
0
/**
 * telnet_check_suboption:
 * @self: 
 * @ep: 
 *
 * 
 *
 * Returns:
 * 
 */
static guint
telnet_check_suboption(TelnetProxy *self, guint ep)
{
  guint                 res;
  TelnetOptionFunction  check_func;
  ZIOBuffer             *sbuf = &self->suboptions[ep];
  gchar                 buf[TELNET_BUFFER_SIZE + 1];
  guint                 i, j;

  z_proxy_enter(self);
  /* check if allowed in this session */
  if (!(self->options[self->opneg_option[ep]][OTHER_EP(ep)] & (SENT_WILL | GOT_DO)) &&
      !(self->options[self->opneg_option[ep]][ep] & (SENT_WILL | GOT_DO)))
    {
      z_proxy_log(self, TELNET_VIOLATION, 3, "Option not allowed in the session; option='%d'", self->opneg_option[ep]);
      z_proxy_return(self, TELNET_CHECK_ABORT);
    }

  /* check if valid */
  if ((check_func = self->telnet_options[self->opneg_option[ep]]) == NULL)
    {
      /* option has no suboption check function */
      /* copy suboption negotiation buffer into policy_value */
      for (j = 0, i = sbuf->ofs; i < sbuf->end; j++, i++)
          buf[j] = sbuf->buf[i];
      g_string_assign(self->policy_name, "");
      g_string_assign(self->policy_value, buf);
      /* call policy check */
      res = telnet_policy_suboption(self, (guchar) buf[0], "", buf);
    }
  else
    {
      /* call check function, and check function calls policy */
      res = check_func(self, ep);
    }
  z_proxy_return(self, res);
}
Esempio n. 18
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;
}
Esempio n. 19
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;
}
Esempio n. 20
0
gboolean
pop3_data_transfer(Pop3Proxy *owner)
{
  Pop3Transfer *t;
  GString *preamble;
  gboolean success;
  gchar buf[256];

  z_proxy_enter(owner);
  preamble = g_string_new(owner->response->str);
  if (owner->response_param->len)
    {
      g_string_append_c(preamble, ' ');
      g_string_append(preamble, owner->response_param->str);
    }
  g_string_append(preamble, "\r\n");
  t = Z_CAST(z_dot_transfer_new(Z_CLASS(Pop3Transfer),
                                &owner->super, owner->poll,
                                owner->super.endpoints[EP_SERVER], owner->super.endpoints[EP_CLIENT],
                                owner->buffer_length,
                                owner->timeout,
                                ZT2F_COMPLETE_COPY | ZT2F_PROXY_STREAMS_POLLED,
                                preamble),
             Pop3Transfer);
  z_transfer2_set_content_format(&t->super.super, "email");

  z_stream_line_set_nul_nonfatal(owner->super.endpoints[EP_SERVER], TRUE);
  if (owner->policy_enable_longline)
    z_stream_line_set_split(owner->super.endpoints[EP_SERVER], TRUE);

  success = z_transfer2_simple_run(&t->super.super);
  z_stream_line_set_split(owner->super.endpoints[EP_SERVER], FALSE);
  z_stream_line_set_nul_nonfatal(owner->super.endpoints[EP_SERVER], FALSE);
  if (t->super.dst_write_state == DOT_DW_PREAMBLE)
    {
      /* nothing was written to destination */
      switch (z_transfer2_get_stack_decision(&t->super.super))
        {
        case ZV_REJECT:
	  /*LOG
	    This message indicates that the stacked proxy rejected the content and Zorp
	    rejects the response.
	   */
          z_proxy_log(owner, POP3_ERROR, 2, "Stacked proxy rejected contents; info='%s'", z_transfer2_get_stack_info(&t->super.super));
          g_snprintf(buf, sizeof(buf), "Content rejected (%s)", z_transfer2_get_stack_info(&t->super.super));
          if (owner->reject_by_mail)
            pop3_error_msg(owner, buf);
          else
            pop3_response_reject(owner, buf);
          break;

        case ZV_ERROR:
          g_snprintf(buf, sizeof(buf), "Error occurred while transferring data (%s)", z_transfer2_get_stack_info(&t->super.super));
          pop3_response_reject(owner, buf);
          owner->pop3_state = POP3_STATE_QUIT;
          break;

        default:
          pop3_response_write(owner);
          pop3_write_client(owner, ".\r\n");
          break;
        }
    }
  else
    {
      pop3_write_client(owner, ".\r\n");
    }

  if (owner->from)
    {
      g_string_free(owner->from, TRUE);
      owner->from = NULL;
    }

  if (owner->to)
    {
      g_string_free(owner->to, TRUE);
      owner->to = NULL;
    }

  if (owner->subject)
    {
      g_string_free(owner->subject, TRUE);
      owner->subject = NULL;
    }

  z_object_unref(&t->super.super.super);
  z_proxy_return(owner, success);
}
Esempio n. 21
0
/**
 * finger_send_request:
 * @self: FingerProxy instance
 *
 * Construct and send a request to the server based on the state
 * stored by finger_fetch_request().
 **/
static gboolean
finger_send_request(FingerProxy *self)
{
    gchar request[self->username->len + self->hostnames->len + 6];
    gsize bytes_written;

    z_proxy_enter(self);
    if (self->long_req)
    {
        if (self->username->len > 0)
        {
            if (self->hostnames->len > 0)
                g_snprintf(request, sizeof(request), "/W %s%s\r\n",
                           self->username->str,
                           self->hostnames->str);
            else
                g_snprintf(request, sizeof(request), "/W %s\r\n",
                           self->username->str);
        }
        else
        {
            if (self->hostnames->len > 0)
                g_snprintf(request, sizeof(request), "/W %s\r\n",
                           self->hostnames->str);
            else
                g_snprintf(request, sizeof(request), "/W\r\n");
        }
    }
    else
    {
        if (self->username->len > 0)
        {
            if (self->hostnames->len > 0)
                g_snprintf(request, sizeof(request), "%s%s\r\n",
                           self->username->str,
                           self->hostnames->str);
            else
                g_snprintf(request, sizeof(request), "%s\r\n",
                           self->username->str);
        }
        else
        {
            if (self->hostnames->len > 0)
                g_snprintf(request, sizeof(request), "%s\r\n",
                           self->hostnames->str);
            else
                g_snprintf(request, sizeof(request), "\r\n");
        }
    }

    if (z_stream_write(self->super.endpoints[EP_SERVER],
                       request,
                       strlen(request),
                       &bytes_written,
                       NULL) != G_IO_STATUS_NORMAL)
    {
        /*LOG
          This message appear when some error
          found in server side.
         */
        z_proxy_log(self, FINGER_ERROR, 1, "Error write request;");
        z_proxy_return(self, FALSE);
    }
    z_proxy_return(self, TRUE);
}
Esempio n. 22
0
static GIOStatus
http_transfer_src_read(ZTransfer2 *s, ZStream *stream, gchar *buf, gsize count, gsize *bytes_read, GError **err)
{
  HttpTransfer *self = Z_CAST(s, HttpTransfer);
  HttpProxy *owner = Z_CAST(s->owner, HttpProxy);
  GError *local_error = NULL;
  gsize br;
  GIOStatus res = G_IO_STATUS_NORMAL;

  if (self->src_read_state == HTTP_SR_INITIAL)
    self->src_read_state = HTTP_SR_PUSH_HEADERS;

  if (self->src_read_state >= HTTP_SR_PUSH_HEADERS && self->src_read_state <= HTTP_SR_PUSH_HEADERS_MAX)
    {
      if (self->push_mime_headers && self->stacked_preamble->len > 0)
        {
          gint move;

          *bytes_read = 0;

          move = MIN(count, self->stacked_preamble->len - self->stacked_preamble_ofs);
          memmove(buf, self->stacked_preamble->str + self->stacked_preamble_ofs, move);
          self->stacked_preamble_ofs += move;
          *bytes_read = move;

          if (self->stacked_preamble_ofs == self->stacked_preamble->len)
            {
              z_transfer2_set_proxy_out(s, FALSE);
              self->src_read_state = HTTP_SR_READ_INITIAL;
            }

          return G_IO_STATUS_NORMAL;
        }
      else
        {
          self->src_read_state = HTTP_SR_READ_INITIAL;
        }
    }

  *bytes_read = 0;

  if (self->src_chunked)
    {
      /* read as a chunked stream */
      switch (self->src_read_state)
        {
        case HTTP_SR_READ_INITIAL:
          self->src_whole_length = 0;
          self->src_read_state = HTTP_SR_READ_CHUNK_LENGTH;
          z_stream_line_set_poll_partial(stream, FALSE);
          /* fallthrough */
        case HTTP_SR_READ_CHUNK_LENGTH:
          {
            gchar line_buf[32], *line;
            gsize line_length;
            guint32 chunk_length;
            gchar *end;

            res = z_stream_line_get(stream, &line, &line_length, NULL);

            if (res == G_IO_STATUS_NORMAL)
              {
                /* a complete line was read, check if it is a valid chunk length */
                if (line_length >= sizeof(line_buf) - 1)
                  {
                    /*LOG
                      This message indicates that the chunk length line is too long.
                      It is likely caused by a buggy client or server.
                    */
                    z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Chunk length line too long; line='%.*s'", (gint) line_length, line);
                    res = G_IO_STATUS_ERROR;
                    break;
                  }

                /* we already checked that line_buf is large enough */
                memcpy(line_buf, line, line_length);
                line_buf[line_length] = 0;
                chunk_length = strtoul(line_buf, &end, 16);

                if (end == line_buf)
                  {
                    /* hmm... invalid chunk length */
                    /*LOG
                      This message indicates that the chunk length is invalid.
                      It is likely caused by a buggy client or server.
                    */
                    z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Invalid chunk length; line='%s'", line_buf);
                    res = G_IO_STATUS_ERROR;
                    break;
                  }

                /*
                 * NOTE: the string  pointed by end is NUL terminated, thus
                 * we will not overflow our buffer
                 */

                while (*end == ' ')
                  end++;

                if (*end == ';')
                  {
                    /* ignore and strip chunk extensions */
                    *end = 0;
                  }

                if (*end)
                  {
                    /* hmm... invalid chunk length */
                    /*LOG
                      This message indicates that the chunk length is invalid.
                      It is likely caused by a buggy client or server.
                    */
                    z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Invalid chunk length; line='%s'", line_buf);
                    res = G_IO_STATUS_ERROR;
                    break;
                  }

                if ((owner->max_chunk_length && chunk_length > owner->max_chunk_length) ||
                    (chunk_length & 0x80000000))
                  {
                    /*LOG
                      This message indicates that the length of the chunk is larger than allowed
                      or is a negative number. Check the 'max_chunk_length' attribute.
                    */
                    z_proxy_log(self->super.owner, HTTP_POLICY, 2, "Chunk too large; length='%d', max_chunk_length='%d'", chunk_length, owner->max_chunk_length);
                    res = G_IO_STATUS_ERROR;
                    break;
                  }

                if (owner->max_body_length && (guint) self->src_whole_length + chunk_length > owner->max_body_length)
                  {
                    /* this chunk would be over body_length limit */

                    chunk_length = owner->max_body_length - self->src_whole_length;
                    self->src_chunk_left = chunk_length;
                    self->force_nonpersistent_mode = TRUE;
                    self->src_chunk_truncated = TRUE;
                  }

                self->src_chunk_left = chunk_length;
                self->src_last_chunk = chunk_length == 0;
                self->src_read_state = HTTP_SR_READ_CHUNK;
                z_stream_line_set_poll_partial(stream, TRUE);
                /* fall through */
              }
            else
              break;
          }
        case HTTP_SR_READ_CHUNK:

          if (!self->src_last_chunk)
            {
              res = z_stream_read(stream, buf, MIN(self->src_chunk_left, count), &br, &local_error);

              if (res == G_IO_STATUS_NORMAL)
                {
                  self->src_whole_length += br;
                  self->src_chunk_left -= br;
                  *bytes_read = br;
                }
              else if (res == G_IO_STATUS_EOF)
                {
                  /* unexpected eof */
                  /*LOG
                    This message indicates that Zorp unexpectedly got EOF during
                    chunk encoded data transfer. It is likely a caused by a buggy client
                    or server.
                  */
                  z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Unexpected EOF while dechunking stream;");
                  res = G_IO_STATUS_ERROR;
                  break;
                }

              if (self->src_chunk_left == 0)
                {
                  self->src_read_state = HTTP_SR_READ_FOOTER;
                  z_stream_line_set_poll_partial(stream, FALSE);
                }

              break;
            }
          else
            {
              self->src_read_state = HTTP_SR_READ_FOOTER;
              z_stream_line_set_poll_partial(stream, FALSE);
              /* fallthrough */
            }

        case HTTP_SR_READ_FOOTER:
          {
            gchar *line;
            gsize line_length;

            if (!self->src_chunk_truncated)
              {
                res = z_stream_line_get(stream, &line, &line_length, NULL);
              }
            else
              {
                res = G_IO_STATUS_EOF;
              }

            if (res == G_IO_STATUS_NORMAL)
              {
                if (line_length != 0)
                  {
                    /*LOG
                      This message indicates that the chunk footer contains data.
                      It is likely caused by a buggy client or server.
                    */
                    z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Chunk footer is not an empty line;");
                    res = G_IO_STATUS_ERROR;
                    break;
                  }

                if (self->src_last_chunk)
                  {
                    res = G_IO_STATUS_EOF;
                  }
                else
                  {
                    self->src_read_state = HTTP_SR_READ_CHUNK_LENGTH;
                    z_stream_line_set_poll_partial(stream, TRUE);
                    /* come back later */
                    res = G_IO_STATUS_AGAIN;
                  }

                break;
              }

            break;
          }
        }
    }
  else
    {
      /* copy until EOF or self->content_length bytes */
      if (self->content_length == HTTP_LENGTH_NONE)
        {
          res = G_IO_STATUS_EOF;
        }
      else
        {
          if (self->src_read_state == HTTP_SR_INITIAL)
            {
              self->src_whole_length = 0;
              self->src_read_state = HTTP_SR_READ_ENTITY;
            }

          if (self->content_length == HTTP_LENGTH_UNKNOWN)
            {
              if (owner->max_body_length && self->src_whole_length + count >= owner->max_body_length)
                {
                  count = owner->max_body_length - self->src_whole_length;
                }

              if (count == 0)
                {
                  self->force_nonpersistent_mode = TRUE;
                  res = G_IO_STATUS_EOF;
                }
              else
                res = z_stream_read(stream, buf, count, &br, &local_error);
            }
          else
            {
              /* for specified content-length, max_body_length has already
                 been processed, and content_length contains the number of
                 bytes to be transferred, but maximum max_body_length */
              if (self->content_length >= 0 && (guint64) self->content_length == self->src_whole_length)
                res = G_IO_STATUS_EOF;
              else
                res = z_stream_read(stream, buf, MIN(count, self->content_length - self->src_whole_length), &br, &local_error);
            }

          if (res == G_IO_STATUS_NORMAL)
            {
              self->src_whole_length += br;
              *bytes_read = br;
            }
        }
    }

  if (local_error)
    g_propagate_error(err, local_error);

  return res;
}
Esempio n. 23
0
/**
 * finger_fetch_request:
 * @self: FingerProxy instance
 *
 * Read and process a request.
 **/
static gboolean
finger_fetch_request(FingerProxy *self)
{
    gchar *p, *line;
    gint left, hop_count;
    gsize line_length;
    gint res;
    gboolean fetch_user = TRUE;
    guint hostlen = 0;

    z_proxy_enter(self);
    res = z_stream_line_get(self->super.endpoints[EP_CLIENT], &line, &line_length, NULL);
    if (res != G_IO_STATUS_NORMAL)
    {
        /*LOG
          This message is appears when zorp cannot read finger request
         */
        z_proxy_log(self, FINGER_ERROR, 1, "Error reading request;");
        z_proxy_return(self, FALSE);
    }

    /*LOG
      This message is say about read finger request
     */
    z_proxy_log(self, FINGER_REQUEST, 6, "Request details; req='%.*s'", (gint) line_length, line);
    p = line;
    left = line_length;
    self->long_req = FALSE;
    while (*p == ' ' && left)
    {
        p++;
        left--;
    }
    if (*p == '/')
    {
        p++;
        left--;
        if (*p == 'W')
        {
            self->long_req = TRUE;
            p++;
            left--;
        }
        else
        {
            /*LOG
              This message appear when zorp cannot parse request
             */
            z_proxy_log(self, FINGER_VIOLATION, 1, "Parse error, dropping request; req='%.*s'", (gint) line_length, line);
            z_proxy_return(self, FALSE);
        }
    }
    while (*p == ' ' && left)
    {
        p++;
        left--;
    }
    hop_count = 0;
    g_string_truncate(self->username, 0);
    g_string_truncate(self->hostnames, 0);
    while (*p && left)
    {
        if (*p == '@')
        {
            if (self->max_hop_count != -1)
            {
                hop_count++;
                if (hop_count > self->max_hop_count)
                    break;
            }
            fetch_user = FALSE;
            hostlen = 0;
        }
        if (self->strict_username_check &&
                !(isalnum(*p) || *p == '_' || *p == '@' || *p == '.' || *p == '-'))
        {
            /*LOG
              This message say that zorp found an invalid character
              in finger request.
             */
            z_proxy_log(self, FINGER_VIOLATION, 1, "Invalid character, dropping request; line='%.*s'", (gint) line_length, line);
            z_proxy_return(self, FALSE);
        }
        if (fetch_user)
        {
            g_string_append_c(self->username, *p);
            if (self->username->len > self->max_username_length)
            {
                /*LOG
                  This message is about too long username found
                  in the request.
                 */
                z_proxy_log(self, FINGER_VIOLATION, 1, "Username too long, dropping request; line='%.*s'", (gint) line_length, line);
                z_proxy_return(self, FALSE);
            }
        }
        else
        {
            g_string_append_c(self->hostnames, *p);
            if (hostlen > self->max_hostname_length)
            {
                /*LOG
                  This message is appear when a too long hostname found
                  in the request horname chain.
                 */
                z_proxy_log(self, FINGER_VIOLATION, 1, "One hostname is too long in hostname chain, dropping request; req='%.*s'", (gint) line_length, line);
                z_proxy_return(self, FALSE);
            }
            hostlen++;
        }
        p++;
        left--;
    }
    z_proxy_return(self, TRUE);
}
Esempio n. 24
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);
}
Esempio n. 25
0
/**
 * finger_copy_response:
 * @self: FingerProxy instance
 *
 * Copy server's response to the client.
 *
 **/
static gboolean
finger_copy_response(FingerProxy *self)
{
    gsize bytes_written;
    gint res = G_IO_STATUS_ERROR;

    z_proxy_enter(self);
    if (self->response_header->len &&
            z_stream_write(self->super.endpoints[EP_CLIENT],
                           self->response_header->str,
                           self->response_header->len,
                           &bytes_written,
                           NULL) != G_IO_STATUS_NORMAL)
    {
        /*LOG
          This message appear when some error
          found in client side when writting the header.
         */
        z_proxy_log(self, FINGER_ERROR, 1, "Error write request;");
        z_proxy_return(self, FALSE);
    }

    while (1)
    {
        gchar *line;
        gsize line_len;
        gchar *response;

        if (!z_proxy_loop_iteration(&self->super))
            break;

        res = z_stream_line_get(self->super.endpoints[EP_SERVER], &line, &line_len, NULL);
        if (res != G_IO_STATUS_NORMAL)
            /* EOF or read error */
            break;

        response = alloca(line_len + 3);
        memcpy(response, line, line_len);
        strcpy(response + line_len, "\r\n");
        if (z_stream_write(self->super.endpoints[EP_CLIENT],
                           response,
                           line_len + 2,
                           &bytes_written,
                           NULL) != G_IO_STATUS_NORMAL)
        {
            /*LOG
              This message appear when some error
              found in client side when writting the response.
             */
            z_proxy_log(self, FINGER_ERROR, 1, "Error write request;");
            z_proxy_return(self, FALSE);
        }

    }
    if (res != G_IO_STATUS_ERROR &&
            self->response_footer->len &&
            z_stream_write(self->super.endpoints[EP_CLIENT],
                           self->response_footer->str,
                           self->response_footer->len,
                           &bytes_written,
                           NULL) != G_IO_STATUS_NORMAL)
    {
        /*LOG
          This message appear when some error
          found in client side when writting the footer.
         */
        z_proxy_log(self, FINGER_ERROR, 1, "Error write request;");
        z_proxy_return(self, FALSE);
    }
    z_proxy_return(self, TRUE);
}
Esempio n. 26
0
/**
 * telnet_forward:
 * @self: 
 * @from: 
 * @to: 
 * @ep: 
 *
 * 
 *
 * Returns:
 * 
 */
static gboolean
telnet_forward(TelnetProxy *self, ZStream *from, ZStream *to, guint ep)
{
  ZIOBuffer       *buf = &self->read_buffers[ep];
  ZIOBufferDyn    *dbuf = &self->write_buffers[OTHER_EP(ep)];
  ZIOBufferDyn    *odbuf = &self->write_buffers[ep];
  guint           maxiter = 5;
  GIOStatus       res;
  gboolean        rc;

  z_proxy_enter(self);
  from->want_read = FALSE;
  /* write any pending data in output buffer */
  to->want_write = FALSE;
  res = telnet_stream_write(self, dbuf, OTHER_EP(ep));
  if (res != G_IO_STATUS_NORMAL)
    z_proxy_return(self, res == G_IO_STATUS_AGAIN);

  /* read and write */
  while (maxiter)
    {
      maxiter--;
      if (buf->ofs != buf->end)
        memmove(buf->buf, buf->buf + buf->ofs, buf->end - buf->ofs);
      buf->end -= buf->ofs;
      buf->ofs = 0;

      res = telnet_stream_read(self, buf, ep);
      if (res == G_IO_STATUS_NORMAL)
        {
          /* process buffer */
          rc = telnet_process_buf(self, buf, dbuf, odbuf, ep);
          if (!rc)
            z_proxy_return(self, FALSE);
          /* write output buffer */
          if (!from->want_write)
            {
              res = telnet_stream_write(self, odbuf, ep);
              if (res != G_IO_STATUS_NORMAL && res != G_IO_STATUS_AGAIN)
                z_proxy_return(self, FALSE);
            }
          res = telnet_stream_write(self, dbuf, OTHER_EP(ep));
          if (res == G_IO_STATUS_AGAIN)
            break;
          else if (res != G_IO_STATUS_NORMAL)
            z_proxy_return(self, FALSE);
        }
      else if (res == G_IO_STATUS_AGAIN)
        {
          break;
        }
      else if (res == G_IO_STATUS_EOF)
        {
          z_proxy_log(self, TELNET_DEBUG, 6, "Connection closed by peer; side='%s'", WHICH_EP(ep));
          z_proxy_return(self, FALSE);
        }
      else if (res == G_IO_STATUS_ERROR)
        {
          z_proxy_return(self, FALSE);
        }
    }

  /* check if output buffer is empty */
  if (dbuf->ofs == dbuf->end)
    from->want_read = TRUE;
  z_proxy_return(self, TRUE);
}
Esempio n. 27
0
/**
 * finger_main:
 * @s: FingerProxy instance
 *
 * main proxy routine.
 **/
static void
finger_main(ZProxy *s)
{
    FingerProxy *self = Z_CAST(s, FingerProxy);

    z_proxy_enter(self);
    if (!finger_init_client_stream(self))
        z_proxy_return(self);

    /*LOG
      This debug message is about proxy state when start to
      fetching request
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "fetching request;");
    if (!finger_fetch_request(self))
    {
        char *errmsg = "Finger protocol or disallowed protocol element, request denied.\r\n";
        gsize bytes_written;

        z_stream_write(self->super.endpoints[EP_CLIENT],
                       errmsg,
                       strlen(errmsg),
                       &bytes_written,
                       NULL);
        z_proxy_return(self);
    }

    /*LOG
      This debug message is about proxy state when finger
      fetched request and asking policy about it
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "asking policy;");
    if (!finger_query_policy(self))
        z_proxy_return(self);

    /*LOG
      This debug message is about proxy state when finger
      start connect to server.
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "connecting server;");
    /* this sets the server side endpoint if successful */
    if (!z_proxy_connect_server(&self->super, NULL, 0))
        z_proxy_return(self);

    if (!finger_init_server_stream(self))
        z_proxy_return(self);

    /*LOG
      This debug message is about proxy state when finger
      start send the request to server.
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "sending request;");
    if (!finger_send_request(self))
        z_proxy_return(self);

    /*LOG
      This debug message is about proxy state when finger
      start to copy server answer to client.
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "copying response;");
    if (!finger_copy_response(self))
        z_proxy_return(self);

    /*LOG
      This debug message is about proxy state when finger
      stop it's work.
     */
    z_proxy_log(self, FINGER_DEBUG, 6, "everything is done;");
    z_proxy_return(self);

}
Esempio n. 28
0
/**
 * telnet_policy_suboption:
 * @self: 
 * @command: 
 * @name: 
 * @value: 
 *
 * 
 *
 * Returns:
 * 
 */
guint
telnet_policy_suboption(TelnetProxy *self, guchar command, gchar *name, gchar *value)
{
  guint         res;
  ZPolicyObj    *pol_res;
  ZPolicyObj    *tmp;
  ZPolicyObj    *command_where = NULL;
  guint         command_do;
  gchar         lookup_str[2][10];
  gchar         *keys[2];
  gboolean      type_found;

  z_proxy_enter(self);
  z_proxy_log(self, TELNET_DEBUG, 8, "Policy suboption negotiation check;");
  g_snprintf(lookup_str[0], sizeof(lookup_str[0]), "%d", self->opneg_option[self->ep]);
  g_snprintf(lookup_str[1], sizeof(lookup_str[1]), "%d", command);
  keys[0] = lookup_str[0];
  keys[1] = lookup_str[1];
  tmp = z_dim_hash_table_search(self->telnet_policy, 2, keys);
  if (!tmp)
    {
      z_proxy_log(self, TELNET_POLICY, 1, "Option not found in policy hash, dropping; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
      z_proxy_return(self, TELNET_CHECK_DROP);
    }

  z_policy_lock(self->super.thread);
  type_found = telnet_hash_get_type(tmp, &command_do);
  z_policy_unlock(self->super.thread);
  if (!type_found)
    {
      z_proxy_log(self, TELNET_POLICY, 2, "Policy type invalid!");
      z_proxy_return(self, TELNET_CHECK_ABORT);
    }

  switch (command_do)
    {
    case TELNET_OPTION_DROP:
      z_proxy_log(self, TELNET_POLICY, 6, "Policy denied suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
      res = TELNET_CHECK_DROP;
      break;

    case TELNET_OPTION_ACCEPT:
      z_proxy_log(self, TELNET_POLICY, 6, "Policy accepted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
      res = TELNET_CHECK_OK;
      break;

    case TELNET_OPTION_POLICY:
      z_policy_lock(self->super.thread);
      if (!z_policy_var_parse(tmp, "(iO)", &command_do, &command_where))
        {
          z_proxy_log(self, TELNET_POLICY, 2, "Cannot parse policy line for option; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
          res = TELNET_CHECK_ABORT;
        }
      else 
        {
          /* call Python method with appropriate parameters */
          switch (self->opneg_option[self->ep])
            {
            case TELNET_OPTION_TERMINAL_TYPE:
            case TELNET_OPTION_TERMINAL_SPEED:
            case TELNET_OPTION_X_DISPLAY_LOCATION:
            case TELNET_OPTION_ENVIRONMENT:
            case TELNET_OPTION_NAWS:
              pol_res = z_policy_call_object(command_where, z_policy_var_build("(iss)", &self->opneg_option[self->ep], name, value), self->super.session_id);
              break;

            default:
              pol_res = z_policy_call_object(command_where, z_policy_var_build("(i)", &self->opneg_option[self->ep]), self->super.session_id);
              break;
            }

          if (pol_res == NULL)
            {
              z_proxy_log(self, TELNET_POLICY, 2, "Error in policy calling; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
              res = TELNET_CHECK_ABORT;
            }
          else if (!z_policy_var_parse(pol_res, "i", &res))
            {
              z_proxy_log(self, TELNET_POLICY, 2, "Can't parse return verdict; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
              res = TELNET_CHECK_ABORT;
            }
          else
            {
              switch (res)
                {
                case ZV_ACCEPT:
                  z_proxy_log(self, TELNET_POLICY, 6, "Policy function accepted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
                  res = TELNET_CHECK_OK;
                  break;

                case ZV_UNSPEC:
                case ZV_REJECT:
                case ZV_DROP:
                  z_proxy_log(self, TELNET_POLICY, 3, "Policy function denied suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
                  res = TELNET_CHECK_DROP;
                  break;

                case ZV_ABORT:
                default:
                  z_proxy_log(self, TELNET_POLICY, 3, "Policy function aborted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
                  res = TELNET_CHECK_ABORT;
                  break;
                }
            }
        }
      z_policy_unlock(self->super.thread);
      break;

    case TELNET_OPTION_ABORT:
    default:
      z_proxy_log(self, TELNET_POLICY, 3, "Policy aborted session; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]);
      res = TELNET_CHECK_ABORT;
      break;
    }
  z_proxy_return(self, res);
}
Esempio n. 29
0
/**
 * http_ftp_fetch_response:
 * @self: HttpProxy instance
 * @status: returned FTP status code
 * @msg: returned FTP message
 * @msglen: size of the @msg buffer
 *
 * This function is called to fetch a response from the FTP server. Line
 * continuations are supported however only the first line will be returned
 * in @msg.
 **/
static gboolean
http_ftp_fetch_response(HttpProxy *self, gint *status, gchar *msg, gsize msglen)
{
  gchar *line;
  gsize length;
  gboolean continuation = TRUE, first = TRUE;
  gint mul, value, i;

  msg[0] = 0;

  while (continuation)
    {
      if (z_stream_line_get(self->super.endpoints[EP_SERVER], &line, &length, NULL) != G_IO_STATUS_NORMAL)
        return FALSE;

      if (length < 4)
        {
          /*LOG
            This message indicates that the response given by the FTP server
            was too short, not even the mandatory status code was included.
          */
          z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, line too short; line='%.*s'", (gint)length, line);
          return FALSE;
        }

      value = 0;
      mul = 100;

      for (i = 0; i < 3; i++)
        {
          if (!isdigit(line[i]))
            {
              /*LOG
                This message indicates that the FTP server gave an invalid
                response, the status code returned by the server was not
                numeric.
              */
              z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, response code not numeric; line='%.*s'", (gint)length, line);
              return FALSE;
            }

          value = value + mul * (line[i] - '0');
          mul = mul / 10;
        }

      if (first)
        {
          gint copy = MIN(msglen - 1, length - 4 + 1);

          *status = value;
          memcpy(msg, &line[4], copy);
          msg[copy] = 0;
        }
      else if (*status != value)
        {
          /*LOG
            This message indicates that the FTP server gave an invalid response as the
            status code changed from the one which was present on the first line.
          */
          z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, continuation line contains different status code; ftp_status='%d', line='%.*s'", *status, (gint)length, line);
          return FALSE;
        }

      continuation = line[3] == '-';

    }

  return TRUE;
}
Esempio n. 30
0
/**
 * telnet_policy_option:
 * @self: 
 *
 * 
 *
 * Returns:
 * 
 */
guint
telnet_policy_option(TelnetProxy *self)
{
  guint         res;
  ZPolicyObj    *pol_res;
  ZPolicyObj    *tmp;
  ZPolicyObj    *command_where = NULL;
  guint         command_do;
  gchar         lookup_str[10];
  gchar         *keys[1];
  gboolean      type_found;

  z_proxy_enter(self);
  z_proxy_log(self, TELNET_DEBUG, 8, "Policy option negotiation check; option='%d'", self->opneg_option[self->ep]);
  g_snprintf(lookup_str, sizeof(lookup_str), "%d", self->opneg_option[self->ep]);
  keys[0] = lookup_str;
  tmp = z_dim_hash_table_search(self->telnet_policy, 1, keys);
  if (!tmp)
    {
      z_proxy_log(self, TELNET_POLICY, 2, "Option not found in policy; option='%s'", lookup_str);
      z_proxy_return(self, TELNET_CHECK_DROP);
    }

  z_policy_lock(self->super.thread);
  type_found = telnet_hash_get_type(tmp, &command_do);
  z_policy_unlock(self->super.thread);
  if (!type_found )
    {
      z_proxy_log(self, TELNET_POLICY, 2, "Policy type invalid; option='%s'", lookup_str);
      z_proxy_return(self, TELNET_CHECK_ABORT);
    }

  switch (command_do)
    {
    case TELNET_OPTION_DROP:
      z_proxy_log(self, TELNET_POLICY, 3, "Policy denied option; option='%s'", lookup_str);
      res = TELNET_CHECK_DROP;
      break;

    case TELNET_OPTION_ACCEPT:
      z_proxy_log(self, TELNET_POLICY, 6, "Policy accepted option; option='%s'", lookup_str);
      res = TELNET_CHECK_OK;
      break;

    case TELNET_OPTION_POLICY:
      z_policy_lock(self->super.thread);
      if (!z_policy_var_parse(tmp, "(iO)", &command_do, &command_where))
        {
          z_proxy_log(self, TELNET_POLICY, 2, "Cannot parse policy line; option='%s'", lookup_str);
          res = TELNET_CHECK_ABORT;
        }
      else 
        {
          pol_res = z_policy_call_object(command_where, z_policy_var_build("(i)", &self->opneg_option[self->ep]), self->super.session_id);
          if (pol_res == NULL)
            {
              z_proxy_log(self, TELNET_POLICY, 2, "Error in policy calling; option='%s'", lookup_str);
              res = TELNET_CHECK_ABORT;
            }
          else if (!z_policy_var_parse(pol_res, "i", &res))
            {
              z_proxy_log(self, TELNET_POLICY, 1, "Can't parse return verdict; option='%s'", lookup_str);
              res = TELNET_CHECK_ABORT;
            }
          else
            {
              switch (res)
                {
                case ZV_ACCEPT:
                  z_proxy_log(self, TELNET_POLICY, 6, "Policy function accepted option; option='%s'", lookup_str);
                  res = TELNET_CHECK_OK;
                  break;

                case ZV_UNSPEC:
                case ZV_DROP:
                  z_proxy_log(self, TELNET_POLICY, 3, "Policy function drop option; option='%s'", lookup_str);
                  res = TELNET_CHECK_DROP;
                  break;

                case TELNET_OPTION_REJECT:
                  z_proxy_log(self, TELNET_POLICY, 3, "Policy function reject option; option='%s'", lookup_str);
                  res = TELNET_CHECK_REJECT;
                  break;

                case ZV_ABORT:
                default:
                  z_proxy_log(self, TELNET_POLICY, 1, "Policy function aborted session; option='%s'", lookup_str);
                  res = TELNET_CHECK_ABORT;
                  break;
                }
            }
        }
      z_policy_unlock(self->super.thread);
      break;

    case TELNET_OPTION_REJECT:
      z_proxy_log(self, TELNET_POLICY, 3, "Policy rejected option; option='%s'", lookup_str);
      res = TELNET_CHECK_REJECT;
      break;

    case TELNET_OPTION_ABORT:
    default:
      z_proxy_log(self, TELNET_POLICY, 3, "Policy aborted session; option='%s'", lookup_str);
      res = TELNET_CHECK_ABORT;
      break;
    }
  z_proxy_return(self, res);
}